summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk4
-rw-r--r--api/current.txt88
-rw-r--r--api/removed.txt9
-rw-r--r--api/system-current.txt95
-rw-r--r--api/system-removed.txt9
-rw-r--r--api/test-current.txt102
-rw-r--r--api/test-removed.txt9
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java24
-rw-r--r--core/java/android/app/ActionBar.java4
-rw-r--r--core/java/android/app/Activity.java33
-rw-r--r--core/java/android/app/ActivityManagerNative.java124
-rw-r--r--core/java/android/app/ActivityOptions.java27
-rw-r--r--core/java/android/app/ActivityThread.java24
-rw-r--r--core/java/android/app/ApplicationPackageManager.java35
-rw-r--r--core/java/android/app/BackStackRecord.java2
-rw-r--r--core/java/android/app/DatePickerDialog.java194
-rw-r--r--core/java/android/app/DownloadManager.java48
-rw-r--r--core/java/android/app/IActivityManager.java35
-rw-r--r--core/java/android/app/INotificationManager.aidl2
-rw-r--r--core/java/android/app/ITaskStackListener.aidl4
-rw-r--r--core/java/android/app/Notification.java93
-rw-r--r--core/java/android/app/NotificationManager.java3
-rw-r--r--core/java/android/app/SystemServiceRegistry.java2
-rw-r--r--core/java/android/app/UiAutomation.java3
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java129
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl8
-rw-r--r--core/java/android/content/ContentProviderClient.java106
-rw-r--r--core/java/android/content/ContentResolver.java46
-rw-r--r--core/java/android/content/Context.java2
-rw-r--r--core/java/android/content/Intent.java20
-rw-r--r--core/java/android/content/pm/ActivityInfo.java44
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java3
-rw-r--r--core/java/android/content/pm/ManifestDigest.java147
-rw-r--r--core/java/android/content/pm/PackageManager.java294
-rw-r--r--core/java/android/content/pm/PackageParser.java48
-rw-r--r--core/java/android/content/pm/ParceledListSlice.java5
-rw-r--r--core/java/android/content/pm/ResolveInfo.java3
-rw-r--r--core/java/android/content/pm/VerificationParams.java31
-rw-r--r--core/java/android/content/res/AssetManager.java179
-rw-r--r--core/java/android/content/res/Resources.java127
-rw-r--r--core/java/android/net/NetworkScorerAppManager.java19
-rw-r--r--core/java/android/nfc/NfcActivityManager.java64
-rw-r--r--core/java/android/os/UserHandle.java2
-rw-r--r--core/java/android/os/UserManager.java4
-rw-r--r--core/java/android/print/IPrintManager.aidl14
-rw-r--r--core/java/android/print/IPrintSpooler.aidl35
-rw-r--r--core/java/android/print/IPrintSpoolerCallbacks.aidl25
-rw-r--r--core/java/android/print/PageRange.java10
-rw-r--r--core/java/android/print/PrintAttributes.java81
-rw-r--r--core/java/android/print/PrintDocumentInfo.java42
-rw-r--r--core/java/android/print/PrintJob.java7
-rw-r--r--core/java/android/print/PrintJobId.java5
-rw-r--r--core/java/android/print/PrintJobInfo.java54
-rw-r--r--core/java/android/print/PrintManager.java36
-rw-r--r--core/java/android/print/PrinterCapabilitiesInfo.java31
-rw-r--r--core/java/android/print/PrinterId.java3
-rw-r--r--core/java/android/print/PrinterInfo.java256
-rw-r--r--core/java/android/print/pdf/PrintedPdfDocument.java53
-rw-r--r--core/java/android/printservice/CustomPrinterIconCallback.java63
-rw-r--r--core/java/android/printservice/IPrintService.aidl11
-rw-r--r--core/java/android/printservice/IPrintServiceClient.aidl10
-rw-r--r--core/java/android/printservice/PrintDocument.java6
-rw-r--r--core/java/android/printservice/PrintJob.java5
-rw-r--r--core/java/android/printservice/PrintService.java72
-rw-r--r--core/java/android/printservice/PrintServiceInfo.java7
-rw-r--r--core/java/android/printservice/PrinterDiscoverySession.java57
-rw-r--r--core/java/android/provider/MediaStore.java43
-rw-r--r--core/java/android/provider/Settings.java9
-rw-r--r--core/java/android/security/NetworkSecurityPolicy.java1
-rw-r--r--core/java/android/security/net/config/ApplicationConfig.java26
-rw-r--r--core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java40
-rw-r--r--core/java/android/security/net/config/NetworkSecurityConfigProvider.java1
-rw-r--r--core/java/android/service/notification/INotificationAssistant.aidl37
-rw-r--r--core/java/android/service/notification/INotificationListener.aidl8
-rw-r--r--core/java/android/service/notification/NotificationAdjustment.java57
-rw-r--r--core/java/android/service/notification/NotificationAssistantService.java115
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java51
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java20
-rw-r--r--core/java/android/service/quicksettings/IQSService.aidl1
-rw-r--r--core/java/android/service/quicksettings/IQSTileService.aidl1
-rw-r--r--core/java/android/service/quicksettings/Tile.java32
-rw-r--r--core/java/android/service/quicksettings/TileService.java106
-rw-r--r--core/java/android/text/util/Linkify.java2
-rw-r--r--core/java/android/util/LocaleList.java90
-rw-r--r--core/java/android/util/PathParser.java4
-rw-r--r--core/java/android/util/Patterns.java287
-rw-r--r--core/java/android/view/DragEvent.java17
-rw-r--r--core/java/android/view/DropPermissions.java48
-rw-r--r--core/java/android/view/IDockedStackListener.aidl (renamed from core/java/android/view/IDockDividerVisibilityListener.aidl)13
-rw-r--r--core/java/android/view/IWindowManager.aidl21
-rw-r--r--core/java/android/view/LayoutInflater.java24
-rw-r--r--core/java/android/view/Surface.java30
-rw-r--r--core/java/android/view/SurfaceView.java13
-rw-r--r--core/java/android/view/TextureView.java4
-rw-r--r--core/java/android/view/View.java10
-rw-r--r--core/java/android/view/ViewGroup.java16
-rw-r--r--core/java/android/view/ViewRootImpl.java1
-rw-r--r--core/java/android/widget/PopupWindow.java13
-rw-r--r--core/java/com/android/internal/app/LocalePicker.java55
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java6
-rw-r--r--core/java/com/android/internal/app/ToolbarActionBar.java6
-rw-r--r--core/java/com/android/internal/logging/MetricsLogger.java2
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java2
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java33
-rw-r--r--core/java/com/android/internal/view/IDropPermissions.aidl4
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp10
-rw-r--r--core/jni/android_graphics_drawable_VectorDrawable.cpp386
-rw-r--r--core/jni/android_util_AssetManager.cpp16
-rw-r--r--core/jni/android_view_Surface.cpp7
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp26
-rw-r--r--core/res/AndroidManifest.xml16
-rw-r--r--core/res/res/layout/notification_material_reply_text.xml61
-rw-r--r--core/res/res/layout/notification_template_material_big_base.xml5
-rw-r--r--core/res/res/layout/notification_template_material_big_picture.xml7
-rw-r--r--core/res/res/layout/notification_template_material_big_text.xml7
-rw-r--r--core/res/res/layout/text_drag_thumbnail.xml1
-rw-r--r--core/res/res/values-af/strings.xml2
-rw-r--r--core/res/res/values-am/strings.xml2
-rw-r--r--core/res/res/values-ar/strings.xml2
-rw-r--r--core/res/res/values-az-rAZ/strings.xml2
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml2
-rw-r--r--core/res/res/values-bg/strings.xml2
-rw-r--r--core/res/res/values-bn-rBD/strings.xml2
-rw-r--r--core/res/res/values-ca/strings.xml2
-rw-r--r--core/res/res/values-cs/strings.xml2
-rw-r--r--core/res/res/values-da/strings.xml2
-rw-r--r--core/res/res/values-de/strings.xml2
-rw-r--r--core/res/res/values-el/strings.xml2
-rw-r--r--core/res/res/values-en-rAU/strings.xml2
-rw-r--r--core/res/res/values-en-rGB/strings.xml2
-rw-r--r--core/res/res/values-en-rIN/strings.xml2
-rw-r--r--core/res/res/values-es-rUS/strings.xml2
-rw-r--r--core/res/res/values-es/strings.xml2
-rw-r--r--core/res/res/values-et-rEE/strings.xml2
-rw-r--r--core/res/res/values-eu-rES/strings.xml6
-rw-r--r--core/res/res/values-fa/strings.xml4
-rw-r--r--core/res/res/values-fi/strings.xml2
-rw-r--r--core/res/res/values-fr-rCA/strings.xml2
-rw-r--r--core/res/res/values-fr/strings.xml4
-rw-r--r--core/res/res/values-gl-rES/strings.xml2
-rw-r--r--core/res/res/values-gu-rIN/strings.xml2
-rw-r--r--core/res/res/values-hi/strings.xml2
-rw-r--r--core/res/res/values-hr/strings.xml2
-rw-r--r--core/res/res/values-hu/strings.xml2
-rw-r--r--core/res/res/values-hy-rAM/strings.xml2
-rw-r--r--core/res/res/values-in/strings.xml2
-rw-r--r--core/res/res/values-is-rIS/strings.xml2
-rw-r--r--core/res/res/values-it/strings.xml6
-rw-r--r--core/res/res/values-iw/strings.xml2
-rw-r--r--core/res/res/values-ja/strings.xml2
-rw-r--r--core/res/res/values-ka-rGE/strings.xml2
-rw-r--r--core/res/res/values-kk-rKZ/strings.xml2
-rw-r--r--core/res/res/values-km-rKH/strings.xml2
-rw-r--r--core/res/res/values-kn-rIN/strings.xml2
-rw-r--r--core/res/res/values-ko/strings.xml2
-rw-r--r--core/res/res/values-ky-rKG/strings.xml2
-rw-r--r--core/res/res/values-land/config.xml19
-rw-r--r--core/res/res/values-lo-rLA/strings.xml2
-rw-r--r--core/res/res/values-lt/strings.xml2
-rw-r--r--core/res/res/values-lv/strings.xml2
-rw-r--r--core/res/res/values-mk-rMK/strings.xml6
-rw-r--r--core/res/res/values-ml-rIN/strings.xml2
-rw-r--r--core/res/res/values-mn-rMN/strings.xml2
-rw-r--r--core/res/res/values-mr-rIN/strings.xml2
-rw-r--r--core/res/res/values-ms-rMY/strings.xml2
-rw-r--r--core/res/res/values-my-rMM/strings.xml2
-rw-r--r--core/res/res/values-nb/strings.xml2
-rw-r--r--core/res/res/values-ne-rNP/strings.xml2
-rw-r--r--core/res/res/values-nl/strings.xml2
-rw-r--r--core/res/res/values-pa-rIN/strings.xml2
-rw-r--r--core/res/res/values-pl/strings.xml2
-rw-r--r--core/res/res/values-pt-rBR/strings.xml2
-rw-r--r--core/res/res/values-pt-rPT/strings.xml4
-rw-r--r--core/res/res/values-pt/strings.xml2
-rw-r--r--core/res/res/values-ro/strings.xml2
-rw-r--r--core/res/res/values-ru/strings.xml2
-rw-r--r--core/res/res/values-si-rLK/strings.xml2
-rw-r--r--core/res/res/values-sk/strings.xml2
-rw-r--r--core/res/res/values-sl/strings.xml2
-rw-r--r--core/res/res/values-sq-rAL/strings.xml2
-rw-r--r--core/res/res/values-sr/strings.xml2
-rw-r--r--core/res/res/values-sv/strings.xml2
-rw-r--r--core/res/res/values-sw/strings.xml4
-rw-r--r--core/res/res/values-sw600dp/config.xml1
-rw-r--r--core/res/res/values-ta-rIN/strings.xml2
-rw-r--r--core/res/res/values-te-rIN/strings.xml2
-rw-r--r--core/res/res/values-th/strings.xml2
-rw-r--r--core/res/res/values-tl/strings.xml2
-rw-r--r--core/res/res/values-tr/strings.xml2
-rw-r--r--core/res/res/values-uk/strings.xml2
-rw-r--r--core/res/res/values-ur-rPK/strings.xml2
-rw-r--r--core/res/res/values-uz-rUZ/strings.xml2
-rw-r--r--core/res/res/values-vi/strings.xml2
-rw-r--r--core/res/res/values-zh-rCN/strings.xml11
-rw-r--r--core/res/res/values-zh-rHK/strings.xml2
-rw-r--r--core/res/res/values-zh-rTW/strings.xml2
-rw-r--r--core/res/res/values-zu/strings.xml2
-rw-r--r--core/res/res/values/attrs_manifest.xml5
-rw-r--r--core/res/res/values/config.xml7
-rw-r--r--core/res/res/values/dimens.xml4
-rw-r--r--core/res/res/values/locale_config.xml14
-rw-r--r--core/res/res/values/strings.xml5
-rw-r--r--core/res/res/values/styles_material.xml2
-rw-r--r--core/res/res/values/styles_micro.xml4
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--core/tests/coretests/Android.mk2
-rw-r--r--core/tests/coretests/AndroidManifest.xml10
-rw-r--r--core/tests/coretests/res/layout/datepicker_layout.xml33
-rw-r--r--core/tests/coretests/res/values-fa/strings.xml4
-rw-r--r--core/tests/coretests/res/values/strings.xml3
-rw-r--r--core/tests/coretests/src/android/content/pm/ManifestDigestTest.java77
-rw-r--r--core/tests/coretests/src/android/content/pm/VerificationParamsTest.java82
-rw-r--r--core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java53
-rw-r--r--core/tests/coretests/src/android/util/PatternsTest.java485
-rw-r--r--core/tests/coretests/src/android/widget/DatePickerActivity.java32
-rw-r--r--core/tests/coretests/src/android/widget/DatePickerFocusTest.java250
-rw-r--r--data/etc/platform.xml1
-rw-r--r--data/fonts/fonts.xml2
-rw-r--r--drm/java/android/drm/DrmManagerClient.java65
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java30
-rw-r--r--graphics/java/android/graphics/Canvas.java30
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java27
-rw-r--r--graphics/java/android/graphics/drawable/Icon.aidl (renamed from core/java/android/service/notification/NotificationAdjustment.aidl)4
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java1101
-rw-r--r--include/androidfw/AssetManager.h17
-rw-r--r--include/androidfw/ResourceTypes.h15
-rw-r--r--keystore/java/android/security/KeyChain.java4
-rw-r--r--libs/androidfw/AssetManager.cpp15
-rw-r--r--libs/androidfw/ResourceTypes.cpp50
-rw-r--r--libs/hwui/Android.mk3
-rw-r--r--libs/hwui/BakedOpDispatcher.cpp40
-rw-r--r--libs/hwui/BakedOpDispatcher.h4
-rw-r--r--libs/hwui/BakedOpRenderer.cpp170
-rw-r--r--libs/hwui/BakedOpRenderer.h26
-rw-r--r--libs/hwui/BakedOpState.cpp79
-rw-r--r--libs/hwui/BakedOpState.h112
-rw-r--r--libs/hwui/CanvasState.cpp15
-rw-r--r--libs/hwui/CanvasState.h7
-rw-r--r--libs/hwui/ClipArea.cpp213
-rw-r--r--libs/hwui/ClipArea.h98
-rw-r--r--libs/hwui/FontRenderer.h5
-rw-r--r--libs/hwui/Glop.h2
-rw-r--r--libs/hwui/GlopBuilder.cpp2
-rw-r--r--libs/hwui/JankTracker.cpp1
-rw-r--r--libs/hwui/OpReorderer.cpp30
-rw-r--r--libs/hwui/OpReorderer.h30
-rw-r--r--libs/hwui/PathParser.h2
-rw-r--r--libs/hwui/Properties.cpp2
-rw-r--r--libs/hwui/Properties.h3
-rw-r--r--libs/hwui/RecordedOp.h134
-rw-r--r--libs/hwui/RecordingCanvas.cpp53
-rw-r--r--libs/hwui/RecordingCanvas.h4
-rw-r--r--libs/hwui/Snapshot.h1
-rw-r--r--libs/hwui/VectorDrawable.cpp492
-rw-r--r--libs/hwui/VectorDrawable.h330
-rw-r--r--libs/hwui/VectorDrawablePath.cpp59
-rw-r--r--libs/hwui/VectorDrawablePath.h55
-rw-r--r--libs/hwui/renderstate/Scissor.cpp22
-rw-r--r--libs/hwui/renderstate/Scissor.h3
-rw-r--r--libs/hwui/renderthread/EglManager.cpp11
-rw-r--r--libs/hwui/tests/common/TestScene.h1
-rw-r--r--libs/hwui/tests/common/scenes/ClippingAnimation.cpp67
-rw-r--r--libs/hwui/tests/common/scenes/TestSceneBase.h1
-rw-r--r--libs/hwui/tests/macrobench/TestSceneRunner.cpp49
-rw-r--r--libs/hwui/tests/macrobench/main.cpp127
-rw-r--r--libs/hwui/tests/microbench/PathParserBench.cpp2
-rwxr-xr-xlibs/hwui/tests/scripts/prep_volantis.sh54
-rw-r--r--libs/hwui/tests/unit/BakedOpStateTests.cpp41
-rw-r--r--libs/hwui/tests/unit/ClipAreaTests.cpp117
-rw-r--r--libs/hwui/tests/unit/LinearAllocatorTests.cpp10
-rw-r--r--libs/hwui/tests/unit/OpReordererTests.cpp28
-rw-r--r--libs/hwui/tests/unit/RecordingCanvasTests.cpp53
-rw-r--r--libs/hwui/tests/unit/VectorDrawableTests.cpp104
-rw-r--r--libs/hwui/utils/LinearAllocator.h8
-rw-r--r--libs/hwui/utils/VectorDrawableUtils.h2
-rw-r--r--media/java/android/media/MediaInserter.java10
-rw-r--r--media/java/android/media/MediaScanner.java203
-rwxr-xr-xmedia/java/android/mtp/MtpDatabase.java91
-rw-r--r--media/java/android/mtp/MtpPropertyGroup.java24
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java6
-rw-r--r--packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml4
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.pngbin420 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.pngbin341 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.pngbin276 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.pngbin911 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.pngbin925 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.pngbin576 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.pngbin792 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.pngbin650 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.pngbin811 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.pngbin558 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.pngbin953 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.pngbin675 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.pngbin704 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.pngbin841 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.pngbin722 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.pngbin531 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.pngbin584 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.pngbin550 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.pngbin721 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.pngbin926 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.pngbin171 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.pngbin279 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.pngbin213 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.pngbin204 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.pngbin693 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.pngbin698 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.pngbin547 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.pngbin642 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.pngbin619 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.pngbin601 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.pngbin492 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.pngbin708 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.pngbin594 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.pngbin589 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.pngbin657 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.pngbin622 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.pngbin517 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.pngbin594 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.pngbin527 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.pngbin576 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.pngbin708 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.pngbin139 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.pngbin554 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.pngbin343 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.pngbin359 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.pngbin1149 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.pngbin1164 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.pngbin683 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.pngbin905 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.pngbin740 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.pngbin987 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.pngbin610 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.pngbin1260 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.pngbin756 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.pngbin831 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.pngbin1095 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.pngbin859 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.pngbin602 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.pngbin706 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.pngbin633 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.pngbin801 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.pngbin1207 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.pngbin209 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.pngbin797 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.pngbin519 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.pngbin506 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.pngbin903 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.pngbin967 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.pngbin422 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.pngbin671 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.pngbin437 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.pngbin667 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.pngbin404 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.pngbin1079 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.pngbin483 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.pngbin633 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.pngbin1082 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.pngbin628 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.pngbin395 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.pngbin393 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.pngbin398 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.pngbin413 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.pngbin996 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.pngbin288 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.pngbin1064 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.pngbin641 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.pngbin660 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.pngbin1236 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.pngbin1314 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.pngbin556 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.pngbin911 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.pngbin549 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.pngbin922 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.pngbin506 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.pngbin1473 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.pngbin624 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.pngbin814 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.pngbin1460 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.pngbin869 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.pngbin483 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.pngbin516 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.pngbin508 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.pngbin516 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.pngbin1296 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.pngbin369 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_album.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_apk.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_audio.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_certificate.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_codes.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_compressed.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_contact.xml29
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_document.xml24
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_event.xml29
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_excel.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_folder.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_font.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_generic.xml29
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_image.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_pdf.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_presentation.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml29
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_text.xml29
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_video.xml29
-rw-r--r--packages/DocumentsUI/res/drawable/ic_doc_word.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/ic_root_sdcard.xml4
-rw-r--r--packages/DocumentsUI/res/drawable/ic_root_smartphone.xml (renamed from packages/SystemUI/res/drawable/docked_divider_handle.xml)18
-rw-r--r--packages/DocumentsUI/res/layout/item_dir_grid.xml62
-rw-r--r--packages/DocumentsUI/res/layout/item_doc_grid.xml8
-rw-r--r--packages/DocumentsUI/res/values-mk-rMK/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-sw/strings.xml4
-rw-r--r--packages/DocumentsUI/res/values-sw720dp/dimens.xml1
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java12
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java80
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/IconUtils.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/State.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java282
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java9
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java117
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java10
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java53
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java57
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java40
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java28
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java230
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java160
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java217
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java2
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java154
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java64
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java11
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java75
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.java50
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java41
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java82
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java86
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java27
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java4
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java1
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java5
-rw-r--r--packages/PrintSpooler/AndroidManifest.xml6
-rw-r--r--packages/PrintSpooler/res/drawable/ic_info.xml24
-rw-r--r--packages/PrintSpooler/res/layout/printer_dropdown_item.xml2
-rw-r--r--packages/PrintSpooler/res/layout/printer_list_item.xml13
-rw-r--r--packages/PrintSpooler/res/values-af/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-am/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ar/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-az-rAZ/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-bg/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-bn-rBD/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ca/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-cs/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-da/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-de/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-el/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-en-rAU/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-en-rGB/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-en-rIN/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-es-rUS/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-es/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-et-rEE/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-eu-rES/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-fa/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-fi/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-fr/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-gl-rES/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-gu-rIN/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-hi/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-hr/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-hu/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-hy-rAM/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-in/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-is-rIS/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-it/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-iw/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ja/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ka-rGE/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-kk-rKZ/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-km-rKH/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-kn-rIN/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ko/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ky-rKG/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-lo-rLA/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-lt/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-lv/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-mk-rMK/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ml-rIN/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-mn-rMN/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-mr-rIN/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ms-rMY/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-my-rMM/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-nb/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ne-rNP/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-nl/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-pa-rIN/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-pl/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-pt/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ro/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ru/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-si-rLK/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-sk/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-sl/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-sq-rAL/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-sr/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-sv/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-sw/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ta-rIN/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-te-rIN/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-th/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-tl/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-tr/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-uk/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-ur-rPK/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-uz-rUZ/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-vi/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-zu/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values/strings.xml6
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/model/CustomPrinterIconCache.java165
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java7
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java1
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java78
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java10
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java465
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java4
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java24
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java12
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java47
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java4
-rw-r--r--packages/SettingsLib/res/values-af/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-am/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ar/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-az-rAZ/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-az-rAZ/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bg/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bn-rBD/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-bn-rBD/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ca/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-cs/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-da/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-de/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-el/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rAU/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rGB/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rIN/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-es-rUS/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-es/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-et-rEE/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-et-rEE/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-eu-rES/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-eu-rES/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fa/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fi/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fr/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-gl-rES/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-gl-rES/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-gu-rIN/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-gu-rIN/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-hi/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-hr/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-hu/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-hy-rAM/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-hy-rAM/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-in/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-is-rIS/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-is-rIS/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-it/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-iw/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ja/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml10
-rw-r--r--packages/SettingsLib/res/values-ka-rGE/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ka-rGE/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-kk-rKZ/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-kk-rKZ/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-km-rKH/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-km-rKH/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-kn-rIN/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-kn-rIN/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ko/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ky-rKG/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ky-rKG/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-lo-rLA/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-lo-rLA/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-lt/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-lv/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mk-rMK/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-mk-rMK/strings.xml6
-rw-r--r--packages/SettingsLib/res/values-ml-rIN/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ml-rIN/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mn-rMN/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-mn-rMN/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mr-rIN/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-mr-rIN/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ms-rMY/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ms-rMY/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-my-rMM/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-my-rMM/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-nb/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ne-rNP/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ne-rNP/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-nl/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pa-rIN/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-pa-rIN/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pl/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pt/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ro/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ru/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-si-rLK/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-si-rLK/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sk/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sl/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sq-rAL/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-sq-rAL/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sr/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sv/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sw/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ta-rIN/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ta-rIN/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-te-rIN/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-te-rIN/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-th/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-tl/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-tr/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-uk/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ur-rPK/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-ur-rPK/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-uz-rUZ/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-uz-rUZ/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-vi/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zu/arrays.xml29
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml2
-rw-r--r--packages/SettingsLib/res/values/arrays.xml6
-rw-r--r--packages/SettingsLib/res/values/strings.xml5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java2
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/Shell/res/values-af/strings.xml3
-rw-r--r--packages/Shell/res/values-am/strings.xml3
-rw-r--r--packages/Shell/res/values-ar/strings.xml3
-rw-r--r--packages/Shell/res/values-az-rAZ/strings.xml3
-rw-r--r--packages/Shell/res/values-b+sr+Latn/strings.xml3
-rw-r--r--packages/Shell/res/values-bg/strings.xml3
-rw-r--r--packages/Shell/res/values-bn-rBD/strings.xml3
-rw-r--r--packages/Shell/res/values-ca/strings.xml3
-rw-r--r--packages/Shell/res/values-cs/strings.xml3
-rw-r--r--packages/Shell/res/values-da/strings.xml3
-rw-r--r--packages/Shell/res/values-de/strings.xml3
-rw-r--r--packages/Shell/res/values-el/strings.xml3
-rw-r--r--packages/Shell/res/values-en-rAU/strings.xml3
-rw-r--r--packages/Shell/res/values-en-rGB/strings.xml3
-rw-r--r--packages/Shell/res/values-en-rIN/strings.xml3
-rw-r--r--packages/Shell/res/values-es-rUS/strings.xml3
-rw-r--r--packages/Shell/res/values-es/strings.xml3
-rw-r--r--packages/Shell/res/values-et-rEE/strings.xml3
-rw-r--r--packages/Shell/res/values-eu-rES/strings.xml3
-rw-r--r--packages/Shell/res/values-fa/strings.xml3
-rw-r--r--packages/Shell/res/values-fi/strings.xml3
-rw-r--r--packages/Shell/res/values-fr-rCA/strings.xml3
-rw-r--r--packages/Shell/res/values-fr/strings.xml3
-rw-r--r--packages/Shell/res/values-gl-rES/strings.xml3
-rw-r--r--packages/Shell/res/values-gu-rIN/strings.xml3
-rw-r--r--packages/Shell/res/values-hi/strings.xml3
-rw-r--r--packages/Shell/res/values-hr/strings.xml3
-rw-r--r--packages/Shell/res/values-hu/strings.xml3
-rw-r--r--packages/Shell/res/values-hy-rAM/strings.xml3
-rw-r--r--packages/Shell/res/values-in/strings.xml3
-rw-r--r--packages/Shell/res/values-is-rIS/strings.xml3
-rw-r--r--packages/Shell/res/values-it/strings.xml3
-rw-r--r--packages/Shell/res/values-iw/strings.xml3
-rw-r--r--packages/Shell/res/values-ja/strings.xml3
-rw-r--r--packages/Shell/res/values-ka-rGE/strings.xml3
-rw-r--r--packages/Shell/res/values-kk-rKZ/strings.xml3
-rw-r--r--packages/Shell/res/values-km-rKH/strings.xml3
-rw-r--r--packages/Shell/res/values-kn-rIN/strings.xml3
-rw-r--r--packages/Shell/res/values-ko/strings.xml3
-rw-r--r--packages/Shell/res/values-ky-rKG/strings.xml5
-rw-r--r--packages/Shell/res/values-lo-rLA/strings.xml3
-rw-r--r--packages/Shell/res/values-lt/strings.xml3
-rw-r--r--packages/Shell/res/values-lv/strings.xml3
-rw-r--r--packages/Shell/res/values-mk-rMK/strings.xml3
-rw-r--r--packages/Shell/res/values-ml-rIN/strings.xml3
-rw-r--r--packages/Shell/res/values-mn-rMN/strings.xml3
-rw-r--r--packages/Shell/res/values-mr-rIN/strings.xml3
-rw-r--r--packages/Shell/res/values-ms-rMY/strings.xml3
-rw-r--r--packages/Shell/res/values-my-rMM/strings.xml3
-rw-r--r--packages/Shell/res/values-nb/strings.xml3
-rw-r--r--packages/Shell/res/values-ne-rNP/strings.xml3
-rw-r--r--packages/Shell/res/values-nl/strings.xml3
-rw-r--r--packages/Shell/res/values-pa-rIN/strings.xml3
-rw-r--r--packages/Shell/res/values-pl/strings.xml3
-rw-r--r--packages/Shell/res/values-pt-rBR/strings.xml3
-rw-r--r--packages/Shell/res/values-pt-rPT/strings.xml3
-rw-r--r--packages/Shell/res/values-pt/strings.xml3
-rw-r--r--packages/Shell/res/values-ro/strings.xml3
-rw-r--r--packages/Shell/res/values-ru/strings.xml3
-rw-r--r--packages/Shell/res/values-si-rLK/strings.xml3
-rw-r--r--packages/Shell/res/values-sk/strings.xml3
-rw-r--r--packages/Shell/res/values-sl/strings.xml3
-rw-r--r--packages/Shell/res/values-sq-rAL/strings.xml3
-rw-r--r--packages/Shell/res/values-sr/strings.xml3
-rw-r--r--packages/Shell/res/values-sv/strings.xml3
-rw-r--r--packages/Shell/res/values-sw/strings.xml3
-rw-r--r--packages/Shell/res/values-ta-rIN/strings.xml3
-rw-r--r--packages/Shell/res/values-te-rIN/strings.xml3
-rw-r--r--packages/Shell/res/values-th/strings.xml3
-rw-r--r--packages/Shell/res/values-tl/strings.xml3
-rw-r--r--packages/Shell/res/values-tr/strings.xml3
-rw-r--r--packages/Shell/res/values-uk/strings.xml3
-rw-r--r--packages/Shell/res/values-ur-rPK/strings.xml3
-rw-r--r--packages/Shell/res/values-uz-rUZ/strings.xml3
-rw-r--r--packages/Shell/res/values-vi/strings.xml3
-rw-r--r--packages/Shell/res/values-zh-rCN/strings.xml3
-rw-r--r--packages/Shell/res/values-zh-rHK/strings.xml3
-rw-r--r--packages/Shell/res/values-zh-rTW/strings.xml3
-rw-r--r--packages/Shell/res/values-zu/strings.xml3
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java12
-rw-r--r--packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java40
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.pngbin0 -> 1755 bytes
-rw-r--r--packages/SystemUI/res/layout/assist_orb.xml1
-rw-r--r--packages/SystemUI/res/layout/docked_stack_divider.xml5
-rw-r--r--packages/SystemUI/res/layout/mobile_signal_group.xml1
-rw-r--r--packages/SystemUI/res/layout/navigation_bar.xml1
-rw-r--r--packages/SystemUI/res/layout/notification_guts.xml74
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml14
-rw-r--r--packages/SystemUI/res/layout/recents_task_view.xml5
-rw-r--r--packages/SystemUI/res/layout/signal_cluster_view.xml1
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml1
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml1
-rw-r--r--packages/SystemUI/res/layout/status_bar_no_recent_apps.xml1
-rw-r--r--packages/SystemUI/res/values-af/strings.xml12
-rw-r--r--packages/SystemUI/res/values-am/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml12
-rw-r--r--packages/SystemUI/res/values-az-rAZ/strings.xml12
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml14
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml12
-rw-r--r--packages/SystemUI/res/values-bn-rBD/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml12
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml12
-rw-r--r--packages/SystemUI/res/values-da/strings.xml12
-rw-r--r--packages/SystemUI/res/values-de/strings.xml12
-rw-r--r--packages/SystemUI/res/values-el/strings.xml12
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml12
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml12
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml12
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml12
-rw-r--r--packages/SystemUI/res/values-es/strings.xml12
-rw-r--r--packages/SystemUI/res/values-et-rEE/strings.xml12
-rw-r--r--packages/SystemUI/res/values-eu-rES/strings.xml14
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml12
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml12
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml12
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml12
-rw-r--r--packages/SystemUI/res/values-gl-rES/strings.xml12
-rw-r--r--packages/SystemUI/res/values-gu-rIN/strings.xml12
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml12
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml12
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml20
-rw-r--r--packages/SystemUI/res/values-hy-rAM/strings.xml12
-rw-r--r--packages/SystemUI/res/values-in/strings.xml28
-rw-r--r--packages/SystemUI/res/values-is-rIS/strings.xml12
-rw-r--r--packages/SystemUI/res/values-it/strings.xml12
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml18
-rw-r--r--packages/SystemUI/res/values-ka-rGE/strings.xml12
-rw-r--r--packages/SystemUI/res/values-kk-rKZ/strings.xml12
-rw-r--r--packages/SystemUI/res/values-km-rKH/strings.xml12
-rw-r--r--packages/SystemUI/res/values-kn-rIN/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ky-rKG/strings.xml12
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-land/styles.xml4
-rw-r--r--packages/SystemUI/res/values-lo-rLA/strings.xml12
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml12
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml12
-rw-r--r--packages/SystemUI/res/values-mk-rMK/strings.xml18
-rw-r--r--packages/SystemUI/res/values-ml-rIN/strings.xml12
-rw-r--r--packages/SystemUI/res/values-mn-rMN/strings.xml14
-rw-r--r--packages/SystemUI/res/values-mr-rIN/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ms-rMY/strings.xml12
-rw-r--r--packages/SystemUI/res/values-my-rMM/strings.xml12
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ne-rNP/strings.xml20
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml14
-rw-r--r--packages/SystemUI/res/values-pa-rIN/strings.xml12
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml14
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml12
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml18
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml12
-rw-r--r--packages/SystemUI/res/values-si-rLK/strings.xml12
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml12
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml12
-rw-r--r--packages/SystemUI/res/values-sq-rAL/strings.xml12
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml14
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml12
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ta-rIN/strings.xml12
-rw-r--r--packages/SystemUI/res/values-te-rIN/strings.xml12
-rw-r--r--packages/SystemUI/res/values-th/strings.xml12
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml12
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml12
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ur-rPK/strings.xml12
-rw-r--r--packages/SystemUI/res/values-uz-rUZ/strings.xml12
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml12
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml54
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml14
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml12
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml12
-rw-r--r--packages/SystemUI/res/values/dimens.xml4
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/res/values/styles.xml12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSIconView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTile.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java76
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java (renamed from packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java)113
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java107
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java360
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java197
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java208
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/Task.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java142
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java136
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java285
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java79
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerService.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java2
-rw-r--r--packages/SystemUI/tests/AndroidManifest.xml6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java318
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java101
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java108
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java2
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java2
-rw-r--r--services/core/java/com/android/server/PersistentDataBlockService.java2
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java60
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java259
-rw-r--r--services/core/java/com/android/server/am/ActivityMetricsLogger.java2
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityRecord.java20
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java162
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java534
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java1584
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java2
-rw-r--r--services/core/java/com/android/server/am/ResizeDockedStackTimeout.java63
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java12
-rw-r--r--services/core/java/com/android/server/am/UserController.java34
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java2
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java31
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java2
-rw-r--r--services/core/java/com/android/server/notification/ConditionProviders.java5
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java35
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java130
-rw-r--r--services/core/java/com/android/server/notification/RankingHandler.java21
-rw-r--r--services/core/java/com/android/server/notification/RankingHelper.java21
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java11
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java462
-rw-r--r--services/core/java/com/android/server/pm/Settings.java110
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java6
-rw-r--r--services/core/java/com/android/server/policy/GlobalActions.java8
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java11
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java2
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java56
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java27
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java104
-rw-r--r--services/core/java/com/android/server/wm/DropPermissionsHandler.java30
-rw-r--r--services/core/java/com/android/server/wm/Task.java75
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java28
-rw-r--r--services/core/java/com/android/server/wm/TaskTapPointerEventListener.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowLayersController.java51
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerDebugConfig.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java286
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java165
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java23
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java17
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java157
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/print/java/com/android/server/print/PrintManagerService.java20
-rw-r--r--services/print/java/com/android/server/print/RemotePrintService.java40
-rw-r--r--services/print/java/com/android/server/print/RemotePrintSpooler.java179
-rw-r--r--services/print/java/com/android/server/print/UserState.java102
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java133
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java2
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java2
-rw-r--r--services/usage/java/com/android/server/usage/UserUsageStatsService.java2
-rw-r--r--telecomm/java/android/telecom/Call.java11
-rw-r--r--telecomm/java/android/telecom/Connection.java2
-rw-r--r--telecomm/java/android/telecom/DefaultDialerManager.java5
-rw-r--r--telecomm/java/android/telecom/InCallService.java2
-rw-r--r--telephony/java/android/telephony/ServiceState.java23
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java2
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java33
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java2
-rw-r--r--tools/aapt2/Android.mk4
-rw-r--r--tools/aapt2/Debug.cpp12
-rw-r--r--tools/aapt2/ResourceParser.cpp620
-rw-r--r--tools/aapt2/ResourceParser.h18
-rw-r--r--tools/aapt2/ResourceParser_test.cpp70
-rw-r--r--tools/aapt2/ResourceUtils.cpp17
-rw-r--r--tools/aapt2/ResourceUtils_test.cpp5
-rw-r--r--tools/aapt2/ResourceValues.cpp40
-rw-r--r--tools/aapt2/ResourceValues.h31
-rw-r--r--tools/aapt2/compile/Compile.cpp29
-rw-r--r--tools/aapt2/compile/PseudolocaleGenerator.cpp261
-rw-r--r--tools/aapt2/compile/PseudolocaleGenerator.h36
-rw-r--r--tools/aapt2/compile/PseudolocaleGenerator_test.cpp123
-rw-r--r--tools/aapt2/compile/Pseudolocalizer.cpp394
-rw-r--r--tools/aapt2/compile/Pseudolocalizer.h58
-rw-r--r--tools/aapt2/compile/Pseudolocalizer_test.cpp227
-rw-r--r--tools/aapt2/compile/XmlIdCollector_test.cpp6
-rw-r--r--tools/aapt2/flatten/TableFlattener.cpp27
-rw-r--r--tools/aapt2/java/ProguardRules.cpp4
-rw-r--r--tools/aapt2/test/Builders.h6
-rw-r--r--tools/aapt2/unflatten/BinaryResourceParser.cpp7
-rw-r--r--tools/aapt2/util/ImmutableMap.h84
-rw-r--r--tools/aapt2/util/TypeTraits.h51
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java9
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java21
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java32
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java58
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java16
1028 files changed, 20951 insertions, 7778 deletions
diff --git a/Android.mk b/Android.mk
index 51dfa575b77f..c1c74ea04e55 100644
--- a/Android.mk
+++ b/Android.mk
@@ -226,7 +226,6 @@ LOCAL_SRC_FILES += \
core/java/android/service/carrier/ICarrierMessagingService.aidl \
core/java/android/service/gatekeeper/IGateKeeperService.aidl \
core/java/android/service/notification/INotificationListener.aidl \
- core/java/android/service/notification/INotificationAssistant.aidl \
core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
core/java/android/service/notification/IConditionListener.aidl \
core/java/android/service/notification/IConditionProvider.aidl \
@@ -262,7 +261,7 @@ LOCAL_SRC_FILES += \
core/java/android/view/IApplicationToken.aidl \
core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl \
core/java/android/view/IAssetAtlas.aidl \
- core/java/android/view/IDockDividerVisibilityListener.aidl \
+ core/java/android/view/IDockedStackListener.aidl \
core/java/android/view/IGraphicsStats.aidl \
core/java/android/view/IInputFilter.aidl \
core/java/android/view/IInputFilterHost.aidl \
@@ -499,6 +498,7 @@ aidl_files := \
frameworks/base/graphics/java/android/graphics/PointF.aidl \
frameworks/base/graphics/java/android/graphics/RectF.aidl \
frameworks/base/graphics/java/android/graphics/Rect.aidl \
+ frameworks/base/graphics/java/android/graphics/drawable/Icon.aidl \
frameworks/base/core/java/android/accounts/AuthenticatorDescription.aidl \
frameworks/base/core/java/android/accounts/Account.aidl \
frameworks/base/core/java/android/app/admin/SystemUpdatePolicy.aidl \
diff --git a/api/current.txt b/api/current.txt
index 6610e37e309d..d15092f63a98 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -67,7 +67,6 @@ package android {
field public static final java.lang.String DUMP = "android.permission.DUMP";
field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
- field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
@@ -3504,6 +3503,7 @@ package android.app {
method public boolean releaseInstance();
method public final deprecated void removeDialog(int);
method public void reportFullyDrawn();
+ method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
method public final void requestPermissions(java.lang.String[], int);
method public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
@@ -4081,11 +4081,14 @@ package android.app {
}
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+ ctor public DatePickerDialog(android.content.Context);
+ ctor public DatePickerDialog(android.content.Context, int);
ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
method public android.widget.DatePicker getDatePicker();
method public void onClick(android.content.DialogInterface, int);
method public void onDateChanged(android.widget.DatePicker, int, int, int);
+ method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
method public void updateDate(int, int, int);
}
@@ -4225,7 +4228,7 @@ package android.app {
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
field public static final java.lang.String COLUMN_ID = "_id";
field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
- field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+ field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -4837,6 +4840,7 @@ package android.app {
field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
@@ -5003,6 +5007,7 @@ package android.app {
method public android.app.Notification.Builder setPriority(int);
method public android.app.Notification.Builder setProgress(int, int, boolean);
method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
+ method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
method public android.app.Notification.Builder setShowWhen(boolean);
method public android.app.Notification.Builder setSmallIcon(int);
method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5192,6 +5197,7 @@ package android.app {
field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
field public final int priorityCallSenders;
field public final int priorityCategories;
field public final int priorityMessageSenders;
@@ -5752,6 +5758,7 @@ package android.app.admin {
method public java.lang.String getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
+ method public java.lang.String getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
@@ -5772,6 +5779,7 @@ package android.app.admin {
method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
+ method public java.lang.String getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5813,6 +5821,7 @@ package android.app.admin {
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -5837,6 +5846,7 @@ package android.app.admin {
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -7562,11 +7572,12 @@ package android.content {
method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
}
- public class ContentProviderClient {
+ public class ContentProviderClient implements java.lang.AutoCloseable {
method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+ method public void close();
method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
method public android.content.ContentProvider getLocalContentProvider();
method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7580,7 +7591,7 @@ package android.content {
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
- method public boolean release();
+ method public deprecated boolean release();
method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
}
@@ -9507,6 +9518,7 @@ package android.content.pm {
field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+ field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9565,8 +9577,8 @@ package android.content.pm {
field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final int GET_ACTIVITIES = 1; // 0x1
field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
- field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
- field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+ field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
field public static final int GET_GIDS = 256; // 0x100
field public static final int GET_INSTRUMENTATION = 16; // 0x10
field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9578,13 +9590,17 @@ package android.content.pm {
field public static final int GET_SERVICES = 4; // 0x4
field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
field public static final int GET_SIGNATURES = 64; // 0x40
- field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+ field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+ field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+ field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
- field public static final int MATCH_ENCRYPTION_AWARE_ONLY = 524288; // 0x80000
- field public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 262144; // 0x40000
+ field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+ field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+ field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -10834,7 +10850,7 @@ package android.drm {
field public final int statusCode;
}
- public class DrmManagerClient {
+ public class DrmManagerClient implements java.lang.AutoCloseable {
ctor public DrmManagerClient(android.content.Context);
method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
method public int acquireRights(android.drm.DrmInfoRequest);
@@ -10844,6 +10860,7 @@ package android.drm {
method public int checkRightsStatus(android.net.Uri);
method public int checkRightsStatus(java.lang.String, int);
method public int checkRightsStatus(android.net.Uri, int);
+ method public void close();
method public android.drm.DrmConvertedStatus closeConvertSession(int);
method public android.drm.DrmConvertedStatus convertData(int, byte[]);
method public java.lang.String[] getAvailableDrmEngines();
@@ -10857,7 +10874,7 @@ package android.drm {
method public java.lang.String getOriginalMimeType(android.net.Uri);
method public int openConvertSession(java.lang.String);
method public int processDrmInfo(android.drm.DrmInfo);
- method public void release();
+ method public deprecated void release();
method public int removeAllRights();
method public int removeRights(java.lang.String);
method public int removeRights(android.net.Uri);
@@ -11261,14 +11278,14 @@ package android.graphics {
public static class BitmapFactory.Options {
ctor public BitmapFactory.Options();
- method public void requestCancelDecode();
+ method public deprecated void requestCancelDecode();
field public android.graphics.Bitmap inBitmap;
field public int inDensity;
- field public boolean inDither;
+ field public deprecated boolean inDither;
field public deprecated boolean inInputShareable;
field public boolean inJustDecodeBounds;
field public boolean inMutable;
- field public boolean inPreferQualityOverSpeed;
+ field public deprecated boolean inPreferQualityOverSpeed;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;
@@ -18237,7 +18254,6 @@ package android.icu.util {
method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
method public int getDSTSavings();
method public static android.icu.util.TimeZone getDefault();
- method public static int getDefaultTimeZoneType();
method public final java.lang.String getDisplayName();
method public final java.lang.String getDisplayName(java.util.Locale);
method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -18261,8 +18277,6 @@ package android.icu.util {
method public abstract boolean inDaylightTime(java.util.Date);
method public boolean isFrozen();
method public boolean observesDaylightTime();
- method public static synchronized void setDefault(android.icu.util.TimeZone);
- method public static synchronized void setDefaultTimeZoneType(int);
method public void setID(java.lang.String);
method public abstract void setRawOffset(int);
method public abstract boolean useDaylightTime();
@@ -18275,8 +18289,6 @@ package android.icu.util {
field public static final int SHORT_COMMONLY_USED = 6; // 0x6
field public static final int SHORT_GENERIC = 2; // 0x2
field public static final int SHORT_GMT = 4; // 0x4
- field public static final int TIMEZONE_ICU = 0; // 0x0
- field public static final int TIMEZONE_JDK = 1; // 0x1
field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
}
@@ -18372,8 +18384,6 @@ package android.icu.util {
method public static java.lang.String getVariant(java.lang.String);
method public boolean isRightToLeft();
method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
method public java.lang.String toLanguageTag();
@@ -29146,6 +29156,9 @@ package android.print {
method public android.print.PrinterInfo build();
method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
+ method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon();
+ method public android.print.PrinterInfo.Builder setIconResourceId(int);
+ method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
method public android.print.PrinterInfo.Builder setName(java.lang.String);
method public android.print.PrinterInfo.Builder setStatus(int);
}
@@ -29166,6 +29179,10 @@ package android.print.pdf {
package android.printservice {
+ public class CustomPrinterIconCallback {
+ method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
+ }
+
public final class PrintDocument {
method public android.os.ParcelFileDescriptor getData();
method public android.print.PrintDocumentInfo getInfo();
@@ -29221,6 +29238,7 @@ package android.printservice {
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
@@ -33088,6 +33106,7 @@ package android.security {
public class NetworkSecurityPolicy {
method public static android.security.NetworkSecurityPolicy getInstance();
method public boolean isCleartextTrafficPermitted();
+ method public boolean isCleartextTrafficPermitted(java.lang.String);
}
}
@@ -33480,20 +33499,13 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}
- public class NotificationAdjustment implements android.os.Parcelable {
- ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
- }
-
public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
ctor public NotificationAssistantService();
- method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
+ method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
method public final void clearAnnotation(java.lang.String);
method public void onNotificationActionClick(java.lang.String, long, int);
method public void onNotificationClick(java.lang.String, long);
- method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+ method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
method public void onNotificationRemoved(java.lang.String, long, int);
method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
method public final void setAnnotation(java.lang.String, android.app.Notification);
@@ -33513,6 +33525,10 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
+ public class NotificationAssistantService.Adjustment {
+ ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
+ }
+
public abstract class NotificationListenerService extends android.app.Service {
ctor public NotificationListenerService();
method public final void cancelAllNotifications();
@@ -33546,6 +33562,7 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
}
public static class NotificationListenerService.Ranking {
@@ -33617,10 +33634,13 @@ package android.service.quicksettings {
method public void onClick();
method public void onStartListening();
method public void onStopListening();
- method public void onTileAdded();
+ method public int onTileAdded();
method public void onTileRemoved();
+ method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
method public final void showDialog(android.app.Dialog);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+ field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
}
@@ -34881,6 +34901,7 @@ package android.telecom {
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_WIFI = 8; // 0x8
+ field public static final int PROPERTY_WORK_CALL = 32; // 0x20
}
public final class CallAudioState implements android.os.Parcelable {
@@ -36719,7 +36740,6 @@ package android.test.mock {
method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public int getComponentEnabledSetting(android.content.ComponentName);
method public android.graphics.drawable.Drawable getDefaultActivityIcon();
- method public java.lang.String getDefaultBrowserPackageName(int);
method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
method public byte[] getEphemeralCookie();
method public int getEphemeralCookieMaxSizeBytes();
@@ -36771,7 +36791,6 @@ package android.test.mock {
method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
- method public boolean setDefaultBrowserPackageName(java.lang.String, int);
method public boolean setEphemeralCookie(byte[]);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
method public void verifyPendingInstall(int, int);
@@ -39161,7 +39180,7 @@ package android.util {
method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher);
field public static final java.util.regex.Pattern DOMAIN_NAME;
field public static final java.util.regex.Pattern EMAIL_ADDRESS;
- field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
+ field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
field public static final java.util.regex.Pattern IP_ADDRESS;
field public static final java.util.regex.Pattern PHONE;
field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN;
@@ -39596,7 +39615,6 @@ package android.view {
method public boolean getResult();
method public float getX();
method public float getY();
- method public android.view.DropPermissions requestDropPermissions();
method public void writeToParcel(android.os.Parcel, int);
field public static final int ACTION_DRAG_ENDED = 4; // 0x4
field public static final int ACTION_DRAG_ENTERED = 5; // 0x5
diff --git a/api/removed.txt b/api/removed.txt
index f12e61eea332..6b7961e9f1f6 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -199,6 +199,15 @@ package android.provider {
}
+package android.test.mock {
+
+ public class MockPackageManager extends android.content.pm.PackageManager {
+ method public deprecated java.lang.String getDefaultBrowserPackageName(int);
+ method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
+ }
+
+}
+
package android.text.format {
public class DateFormat {
diff --git a/api/system-current.txt b/api/system-current.txt
index ff3736580a92..93fd7d24d615 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -93,7 +93,6 @@ package android {
field public static final java.lang.String DUMP = "android.permission.DUMP";
field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
- field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK";
field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
@@ -3609,6 +3608,7 @@ package android.app {
method public boolean releaseInstance();
method public final deprecated void removeDialog(int);
method public void reportFullyDrawn();
+ method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
method public final void requestPermissions(java.lang.String[], int);
method public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
@@ -4201,11 +4201,14 @@ package android.app {
}
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+ ctor public DatePickerDialog(android.content.Context);
+ ctor public DatePickerDialog(android.content.Context, int);
ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
method public android.widget.DatePicker getDatePicker();
method public void onClick(android.content.DialogInterface, int);
method public void onDateChanged(android.widget.DatePicker, int, int, int);
+ method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
method public void updateDate(int, int, int);
}
@@ -4345,7 +4348,7 @@ package android.app {
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
field public static final java.lang.String COLUMN_ID = "_id";
field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
- field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+ field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -4957,6 +4960,7 @@ package android.app {
field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
@@ -5123,6 +5127,7 @@ package android.app {
method public android.app.Notification.Builder setPriority(int);
method public android.app.Notification.Builder setProgress(int, int, boolean);
method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
+ method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
method public android.app.Notification.Builder setShowWhen(boolean);
method public android.app.Notification.Builder setSmallIcon(int);
method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5312,6 +5317,7 @@ package android.app {
field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
field public final int priorityCallSenders;
field public final int priorityCategories;
field public final int priorityMessageSenders;
@@ -5880,6 +5886,7 @@ package android.app.admin {
method public java.lang.String getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
+ method public java.lang.String getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
@@ -5904,6 +5911,7 @@ package android.app.admin {
method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
+ method public java.lang.String getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5947,6 +5955,7 @@ package android.app.admin {
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -5971,6 +5980,7 @@ package android.app.admin {
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -7805,11 +7815,12 @@ package android.content {
method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
}
- public class ContentProviderClient {
+ public class ContentProviderClient implements java.lang.AutoCloseable {
method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+ method public void close();
method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
method public android.content.ContentProvider getLocalContentProvider();
method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7823,7 +7834,7 @@ package android.content {
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
- method public boolean release();
+ method public deprecated boolean release();
method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
}
@@ -9544,12 +9555,6 @@ package android.content.pm {
method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
}
- public class ManifestDigest implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.content.pm.ManifestDigest> CREATOR;
- }
-
public class PackageInfo implements android.os.Parcelable {
ctor public PackageInfo();
method public int describeContents();
@@ -9823,6 +9828,7 @@ package android.content.pm {
field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+ field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9881,8 +9887,8 @@ package android.content.pm {
field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final int GET_ACTIVITIES = 1; // 0x1
field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
- field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
- field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+ field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
field public static final int GET_GIDS = 256; // 0x100
field public static final int GET_INSTRUMENTATION = 16; // 0x10
field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9894,7 +9900,7 @@ package android.content.pm {
field public static final int GET_SERVICES = 4; // 0x4
field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
field public static final int GET_SIGNATURES = 64; // 0x40
- field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+ field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
field public static final int INSTALL_FAILED_ALREADY_EXISTS = -1; // 0xffffffff
field public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13; // 0xfffffff3
@@ -9935,9 +9941,13 @@ package android.content.pm {
field public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+ field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+ field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
- field public static final int MATCH_ENCRYPTION_AWARE_ONLY = 524288; // 0x80000
- field public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 262144; // 0x40000
+ field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+ field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+ field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -11194,7 +11204,7 @@ package android.drm {
field public final int statusCode;
}
- public class DrmManagerClient {
+ public class DrmManagerClient implements java.lang.AutoCloseable {
ctor public DrmManagerClient(android.content.Context);
method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
method public int acquireRights(android.drm.DrmInfoRequest);
@@ -11204,6 +11214,7 @@ package android.drm {
method public int checkRightsStatus(android.net.Uri);
method public int checkRightsStatus(java.lang.String, int);
method public int checkRightsStatus(android.net.Uri, int);
+ method public void close();
method public android.drm.DrmConvertedStatus closeConvertSession(int);
method public android.drm.DrmConvertedStatus convertData(int, byte[]);
method public java.lang.String[] getAvailableDrmEngines();
@@ -11217,7 +11228,7 @@ package android.drm {
method public java.lang.String getOriginalMimeType(android.net.Uri);
method public int openConvertSession(java.lang.String);
method public int processDrmInfo(android.drm.DrmInfo);
- method public void release();
+ method public deprecated void release();
method public int removeAllRights();
method public int removeRights(java.lang.String);
method public int removeRights(android.net.Uri);
@@ -11621,14 +11632,14 @@ package android.graphics {
public static class BitmapFactory.Options {
ctor public BitmapFactory.Options();
- method public void requestCancelDecode();
+ method public deprecated void requestCancelDecode();
field public android.graphics.Bitmap inBitmap;
field public int inDensity;
- field public boolean inDither;
+ field public deprecated boolean inDither;
field public deprecated boolean inInputShareable;
field public boolean inJustDecodeBounds;
field public boolean inMutable;
- field public boolean inPreferQualityOverSpeed;
+ field public deprecated boolean inPreferQualityOverSpeed;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;
@@ -19224,7 +19235,6 @@ package android.icu.util {
method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
method public int getDSTSavings();
method public static android.icu.util.TimeZone getDefault();
- method public static int getDefaultTimeZoneType();
method public final java.lang.String getDisplayName();
method public final java.lang.String getDisplayName(java.util.Locale);
method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -19248,8 +19258,6 @@ package android.icu.util {
method public abstract boolean inDaylightTime(java.util.Date);
method public boolean isFrozen();
method public boolean observesDaylightTime();
- method public static synchronized void setDefault(android.icu.util.TimeZone);
- method public static synchronized void setDefaultTimeZoneType(int);
method public void setID(java.lang.String);
method public abstract void setRawOffset(int);
method public abstract boolean useDaylightTime();
@@ -19262,8 +19270,6 @@ package android.icu.util {
field public static final int SHORT_COMMONLY_USED = 6; // 0x6
field public static final int SHORT_GENERIC = 2; // 0x2
field public static final int SHORT_GMT = 4; // 0x4
- field public static final int TIMEZONE_ICU = 0; // 0x0
- field public static final int TIMEZONE_JDK = 1; // 0x1
field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
}
@@ -19359,8 +19365,6 @@ package android.icu.util {
method public static java.lang.String getVariant(java.lang.String);
method public boolean isRightToLeft();
method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
method public java.lang.String toLanguageTag();
@@ -25756,7 +25760,6 @@ package android.net.wifi {
method public void writeToParcel(android.os.Parcel, int);
field public int band;
field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
- field public int exponent;
field public int maxPeriodInMs;
field public int maxScansToCache;
field public int numBssidsPerScan;
@@ -31156,6 +31159,9 @@ package android.print {
method public android.print.PrinterInfo build();
method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
+ method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon();
+ method public android.print.PrinterInfo.Builder setIconResourceId(int);
+ method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
method public android.print.PrinterInfo.Builder setName(java.lang.String);
method public android.print.PrinterInfo.Builder setStatus(int);
}
@@ -31176,6 +31182,10 @@ package android.print.pdf {
package android.printservice {
+ public class CustomPrinterIconCallback {
+ method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
+ }
+
public final class PrintDocument {
method public android.os.ParcelFileDescriptor getData();
method public android.print.PrintDocumentInfo getInfo();
@@ -31231,6 +31241,7 @@ package android.printservice {
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
@@ -35231,6 +35242,7 @@ package android.security {
public class NetworkSecurityPolicy {
method public static android.security.NetworkSecurityPolicy getInstance();
method public boolean isCleartextTrafficPermitted();
+ method public boolean isCleartextTrafficPermitted(java.lang.String);
}
}
@@ -35623,20 +35635,13 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}
- public class NotificationAdjustment implements android.os.Parcelable {
- ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
- }
-
public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
ctor public NotificationAssistantService();
- method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
+ method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
method public final void clearAnnotation(java.lang.String);
method public void onNotificationActionClick(java.lang.String, long, int);
method public void onNotificationClick(java.lang.String, long);
- method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+ method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
method public void onNotificationRemoved(java.lang.String, long, int);
method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
method public final void setAnnotation(java.lang.String, android.app.Notification);
@@ -35656,6 +35661,10 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
+ public class NotificationAssistantService.Adjustment {
+ ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
+ }
+
public abstract class NotificationListenerService extends android.app.Service {
ctor public NotificationListenerService();
method public final void cancelAllNotifications();
@@ -35694,6 +35703,7 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
field public static final int TRIM_FULL = 0; // 0x0
field public static final int TRIM_LIGHT = 1; // 0x1
}
@@ -35792,10 +35802,13 @@ package android.service.quicksettings {
method public void onClick();
method public void onStartListening();
method public void onStopListening();
- method public void onTileAdded();
+ method public int onTileAdded();
method public void onTileRemoved();
+ method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
method public final void showDialog(android.app.Dialog);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+ field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
}
@@ -37099,6 +37112,7 @@ package android.telecom {
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_WIFI = 8; // 0x8
+ field public static final int PROPERTY_WORK_CALL = 32; // 0x20
}
public static abstract deprecated class Call.Listener extends android.telecom.Call.Callback {
@@ -39067,7 +39081,6 @@ package android.test.mock {
method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public int getComponentEnabledSetting(android.content.ComponentName);
method public android.graphics.drawable.Drawable getDefaultActivityIcon();
- method public java.lang.String getDefaultBrowserPackageName(int);
method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
method public byte[] getEphemeralCookie();
method public int getEphemeralCookieMaxSizeBytes();
@@ -39123,7 +39136,6 @@ package android.test.mock {
method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
- method public boolean setDefaultBrowserPackageName(java.lang.String, int);
method public boolean setEphemeralCookie(byte[]);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
@@ -41515,7 +41527,7 @@ package android.util {
method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher);
field public static final java.util.regex.Pattern DOMAIN_NAME;
field public static final java.util.regex.Pattern EMAIL_ADDRESS;
- field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
+ field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
field public static final java.util.regex.Pattern IP_ADDRESS;
field public static final java.util.regex.Pattern PHONE;
field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN;
@@ -41950,7 +41962,6 @@ package android.view {
method public boolean getResult();
method public float getX();
method public float getY();
- method public android.view.DropPermissions requestDropPermissions();
method public void writeToParcel(android.os.Parcel, int);
field public static final int ACTION_DRAG_ENDED = 4; // 0x4
field public static final int ACTION_DRAG_ENTERED = 5; // 0x5
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 642d2a8ac19c..90a5dc7c474f 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -190,6 +190,15 @@ package android.provider {
}
+package android.test.mock {
+
+ public class MockPackageManager extends android.content.pm.PackageManager {
+ method public deprecated java.lang.String getDefaultBrowserPackageName(int);
+ method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
+ }
+
+}
+
package android.text.format {
public class DateFormat {
diff --git a/api/test-current.txt b/api/test-current.txt
index 883dd31f3c55..a2c207679144 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -67,7 +67,6 @@ package android {
field public static final java.lang.String DUMP = "android.permission.DUMP";
field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
- field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
@@ -3504,6 +3503,7 @@ package android.app {
method public boolean releaseInstance();
method public final deprecated void removeDialog(int);
method public void reportFullyDrawn();
+ method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
method public final void requestPermissions(java.lang.String[], int);
method public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
@@ -4081,11 +4081,14 @@ package android.app {
}
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+ ctor public DatePickerDialog(android.content.Context);
+ ctor public DatePickerDialog(android.content.Context, int);
ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
method public android.widget.DatePicker getDatePicker();
method public void onClick(android.content.DialogInterface, int);
method public void onDateChanged(android.widget.DatePicker, int, int, int);
+ method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
method public void updateDate(int, int, int);
}
@@ -4225,7 +4228,7 @@ package android.app {
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
field public static final java.lang.String COLUMN_ID = "_id";
field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
- field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+ field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -4837,6 +4840,7 @@ package android.app {
field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
@@ -5003,6 +5007,7 @@ package android.app {
method public android.app.Notification.Builder setPriority(int);
method public android.app.Notification.Builder setProgress(int, int, boolean);
method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
+ method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
method public android.app.Notification.Builder setShowWhen(boolean);
method public android.app.Notification.Builder setSmallIcon(int);
method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5192,6 +5197,7 @@ package android.app {
field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
field public final int priorityCallSenders;
field public final int priorityCategories;
field public final int priorityMessageSenders;
@@ -5495,8 +5501,10 @@ package android.app {
method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats();
method public android.view.WindowContentFrameStats getWindowContentFrameStats(int);
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
+ method public boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public boolean injectInputEvent(android.view.InputEvent, boolean);
method public final boolean performGlobalAction(int);
+ method public boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener);
method public boolean setRotation(int);
method public void setRunAsMonkey(boolean);
@@ -5752,6 +5760,7 @@ package android.app.admin {
method public java.lang.String getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
+ method public java.lang.String getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
@@ -5772,6 +5781,7 @@ package android.app.admin {
method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
+ method public java.lang.String getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5813,6 +5823,7 @@ package android.app.admin {
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -5837,6 +5848,7 @@ package android.app.admin {
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -7562,11 +7574,12 @@ package android.content {
method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
}
- public class ContentProviderClient {
+ public class ContentProviderClient implements java.lang.AutoCloseable {
method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+ method public void close();
method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
method public android.content.ContentProvider getLocalContentProvider();
method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7580,7 +7593,7 @@ package android.content {
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
- method public boolean release();
+ method public deprecated boolean release();
method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
}
@@ -7662,6 +7675,7 @@ package android.content {
method public static java.util.List<android.content.PeriodicSync> getPeriodicSyncs(android.accounts.Account, java.lang.String);
method public java.util.List<android.content.UriPermission> getPersistedUriPermissions();
method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String);
+ method public static java.lang.String[] getSyncAdapterPackagesForAuthorityAsUser(java.lang.String, int);
method public static android.content.SyncAdapterType[] getSyncAdapterTypes();
method public static boolean getSyncAutomatically(android.accounts.Account, java.lang.String);
method public final java.lang.String getType(android.net.Uri);
@@ -7828,6 +7842,7 @@ package android.content {
method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
method public final java.lang.CharSequence getText(int);
method public abstract android.content.res.Resources.Theme getTheme();
+ method public abstract int getUserId();
method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
method public abstract deprecated int getWallpaperDesiredMinimumHeight();
method public abstract deprecated int getWallpaperDesiredMinimumWidth();
@@ -8010,6 +8025,7 @@ package android.content {
method public java.lang.Object getSystemService(java.lang.String);
method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
+ method public int getUserId();
method public deprecated android.graphics.drawable.Drawable getWallpaper();
method public deprecated int getWallpaperDesiredMinimumHeight();
method public deprecated int getWallpaperDesiredMinimumWidth();
@@ -9062,6 +9078,8 @@ package android.content.pm {
ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
+ method public boolean isPrivilegedApp();
+ method public boolean isSystemApp();
method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
field public static final android.os.Parcelable.Creator<android.content.pm.ApplicationInfo> CREATOR;
field public static final int FLAG_ALLOW_BACKUP = 32768; // 0x8000
@@ -9423,6 +9441,7 @@ package android.content.pm {
method public abstract android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract int getComponentEnabledSetting(android.content.ComponentName);
method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
+ method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
method public abstract byte[] getEphemeralCookie();
method public abstract int getEphemeralCookieMaxSizeBytes();
@@ -9507,6 +9526,7 @@ package android.content.pm {
field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+ field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9565,8 +9585,8 @@ package android.content.pm {
field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final int GET_ACTIVITIES = 1; // 0x1
field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
- field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
- field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+ field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
field public static final int GET_GIDS = 256; // 0x100
field public static final int GET_INSTRUMENTATION = 16; // 0x10
field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9578,13 +9598,17 @@ package android.content.pm {
field public static final int GET_SERVICES = 4; // 0x4
field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
field public static final int GET_SIGNATURES = 64; // 0x40
- field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+ field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+ field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+ field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
- field public static final int MATCH_ENCRYPTION_AWARE_ONLY = 524288; // 0x80000
- field public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 262144; // 0x40000
+ field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+ field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+ field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -10834,7 +10858,7 @@ package android.drm {
field public final int statusCode;
}
- public class DrmManagerClient {
+ public class DrmManagerClient implements java.lang.AutoCloseable {
ctor public DrmManagerClient(android.content.Context);
method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
method public int acquireRights(android.drm.DrmInfoRequest);
@@ -10844,6 +10868,7 @@ package android.drm {
method public int checkRightsStatus(android.net.Uri);
method public int checkRightsStatus(java.lang.String, int);
method public int checkRightsStatus(android.net.Uri, int);
+ method public void close();
method public android.drm.DrmConvertedStatus closeConvertSession(int);
method public android.drm.DrmConvertedStatus convertData(int, byte[]);
method public java.lang.String[] getAvailableDrmEngines();
@@ -10857,7 +10882,7 @@ package android.drm {
method public java.lang.String getOriginalMimeType(android.net.Uri);
method public int openConvertSession(java.lang.String);
method public int processDrmInfo(android.drm.DrmInfo);
- method public void release();
+ method public deprecated void release();
method public int removeAllRights();
method public int removeRights(java.lang.String);
method public int removeRights(android.net.Uri);
@@ -11261,14 +11286,14 @@ package android.graphics {
public static class BitmapFactory.Options {
ctor public BitmapFactory.Options();
- method public void requestCancelDecode();
+ method public deprecated void requestCancelDecode();
field public android.graphics.Bitmap inBitmap;
field public int inDensity;
- field public boolean inDither;
+ field public deprecated boolean inDither;
field public deprecated boolean inInputShareable;
field public boolean inJustDecodeBounds;
field public boolean inMutable;
- field public boolean inPreferQualityOverSpeed;
+ field public deprecated boolean inPreferQualityOverSpeed;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;
@@ -18237,7 +18262,6 @@ package android.icu.util {
method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
method public int getDSTSavings();
method public static android.icu.util.TimeZone getDefault();
- method public static int getDefaultTimeZoneType();
method public final java.lang.String getDisplayName();
method public final java.lang.String getDisplayName(java.util.Locale);
method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -18261,8 +18285,6 @@ package android.icu.util {
method public abstract boolean inDaylightTime(java.util.Date);
method public boolean isFrozen();
method public boolean observesDaylightTime();
- method public static synchronized void setDefault(android.icu.util.TimeZone);
- method public static synchronized void setDefaultTimeZoneType(int);
method public void setID(java.lang.String);
method public abstract void setRawOffset(int);
method public abstract boolean useDaylightTime();
@@ -18275,8 +18297,6 @@ package android.icu.util {
field public static final int SHORT_COMMONLY_USED = 6; // 0x6
field public static final int SHORT_GENERIC = 2; // 0x2
field public static final int SHORT_GMT = 4; // 0x4
- field public static final int TIMEZONE_ICU = 0; // 0x0
- field public static final int TIMEZONE_JDK = 1; // 0x1
field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
}
@@ -18372,8 +18392,6 @@ package android.icu.util {
method public static java.lang.String getVariant(java.lang.String);
method public boolean isRightToLeft();
method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
method public java.lang.String toLanguageTag();
@@ -28356,6 +28374,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 int getAppId(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);
@@ -29135,6 +29154,7 @@ package android.print {
method public android.print.PrinterId getId();
method public java.lang.String getName();
method public int getStatus();
+ method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.print.PrinterInfo> CREATOR;
field public static final int STATUS_BUSY = 2; // 0x2
@@ -29148,6 +29168,9 @@ package android.print {
method public android.print.PrinterInfo build();
method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
+ method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon();
+ method public android.print.PrinterInfo.Builder setIconResourceId(int);
+ method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
method public android.print.PrinterInfo.Builder setName(java.lang.String);
method public android.print.PrinterInfo.Builder setStatus(int);
}
@@ -29168,6 +29191,10 @@ package android.print.pdf {
package android.printservice {
+ public class CustomPrinterIconCallback {
+ method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
+ }
+
public final class PrintDocument {
method public android.os.ParcelFileDescriptor getData();
method public android.print.PrintDocumentInfo getInfo();
@@ -29223,6 +29250,7 @@ package android.printservice {
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
@@ -31371,6 +31399,7 @@ package android.provider {
field public static final deprecated java.lang.String TTS_USE_DEFAULTS = "tts_use_defaults";
field public static final deprecated java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
+ field public static final java.lang.String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
field public static final deprecated java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
@@ -31754,6 +31783,7 @@ package android.provider {
field public static final int RESULT_SMS_OUT_OF_MEMORY = 3; // 0x3
field public static final int RESULT_SMS_UNSUPPORTED = 4; // 0x4
field public static final java.lang.String SIM_FULL_ACTION = "android.provider.Telephony.SIM_FULL";
+ field public static final java.lang.String SMS_CARRIER_PROVISION_ACTION = "android.provider.Telephony.SMS_CARRIER_PROVISION";
field public static final java.lang.String SMS_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_CB_RECEIVED";
field public static final java.lang.String SMS_DELIVER_ACTION = "android.provider.Telephony.SMS_DELIVER";
field public static final java.lang.String SMS_EMERGENCY_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
@@ -33090,6 +33120,7 @@ package android.security {
public class NetworkSecurityPolicy {
method public static android.security.NetworkSecurityPolicy getInstance();
method public boolean isCleartextTrafficPermitted();
+ method public boolean isCleartextTrafficPermitted(java.lang.String);
}
}
@@ -33482,20 +33513,13 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}
- public class NotificationAdjustment implements android.os.Parcelable {
- ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
- }
-
public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
ctor public NotificationAssistantService();
- method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
+ method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
method public final void clearAnnotation(java.lang.String);
method public void onNotificationActionClick(java.lang.String, long, int);
method public void onNotificationClick(java.lang.String, long);
- method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+ method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
method public void onNotificationRemoved(java.lang.String, long, int);
method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
method public final void setAnnotation(java.lang.String, android.app.Notification);
@@ -33515,6 +33539,10 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
+ public class NotificationAssistantService.Adjustment {
+ ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
+ }
+
public abstract class NotificationListenerService extends android.app.Service {
ctor public NotificationListenerService();
method public final void cancelAllNotifications();
@@ -33548,6 +33576,7 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
}
public static class NotificationListenerService.Ranking {
@@ -33619,10 +33648,13 @@ package android.service.quicksettings {
method public void onClick();
method public void onStartListening();
method public void onStopListening();
- method public void onTileAdded();
+ method public int onTileAdded();
method public void onTileRemoved();
+ method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
method public final void showDialog(android.app.Dialog);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+ field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
}
@@ -34883,6 +34915,7 @@ package android.telecom {
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_WIFI = 8; // 0x8
+ field public static final int PROPERTY_WORK_CALL = 32; // 0x20
}
public final class CallAudioState implements android.os.Parcelable {
@@ -36595,6 +36628,7 @@ package android.test.mock {
method public java.lang.Object getSystemService(java.lang.String);
method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
+ method public int getUserId();
method public android.graphics.drawable.Drawable getWallpaper();
method public int getWallpaperDesiredMinimumHeight();
method public int getWallpaperDesiredMinimumWidth();
@@ -36721,7 +36755,7 @@ package android.test.mock {
method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public int getComponentEnabledSetting(android.content.ComponentName);
method public android.graphics.drawable.Drawable getDefaultActivityIcon();
- method public java.lang.String getDefaultBrowserPackageName(int);
+ method public java.lang.String getDefaultBrowserPackageNameAsUser(int);
method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
method public byte[] getEphemeralCookie();
method public int getEphemeralCookieMaxSizeBytes();
@@ -36773,7 +36807,6 @@ package android.test.mock {
method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
- method public boolean setDefaultBrowserPackageName(java.lang.String, int);
method public boolean setEphemeralCookie(byte[]);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
method public void verifyPendingInstall(int, int);
@@ -39163,7 +39196,7 @@ package android.util {
method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher);
field public static final java.util.regex.Pattern DOMAIN_NAME;
field public static final java.util.regex.Pattern EMAIL_ADDRESS;
- field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
+ field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
field public static final java.util.regex.Pattern IP_ADDRESS;
field public static final java.util.regex.Pattern PHONE;
field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN;
@@ -39598,7 +39631,6 @@ package android.view {
method public boolean getResult();
method public float getX();
method public float getY();
- method public android.view.DropPermissions requestDropPermissions();
method public void writeToParcel(android.os.Parcel, int);
field public static final int ACTION_DRAG_ENDED = 4; // 0x4
field public static final int ACTION_DRAG_ENTERED = 5; // 0x5
diff --git a/api/test-removed.txt b/api/test-removed.txt
index f12e61eea332..6b7961e9f1f6 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -199,6 +199,15 @@ package android.provider {
}
+package android.test.mock {
+
+ public class MockPackageManager extends android.content.pm.PackageManager {
+ method public deprecated java.lang.String getDefaultBrowserPackageName(int);
+ method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
+ }
+
+}
+
package android.text.format {
public class DateFormat {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 4f7a1095cfbe..6302d7418cd0 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -159,6 +159,7 @@ public class Am extends BaseCommand {
" am stack start <DISPLAY_ID> <INTENT>\n" +
" am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
" am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+ " am stack resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]\n" +
" am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" +
" am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
" am stack positiontask <TASK_ID> <STACK_ID> <POSITION>\n" +
@@ -299,7 +300,11 @@ public class Am extends BaseCommand {
"am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
" bottom (false) of <STACK_ID>.\n" +
"\n" +
- "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>." +
+ "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
+ "\n" +
+ "am stack resize-docked-stack: change docked stack to <LEFT,TOP,RIGHT,BOTTOM>\n" +
+ " and supplying temporary different task bounds indicated by\n" +
+ " <TASK_LEFT,TOP,RIGHT,BOTTOM>\n" +
"\n" +
"am stack size-docked-stack-test: test command for sizing docked stack by\n" +
" <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom\n" +
@@ -1683,6 +1688,9 @@ public class Am extends BaseCommand {
case "resize":
runStackResize();
break;
+ case "resize-docked-stack":
+ runStackResizeDocked();
+ break;
case "positiontask":
runStackPositionTask();
break;
@@ -1751,6 +1759,20 @@ public class Am extends BaseCommand {
resizeStack(stackId, bounds, 0);
}
+ private void runStackResizeDocked() throws Exception {
+ final Rect bounds = getBounds();
+ final Rect taskBounds = getBounds();
+ if (bounds == null || taskBounds == null) {
+ System.err.println("Error: invalid input bounds");
+ return;
+ }
+ try {
+ mAm.resizeDockedStack(bounds, taskBounds, null, null, null);
+ } catch (RemoteException e) {
+ showError("Error: resizing docked stack " + e);
+ }
+ }
+
private void resizeStack(int stackId, Rect bounds, int delayMs) throws Exception {
if (bounds == null) {
showError("Error: invalid input bounds");
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 3e6b595da00e..6fc0d74b5f18 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -1082,6 +1082,10 @@ public abstract class ActionBar {
return false;
}
+ /** @hide */
+ public void onDestroy() {
+ }
+
/**
* Common implementation for requestFocus that takes in the Toolbar and moves focus
* to the contents. This makes the ViewGroups containing the toolbar allow focus while it stays
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6d72059e0a47..8346161548aa 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -31,6 +31,8 @@ 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;
@@ -1701,6 +1703,10 @@ public class Activity extends ContextThemeWrapper
mSearchManager.stopSearch();
}
+ if (mActionBar != null) {
+ mActionBar.onDestroy();
+ }
+
getApplication().dispatchActivityDestroyed(this);
}
@@ -2206,14 +2212,22 @@ public class Activity extends ContextThemeWrapper
* @param toolbar Toolbar to set as the Activity's action bar
*/
public void setActionBar(@Nullable Toolbar toolbar) {
- if (getActionBar() instanceof WindowDecorActionBar) {
+ final ActionBar ab = getActionBar();
+ if (ab instanceof WindowDecorActionBar) {
throw new IllegalStateException("This Activity already has an action bar supplied " +
"by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " +
"android:windowActionBar to false in your theme to use a Toolbar instead.");
}
- // Clear out the MenuInflater to make sure that it is valid for the new Action Bar
+
+ // If we reach here then we're setting a new action bar
+ // First clear out the MenuInflater to make sure that it is valid for the new Action Bar
mMenuInflater = null;
+ // If we have an action bar currently, destroy it
+ if (ab != null) {
+ ab.onDestroy();
+ }
+
ToolbarActionBar tbab = new ToolbarActionBar(toolbar, getTitle(), this);
mActionBar = tbab;
mWindow.setCallback(tbab.getWrappedWindowCallback());
@@ -6336,6 +6350,21 @@ public class Activity extends ContextThemeWrapper
mActivityTransitionState.startPostponedEnterTransition();
}
+ /**
+ * Create {@link DropPermissions} object bound to this activity and controlling the access
+ * permissions for content URIs associated with the {@link DragEvent}.
+ * @param event Drag event
+ * @return The DropPermissions object used to control access to the content URIs. Null if
+ * no content URIs are associated with the event or if permissions could not be granted.
+ */
+ public DropPermissions requestDropPermissions(DragEvent event) {
+ DropPermissions dropPermissions = DropPermissions.obtain(event);
+ if (dropPermissions != null && dropPermissions.take(getActivityToken())) {
+ return dropPermissions;
+ }
+ return null;
+ }
+
// ------------------ Internal API ------------------
final void setParent(Activity parent) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1b0827331903..da21099eda2b 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -332,10 +332,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
{
data.enforceInterface(IActivityManager.descriptor);
final int taskId = data.readInt();
- final int launchStackId = data.readInt();
final Bundle options =
data.readInt() == 0 ? null : Bundle.CREATOR.createFromParcel(data);
- final int result = startActivityFromRecents(taskId, launchStackId, options);
+ final int result = startActivityFromRecents(taskId, options);
reply.writeNoException();
reply.writeInt(result);
return true;
@@ -571,6 +570,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case ACTIVITY_RELAUNCHED_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ activityRelaunched(token);
+ reply.writeNoException();
+ return true;
+ }
+
case GET_CALLING_PACKAGE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -786,6 +793,39 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case RESIZE_DOCKED_STACK_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final boolean hasBounds = data.readInt() != 0;
+ Rect bounds = null;
+ if (hasBounds) {
+ bounds = Rect.CREATOR.createFromParcel(data);
+ }
+ final boolean hasTempDockedTaskBounds = data.readInt() != 0;
+ Rect tempDockedTaskBounds = null;
+ if (hasTempDockedTaskBounds) {
+ tempDockedTaskBounds = Rect.CREATOR.createFromParcel(data);
+ }
+ final boolean hasTempDockedTaskInsetBounds = data.readInt() != 0;
+ Rect tempDockedTaskInsetBounds = null;
+ if (hasTempDockedTaskInsetBounds) {
+ tempDockedTaskInsetBounds = Rect.CREATOR.createFromParcel(data);
+ }
+ final boolean hasTempOtherTaskBounds = data.readInt() != 0;
+ Rect tempOtherTaskBounds = null;
+ if (hasTempOtherTaskBounds) {
+ tempOtherTaskBounds = Rect.CREATOR.createFromParcel(data);
+ }
+ final boolean hasTempOtherTaskInsetBounds = data.readInt() != 0;
+ Rect tempOtherTaskInsetBounds = null;
+ if (hasTempOtherTaskInsetBounds) {
+ tempOtherTaskInsetBounds = Rect.CREATOR.createFromParcel(data);
+ }
+ resizeDockedStack(bounds, tempDockedTaskBounds, tempDockedTaskInsetBounds,
+ tempOtherTaskBounds, tempOtherTaskInsetBounds);
+ reply.writeNoException();
+ return true;
+ }
+
case POSITION_TASK_IN_STACK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int taskId = data.readInt();
@@ -1845,6 +1885,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder activityToken = data.readStrongBinder();
+ IBinder perm = getUriPermissionOwnerForActivity(activityToken);
+ reply.writeNoException();
+ reply.writeStrongBinder(perm);
+ return true;
+ }
+
case GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder owner = data.readStrongBinder();
@@ -3079,13 +3128,12 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
return result != 0;
}
- public int startActivityFromRecents(int taskId, int launchStackId, Bundle options)
+ public int startActivityFromRecents(int taskId, Bundle options)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(taskId);
- data.writeInt(launchStackId);
if (options == null) {
data.writeInt(0);
} else {
@@ -3373,6 +3421,17 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
+ public void activityRelaunched(IBinder token) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(ACTIVITY_RELAUNCHED_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
public String getCallingPackage(IBinder token) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -3683,6 +3742,50 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
@Override
+ public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+ Rect tempDockedTaskInsetBounds,
+ Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds)
+ throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ if (dockedBounds != null) {
+ data.writeInt(1);
+ dockedBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ if (tempDockedTaskBounds != null) {
+ data.writeInt(1);
+ tempDockedTaskBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ if (tempDockedTaskInsetBounds != null) {
+ data.writeInt(1);
+ tempDockedTaskInsetBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ if (tempOtherTaskBounds != null) {
+ data.writeInt(1);
+ tempOtherTaskBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ if (tempOtherTaskInsetBounds != null) {
+ data.writeInt(1);
+ tempOtherTaskInsetBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ mRemote.transact(RESIZE_DOCKED_STACK_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+ @Override
public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -5121,6 +5224,19 @@ class ActivityManagerProxy implements IActivityManager
return res;
}
+ public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(activityToken);
+ mRemote.transact(GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION, data, reply, 0);
+ reply.readException();
+ IBinder res = reply.readStrongBinder();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index cee1aa5b90e9..e596a68304fb 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -17,6 +17,7 @@
package android.app;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import android.content.Context;
import android.content.Intent;
@@ -67,7 +68,8 @@ public class ActivityOptions {
* The bounds (window size) that the activity should be launched in. Set to null explicitly for
* full screen. If the key is not found, previous bounds will be preserved.
* NOTE: This value is ignored on devices that don't have
- * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} enabled.
+ * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or
+ * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled.
* @hide
*/
public static final String KEY_LAUNCH_BOUNDS = "android:activity.launchBounds";
@@ -145,6 +147,12 @@ public class ActivityOptions {
private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
/**
+ * The stack id the activity should be launched into.
+ * @hide
+ */
+ private static final String KEY_LAUNCH_STACK_ID = "android.activity.launchStackId";
+
+ /**
* Where the docked stack should be positioned.
* @hide
*/
@@ -215,6 +223,7 @@ public class ActivityOptions {
private int mResultCode;
private int mExitCoordinatorIndex;
private PendingIntent mUsageTimeReport;
+ private int mLaunchStackId = INVALID_STACK_ID;
private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
private AppTransitionAnimationSpec mAnimSpecs[];
@@ -754,6 +763,7 @@ public class ActivityOptions {
mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
break;
}
+ mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID);
mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
if (opts.containsKey(KEY_ANIM_SPECS)) {
Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
@@ -901,7 +911,19 @@ public class ActivityOptions {
}
/** @hide */
- public int getDockCreateMode() { return mDockCreateMode; }
+ public int getLaunchStackId() {
+ return mLaunchStackId;
+ }
+
+ /** @hide */
+ public void setLaunchStackId(int launchStackId) {
+ mLaunchStackId = launchStackId;
+ }
+
+ /** @hide */
+ public int getDockCreateMode() {
+ return mDockCreateMode;
+ }
/** @hide */
public void setDockCreateMode(int dockCreateMode) {
@@ -1049,6 +1071,7 @@ public class ActivityOptions {
b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
break;
}
+ b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId);
b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
if (mAnimSpecs != null) {
b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ed168d1674ac..177fabe2d25c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4161,6 +4161,15 @@ public final class ActivityThread {
r.pendingIntents = pendingNewIntents;
}
}
+
+ // For each relaunch request, activity manager expects an answer
+ if (!r.onlyLocalRequest && fromServer) {
+ try {
+ ActivityManagerNative.getDefault().activityRelaunched(token);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
break;
}
}
@@ -4275,6 +4284,13 @@ public final class ActivityThread {
ActivityClientRecord r = mActivities.get(tmp.token);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r);
if (r == null) {
+ if (!tmp.onlyLocalRequest) {
+ try {
+ ActivityManagerNative.getDefault().activityRelaunched(tmp.token);
+ } catch (RemoteException e) {
+ // If the system process has died, it's game over for everyone.
+ }
+ }
return;
}
@@ -4320,6 +4336,14 @@ public final class ActivityThread {
r.overrideConfig = tmp.overrideConfig;
handleLaunchActivity(r, currentIntent);
+
+ if (!tmp.onlyLocalRequest) {
+ try {
+ ActivityManagerNative.getDefault().activityRelaunched(r.token);
+ } catch (RemoteException e) {
+ // If the system process has died, it's game over for everyone.
+ }
+ }
}
private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 77721e687389..e34b1ac713be 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -42,7 +42,6 @@ import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
@@ -229,7 +228,7 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public int getPackageUid(String packageName, int userHandle)
+ public int getPackageUidAsUser(String packageName, int userHandle)
throws NameNotFoundException {
try {
int uid = mPM.getPackageUid(packageName, userHandle);
@@ -591,12 +590,12 @@ public class ApplicationPackageManager extends PackageManager {
@SuppressWarnings("unchecked")
@Override
public List<PackageInfo> getInstalledPackages(int flags) {
- return getInstalledPackages(flags, mContext.getUserId());
+ return getInstalledPackagesAsUser(flags, mContext.getUserId());
}
/** @hide */
@Override
- public List<PackageInfo> getInstalledPackages(int flags, int userId) {
+ public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
try {
ParceledListSlice<PackageInfo> slice = mPM.getInstalledPackages(flags, userId);
return slice.getList();
@@ -780,7 +779,7 @@ public class ApplicationPackageManager extends PackageManager {
* @hide
*/
@Override
- public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) {
+ public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
try {
return mPM.queryIntentReceivers(
intent,
@@ -794,7 +793,7 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
- return queryBroadcastReceivers(intent, flags, mContext.getUserId());
+ return queryBroadcastReceiversAsUser(intent, flags, mContext.getUserId());
}
@Override
@@ -1421,7 +1420,7 @@ public class ApplicationPackageManager extends PackageManager {
public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
String installerPackageName) {
final VerificationParams verificationParams = new VerificationParams(null, null,
- null, VerificationParams.NO_UID, null);
+ null, VerificationParams.NO_UID);
installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
installerPackageName, verificationParams, null, mContext.getUserId());
}
@@ -1429,9 +1428,9 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
int flags, String installerPackageName, Uri verificationURI,
- ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+ ContainerEncryptionParams encryptionParams) {
final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
- null, VerificationParams.NO_UID, manifestDigest);
+ null, VerificationParams.NO_UID);
installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
}
@@ -1455,7 +1454,7 @@ public class ApplicationPackageManager extends PackageManager {
public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer, int flags,
String installerPackageName, int userId) {
final VerificationParams verificationParams = new VerificationParams(null, null,
- null, VerificationParams.NO_UID, null);
+ null, VerificationParams.NO_UID);
installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null,
userId);
}
@@ -1463,10 +1462,10 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public void installPackageWithVerification(Uri packageURI,
PackageInstallObserver observer, int flags, String installerPackageName,
- Uri verificationURI, ManifestDigest manifestDigest,
+ Uri verificationURI,
ContainerEncryptionParams encryptionParams) {
final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
- null, VerificationParams.NO_UID, manifestDigest);
+ null, VerificationParams.NO_UID);
installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
encryptionParams, mContext.getUserId());
}
@@ -1547,7 +1546,7 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public int getIntentVerificationStatus(String packageName, int userId) {
+ public int getIntentVerificationStatusAsUser(String packageName, int userId) {
try {
return mPM.getIntentVerificationStatus(packageName, userId);
} catch (RemoteException e) {
@@ -1557,7 +1556,7 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+ public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) {
try {
return mPM.updateIntentVerificationStatus(packageName, status, userId);
} catch (RemoteException e) {
@@ -1587,7 +1586,7 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public String getDefaultBrowserPackageName(int userId) {
+ public String getDefaultBrowserPackageNameAsUser(int userId) {
try {
return mPM.getDefaultBrowserPackageName(userId);
} catch (RemoteException e) {
@@ -1597,7 +1596,7 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+ public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
try {
return mPM.setDefaultBrowserPackageName(packageName, userId);
} catch (RemoteException e) {
@@ -1868,7 +1867,7 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public void getPackageSizeInfo(String packageName, int userHandle,
+ public void getPackageSizeInfoAsUser(String packageName, int userHandle,
IPackageStatsObserver observer) {
try {
mPM.getPackageSizeInfo(packageName, userHandle, observer);
@@ -1915,7 +1914,7 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public void addPreferredActivity(IntentFilter filter, int match,
+ public void addPreferredActivityAsUser(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, int userId) {
try {
mPM.addPreferredActivity(filter, match, set, activity, userId);
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 984a18615caf..a147cc87d465 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -719,7 +719,7 @@ final class BackStackRecord extends FragmentTransaction implements
Fragment f = op.fragment;
int containerId = f.mContainerId;
if (mManager.mAdded != null) {
- for (int i = 0; i < mManager.mAdded.size(); i++) {
+ for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
Fragment old = mManager.mAdded.get(i);
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG,
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 3fbbdffba58f..8d7f347024b2 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -16,6 +16,9 @@
package android.app;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@@ -35,95 +38,126 @@ import java.util.Calendar;
/**
* A simple dialog containing an {@link android.widget.DatePicker}.
- *
- * <p>See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
- * guide.</p>
+ * <p>
+ * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
+ * guide.
*/
public class DatePickerDialog extends AlertDialog implements OnClickListener,
OnDateChangedListener {
-
private static final String YEAR = "year";
private static final String MONTH = "month";
private static final String DAY = "day";
private final DatePicker mDatePicker;
- private final OnDateSetListener mDateSetListener;
private final Calendar mCalendar;
+ private OnDateSetListener mDateSetListener;
+
private boolean mTitleNeedsUpdate = true;
/**
- * The callback used to indicate the user is done filling in the date.
+ * Creates a new date picker dialog for the current date using the parent
+ * context's default date picker dialog theme.
+ *
+ * @param context the parent context
*/
- public interface OnDateSetListener {
-
- /**
- * @param view The view associated with this listener.
- * @param year The year that was set.
- * @param monthOfYear The month that was set (0-11) for compatibility
- * with {@link java.util.Calendar}.
- * @param dayOfMonth The day of the month that was set.
- */
- void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth);
+ public DatePickerDialog(Context context) {
+ this(context, 0);
}
/**
- * @param context The context the dialog is to run in.
- * @param callBack How the parent is notified that the date is set.
- * @param year The initial year of the dialog.
- * @param monthOfYear The initial month of the dialog.
- * @param dayOfMonth The initial day of the dialog.
- */
- public DatePickerDialog(Context context,
- OnDateSetListener callBack,
- int year,
- int monthOfYear,
- int dayOfMonth) {
- this(context, 0, callBack, year, monthOfYear, dayOfMonth);
- }
-
- static int resolveDialogTheme(Context context, int resid) {
- if (resid == 0) {
- final TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.datePickerDialogTheme, outValue, true);
- return outValue.resourceId;
- } else {
- return resid;
- }
- }
-
- /**
- * @param context The context the dialog is to run in.
- * @param theme the theme to apply to this dialog
- * @param listener How the parent is notified that the date is set.
- * @param year The initial year of the dialog.
- * @param monthOfYear The initial month of the dialog.
- * @param dayOfMonth The initial day of the dialog.
+ * Creates a new date picker dialog for the current date.
+ *
+ * @param context the parent context
+ * @param themeResId the resource ID of the theme against which to inflate
+ * this dialog, or {@code 0} to use the parent
+ * {@code context}'s default alert dialog theme
*/
- public DatePickerDialog(Context context, int theme, OnDateSetListener listener, int year,
- int monthOfYear, int dayOfMonth) {
- super(context, resolveDialogTheme(context, theme));
-
- mDateSetListener = listener;
- mCalendar = Calendar.getInstance();
+ public DatePickerDialog(Context context, @StyleRes int themeResId) {
+ super(context, resolveDialogTheme(context, themeResId));
final Context themeContext = getContext();
final LayoutInflater inflater = LayoutInflater.from(themeContext);
final View view = inflater.inflate(R.layout.date_picker_dialog, null);
setView(view);
+
setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
+ mCalendar = Calendar.getInstance();
+
+ final int year = mCalendar.get(Calendar.YEAR);
+ final int monthOfYear = mCalendar.get(Calendar.MONTH);
+ final int dayOfMonth = mCalendar.get(Calendar.DAY_OF_MONTH);
mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
mDatePicker.init(year, monthOfYear, dayOfMonth, this);
mDatePicker.setValidationCallback(mValidationCallback);
}
+ /**
+ * Creates a new date picker dialog for the specified date using the parent
+ * context's default date picker dialog theme.
+ *
+ * @param context the parent context
+ * @param listener the listener to call when the user sets the date
+ * @param year the initially selected year
+ * @param month the initially selected month (0-11 for compatibility with
+ * {@link Calendar#MONTH})
+ * @param dayOfMonth the initially selected day of month (1-31, depending
+ * on month)
+ */
+ public DatePickerDialog(@Nullable Context context, @Nullable OnDateSetListener listener,
+ int year, int month, int dayOfMonth) {
+ this(context, 0, listener, year, month, dayOfMonth);
+ }
+
+ /**
+ * Creates a new date picker dialog for the specified date.
+ *
+ * @param context the parent context
+ * @param themeResId the resource ID of the theme against which to inflate
+ * this dialog, or {@code 0} to use the parent
+ * {@code context}'s default alert dialog theme
+ * @param listener the listener to call when the user sets the date
+ * @param year the initially selected year
+ * @param month the initially selected month (0-11 for compatibility with
+ * {@link Calendar#MONTH})
+ * @param dayOfMonth the initially selected day of month (1-31, depending
+ * on month)
+ */
+ public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,
+ @Nullable OnDateSetListener listener, int year, int month, int dayOfMonth) {
+ this(context, themeResId);
+
+ mDateSetListener = listener;
+
+ mDatePicker.updateDate(year, month, dayOfMonth);
+ }
+
+ static int resolveDialogTheme(@NonNull Context context, @StyleRes int themeResId) {
+ if (themeResId == 0) {
+ final TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(R.attr.datePickerDialogTheme, outValue, true);
+ return outValue.resourceId;
+ } else {
+ return themeResId;
+ }
+ }
+
@Override
- public void onDateChanged(DatePicker view, int year, int month, int day) {
- mDatePicker.init(year, month, day, this);
- updateTitle(year, month, day);
+ public void onDateChanged(DatePicker view, int year, int month, int dayOfMonth) {
+ mDatePicker.init(year, month, dayOfMonth, this);
+ updateTitle(year, month, dayOfMonth);
+ }
+
+ /**
+ * Sets the listener to call when the user sets the date.
+ *
+ * @param listener the listener to call when the user sets the date
+ */
+ public void setOnDateSetListener(@Nullable OnDateSetListener listener) {
+ mDateSetListener = listener;
}
@Override
@@ -145,10 +179,11 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
}
/**
- * Gets the {@link DatePicker} contained in this dialog.
+ * Returns the {@link DatePicker} contained in this dialog.
*
- * @return The calendar view.
+ * @return the date picker
*/
+ @NonNull
public DatePicker getDatePicker() {
return mDatePicker;
}
@@ -156,20 +191,22 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
/**
* Sets the current date.
*
- * @param year The date year.
- * @param monthOfYear The date month.
- * @param dayOfMonth The date day of month.
+ * @param year the year
+ * @param month the month (0-11 for compatibility with
+ * {@link Calendar#MONTH})
+ * @param dayOfMonth the day of month (1-31, depending on month)
*/
- public void updateDate(int year, int monthOfYear, int dayOfMonth) {
- mDatePicker.updateDate(year, monthOfYear, dayOfMonth);
+ public void updateDate(int year, int month, int dayOfMonth) {
+ mDatePicker.updateDate(year, month, dayOfMonth);
}
- private void updateTitle(int year, int month, int day) {
+ private void updateTitle(int year, int month, int dayOfMonth) {
if (!mDatePicker.getCalendarViewShown()) {
mCalendar.set(Calendar.YEAR, year);
mCalendar.set(Calendar.MONTH, month);
- mCalendar.set(Calendar.DAY_OF_MONTH, day);
- String title = DateUtils.formatDateTime(mContext,
+ mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
+
+ final String title = DateUtils.formatDateTime(mContext,
mCalendar.getTimeInMillis(),
DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_SHOW_WEEKDAY
@@ -177,12 +214,12 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
| DateUtils.FORMAT_ABBREV_MONTH
| DateUtils.FORMAT_ABBREV_WEEKDAY);
setTitle(title);
+
mTitleNeedsUpdate = true;
- } else {
- if (mTitleNeedsUpdate) {
- mTitleNeedsUpdate = false;
- setTitle(R.string.date_picker_dialog_title);
- }
+ } else if (mTitleNeedsUpdate) {
+ setTitle(R.string.date_picker_dialog_title);
+
+ mTitleNeedsUpdate = false;
}
}
@@ -213,4 +250,19 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
}
}
};
+
+ /**
+ * The listener used to indicate the user has finished selecting a date.
+ */
+ public interface OnDateSetListener {
+ /**
+ * @param view the picker associated with the dialog
+ * @param year the selected year
+ * @param month the selected month (0-11 for compatibility with
+ * {@link Calendar#MONTH})
+ * @param dayOfMonth th selected day of the month (1-31, depending on
+ * month)
+ */
+ void onDateSet(DatePicker view, int year, int month, int dayOfMonth);
+ }
}
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index fb0e79b849b2..a9516d03ba0d 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -27,6 +27,7 @@ import android.database.CursorWrapper;
import android.net.ConnectivityManager;
import android.net.NetworkPolicyManager;
import android.net.Uri;
+import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.Downloads;
@@ -105,8 +106,17 @@ public class DownloadManager {
public final static String COLUMN_LOCAL_URI = "local_uri";
/**
- * The pathname of the file where the download is stored.
+ * Path to the downloaded file on disk.
+ * <p>
+ * Note that apps may not have filesystem permissions to directly access
+ * this path. Instead of trying to open this path directly, apps should use
+ * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain access.
+ *
+ * @deprecated apps should transition to using
+ * {@link ContentResolver#openFileDescriptor(Uri, String)}
+ * instead.
*/
+ @Deprecated
public final static String COLUMN_LOCAL_FILENAME = "local_filename";
/**
@@ -908,16 +918,19 @@ public class DownloadManager {
}
}
- private ContentResolver mResolver;
- private String mPackageName;
+ private final ContentResolver mResolver;
+ private final String mPackageName;
+ private final int mTargetSdkVersion;
+
private Uri mBaseUri = Downloads.Impl.CONTENT_URI;
/**
* @hide
*/
- public DownloadManager(ContentResolver resolver, String packageName) {
- mResolver = resolver;
- mPackageName = packageName;
+ public DownloadManager(Context context) {
+ mResolver = context.getContentResolver();
+ mPackageName = context.getPackageName();
+ mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
}
/**
@@ -997,7 +1010,7 @@ public class DownloadManager {
if (underlyingCursor == null) {
return null;
}
- return new CursorTranslator(underlyingCursor, mBaseUri);
+ return new CursorTranslator(underlyingCursor, mBaseUri, mTargetSdkVersion);
}
/**
@@ -1265,11 +1278,13 @@ public class DownloadManager {
* underlying data.
*/
private static class CursorTranslator extends CursorWrapper {
- private Uri mBaseUri;
+ private final Uri mBaseUri;
+ private final int mTargetSdkVersion;
- public CursorTranslator(Cursor cursor, Uri baseUri) {
+ public CursorTranslator(Cursor cursor, Uri baseUri, int targetSdkVersion) {
super(cursor);
mBaseUri = baseUri;
+ mTargetSdkVersion = targetSdkVersion;
}
@Override
@@ -1290,8 +1305,19 @@ public class DownloadManager {
@Override
public String getString(int columnIndex) {
- return (getColumnName(columnIndex).equals(COLUMN_LOCAL_URI)) ? getLocalUri() :
- super.getString(columnIndex);
+ final String columnName = getColumnName(columnIndex);
+ switch (columnName) {
+ case COLUMN_LOCAL_URI:
+ return getLocalUri();
+ case COLUMN_LOCAL_FILENAME:
+ if (mTargetSdkVersion >= Build.VERSION_CODES.N) {
+ throw new IllegalArgumentException(
+ "COLUMN_LOCAL_FILENAME is deprecated;"
+ + " use ContentResolver.openFileDescriptor() instead");
+ }
+ default:
+ return super.getString(columnIndex);
+ }
}
private String getLocalUri() {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 0ecf2231665a..ceb14ad6d5d2 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -92,7 +92,7 @@ public interface IActivityManager extends IInterface {
int userId) throws RemoteException;
public boolean startNextMatchingActivity(IBinder callingActivity,
Intent intent, Bundle options) throws RemoteException;
- public int startActivityFromRecents(int taskId, int launchStackId, Bundle options)
+ public int startActivityFromRecents(int taskId, Bundle options)
throws RemoteException;
public boolean finishActivity(IBinder token, int code, Intent data, int finishTask)
throws RemoteException;
@@ -122,6 +122,7 @@ public interface IActivityManager extends IInterface {
PersistableBundle persistentState, CharSequence description) throws RemoteException;
public void activitySlept(IBinder token) throws RemoteException;
public void activityDestroyed(IBinder token) throws RemoteException;
+ public void activityRelaunched(IBinder token) throws RemoteException;
public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
int[] verticalSizeConfigurations, int[] smallestWidthConfigurations)
throws RemoteException;
@@ -145,7 +146,31 @@ public interface IActivityManager extends IInterface {
public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
Rect initialBounds) throws RemoteException;
public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
- public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) throws RemoteException;
+ public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode)
+ throws RemoteException;
+
+ /**
+ * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
+ *
+ * @param dockedBounds The bounds for the docked stack.
+ * @param tempDockedTaskBounds The temporary bounds for the tasks in the docked stack, which
+ * might be different from the stack bounds to allow more
+ * flexibility while resizing, or {@code null} if they should be the
+ * same as the stack bounds.
+ * @param tempDockedTaskInsetBounds The temporary bounds for the tasks to calculate the insets.
+ * When resizing, we usually "freeze" the layout of a task. To
+ * achieve that, we also need to "freeze" the insets, which
+ * gets achieved by changing task bounds but not bounds used
+ * to calculate the insets in this transient state
+ * @param tempOtherTaskBounds The temporary bounds for the tasks in all other stacks, or
+ * {@code null} if they should be the same as the stack bounds.
+ * @param tempOtherTaskInsetBounds Like {@code tempDockedTaskInsetBounds}, but for the other
+ * stacks.
+ * @throws RemoteException
+ */
+ public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+ Rect tempDockedTaskInsetBounds,
+ Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) throws RemoteException;
public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
public List<StackInfo> getAllStackInfos() throws RemoteException;
public StackInfo getStackInfo(int stackId) throws RemoteException;
@@ -363,6 +388,7 @@ public interface IActivityManager extends IInterface {
public String getProviderMimeType(Uri uri, int userId) throws RemoteException;
public IBinder newUriPermissionOwner(String name) throws RemoteException;
+ public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) throws RemoteException;
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException;
public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
@@ -919,5 +945,8 @@ public interface IActivityManager extends IInterface {
int IN_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 353;
int KILL_PACKAGE_DEPENDENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 354;
int ENTER_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 355;
- int SET_VR_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 356;
+ int ACTIVITY_RELAUNCHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 356;
+ int GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 357;
+ int RESIZE_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 358;
+ int SET_VR_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 359;
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index abe9822e972f..e60cb0377e96 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -78,6 +78,8 @@ interface INotificationManager
void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
void setInterruptionFilter(String pkg, int interruptionFilter);
+ void setImportanceFromAssistant(in INotificationListener token, String key, int importance, CharSequence explanation);
+
ComponentName getEffectsSuppressor();
boolean matchesCallFilter(in Bundle extras);
boolean isSystemConditionProviderEnabled(String path);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 4b0935ca23cc..560e22a3be1d 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -18,5 +18,9 @@ package android.app;
/** @hide */
oneway interface ITaskStackListener {
+ /** Called whenever there are changes to the state of tasks in a stack. */
void onTaskStackChanged();
+
+ /** Called whenever an Activity is moved to the pinned stack from another stack. */
+ void onActivityPinned();
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3ff089659456..a392abd80de8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -145,6 +145,11 @@ public class Notification implements Parcelable
private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024;
/**
+ * Maximum entries of reply text that are accepted by Builder and friends.
+ */
+ private static final int MAX_REPLY_HISTORY = 5;
+
+ /**
* A timestamp related to this notification, in milliseconds since the epoch.
*
* Default value: {@link System#currentTimeMillis() Now}.
@@ -745,6 +750,12 @@ public class Notification implements Parcelable
public static final String EXTRA_SUB_TEXT = "android.subText";
/**
+ * {@link #extras} key: this is the remote input history, as supplied to
+ * {@link Builder#setRemoteInputHistory(CharSequence[])}.
+ */
+ public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+
+ /**
* {@link #extras} key: this is a small piece of additional text as supplied to
* {@link Builder#setContentInfo(CharSequence)}.
*/
@@ -2324,6 +2335,34 @@ public class Notification implements Parcelable
}
/**
+ * Set the remote input history.
+ *
+ * This should be set to the most recent inputs that have been sent
+ * through a {@link RemoteInput} of this Notification and cleared once the it is no
+ * longer relevant (e.g. for chat notifications once the other party has responded).
+ *
+ * The most recent input must be stored at the 0 index, the second most recent at the
+ * 1 index, etc. Note that the system will limit both how far back the inputs will be shown
+ * and how much of each individual input is shown.
+ *
+ * <p>Note: The reply text will only be shown on notifications that have least one action
+ * with a {@code RemoteInput}.</p>
+ */
+ public Builder setRemoteInputHistory(CharSequence[] text) {
+ if (text == null) {
+ mN.extras.putCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY, null);
+ } else {
+ final int N = Math.min(MAX_REPLY_HISTORY, text.length);
+ CharSequence[] safe = new CharSequence[N];
+ for (int i = 0; i < N; i++) {
+ safe[i] = safeCharSequence(text[i]);
+ }
+ mN.extras.putCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY, safe);
+ }
+ return this;
+ }
+
+ /**
* Set the large number at the right-hand side of the notification. This is
* equivalent to setContentInfo, although it might show the number in a different
* font size for readability.
@@ -3232,6 +3271,14 @@ public class Notification implements Parcelable
private void resetStandardTemplateWithActions(RemoteViews big) {
big.setViewVisibility(R.id.actions, View.GONE);
big.removeAllViews(R.id.actions);
+
+ big.setViewVisibility(R.id.notification_material_reply_container, View.GONE);
+ big.setTextViewText(R.id.notification_material_reply_text_1, null);
+
+ big.setViewVisibility(R.id.notification_material_reply_text_2, View.GONE);
+ big.setTextViewText(R.id.notification_material_reply_text_2, null);
+ big.setViewVisibility(R.id.notification_material_reply_text_3, View.GONE);
+ big.setTextViewText(R.id.notification_material_reply_text_3, null);
}
private RemoteViews applyStandardTemplateWithActions(int layoutId) {
@@ -3239,18 +3286,62 @@ public class Notification implements Parcelable
resetStandardTemplateWithActions(big);
+ boolean validRemoteInput = false;
+
int N = mActions.size();
if (N > 0) {
big.setViewVisibility(R.id.actions, View.VISIBLE);
if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
for (int i=0; i<N; i++) {
- final RemoteViews button = generateActionButton(mActions.get(i));
+ Action action = mActions.get(i);
+ validRemoteInput |= hasValidRemoteInput(action);
+
+ final RemoteViews button = generateActionButton(action);
big.addView(R.id.actions, button);
}
}
+
+ CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
+ if (validRemoteInput && replyText != null
+ && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])) {
+ big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE);
+ big.setTextViewText(R.id.notification_material_reply_text_1, replyText[0]);
+
+ if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])) {
+ big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE);
+ big.setTextViewText(R.id.notification_material_reply_text_2, replyText[1]);
+
+ if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2])) {
+ big.setViewVisibility(
+ R.id.notification_material_reply_text_3, View.VISIBLE);
+ big.setTextViewText(R.id.notification_material_reply_text_3, replyText[2]);
+ }
+ }
+ }
+
return big;
}
+ private boolean hasValidRemoteInput(Action action) {
+ if (TextUtils.isEmpty(action.title) || action.actionIntent == null) {
+ // Weird actions
+ return false;
+ }
+
+ RemoteInput[] remoteInputs = action.getRemoteInputs();
+ if (remoteInputs == null) {
+ return false;
+ }
+
+ for (RemoteInput r : remoteInputs) {
+ CharSequence[] choices = r.getChoices();
+ if (r.getAllowFreeFormInput() || (choices != null && choices.length != 0)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Construct a RemoteViews for the final 1U notification layout. In order:
* 1. Custom contentView from the caller
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 85d9831921ac..9a3c82036399 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -637,10 +637,12 @@ public class NotificationManager
public static final int SUPPRESSED_EFFECTS_UNSET = -1;
public static final int SUPPRESSED_EFFECT_LIGHTS = 1 << 0;
public static final int SUPPRESSED_EFFECT_PEEK = 1 << 1;
+ public static final int SUPPRESSED_EFFECT_SCREEN_ON = 1 << 2;
private static final int[] ALL_SUPPRESSED_EFFECTS = {
SUPPRESSED_EFFECT_LIGHTS,
SUPPRESSED_EFFECT_PEEK,
+ SUPPRESSED_EFFECT_SCREEN_ON,
};
/**
@@ -750,6 +752,7 @@ public class NotificationManager
switch (effect) {
case SUPPRESSED_EFFECT_LIGHTS: return "SUPPRESSED_EFFECT_LIGHTS";
case SUPPRESSED_EFFECT_PEEK: return "SUPPRESSED_EFFECT_PEEK";
+ case SUPPRESSED_EFFECT_SCREEN_ON: return "SUPPRESSED_EFFECT_SCREEN_ON";
case SUPPRESSED_EFFECTS_UNSET: return "SUPPRESSED_EFFECTS_UNSET";
default: return "UNKNOWN_" + effect;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 288a2cb5fa4f..89d52f248bde 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -247,7 +247,7 @@ final class SystemServiceRegistry {
new CachedServiceFetcher<DownloadManager>() {
@Override
public DownloadManager createService(ContextImpl ctx) {
- return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
+ return new DownloadManager(ctx);
}});
registerService(Context.BATTERY_SERVICE, BatteryManager.class,
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index f7848f98b006..8475840bbae2 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -22,6 +22,7 @@ import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
@@ -856,6 +857,7 @@ public final class UiAutomation {
*
* @hide
*/
+ @TestApi
public boolean grantRuntimePermission(String packageName, String permission,
UserHandle userHandle) {
synchronized (mLock) {
@@ -884,6 +886,7 @@ public final class UiAutomation {
*
* @hide
*/
+ @TestApi
public boolean revokeRuntimePermission(String packageName, String permission,
UserHandle userHandle) {
synchronized (mLock) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5df6ba80a10a..f940bd6e8fed 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4142,6 +4142,10 @@ public class DevicePolicyManager {
* <p>When account management is disabled for an account type, adding or removing an account
* of that type will not be possible.
*
+ * <p>From {@link android.os.Build.VERSION_CODES#N} the profile or device owner can still use
+ * {@link android.accounts.AccountManager} APIs to add or remove accounts when account
+ * management for a specific type is disabled.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param accountType For which account management is disabled or enabled.
* @param disabled The boolean indicating that account management will be disabled (true) or
@@ -4798,4 +4802,129 @@ public class DevicePolicyManager {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
}
}
+
+ /**
+ * Called by a device admin to set the short support message. This will
+ * be displayed to the user in settings screens where funtionality has
+ * been disabled by the admin.
+ *
+ * The message should be limited to a short statement such as
+ * "This setting is disabled by your administrator. Contact someone@example.com
+ * for support."
+ * If the message is longer than 200 characters it may be truncated.
+ *
+ * @see #setLongSupportMessage
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param message Short message to be displayed to the user in settings or null to
+ * clear the existing message.
+ */
+ public void setShortSupportMessage(@NonNull ComponentName admin,
+ @Nullable String message) {
+ if (mService != null) {
+ try {
+ mService.setShortSupportMessage(admin, message);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
+ * Called by a device admin to get the short support message.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return The message set by {@link #setShortSupportMessage(ComponentName, String)}
+ * or null if no message has been set.
+ */
+ public String getShortSupportMessage(@NonNull ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getShortSupportMessage(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Called by a device admin to set the long support message. This will
+ * be displayed to the user in the device administators settings screen.
+ *
+ * @see #setShortSupportMessage
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param message Long message to be displayed to the user in settings or null to
+ * clear the existing message.
+ */
+ public void setLongSupportMessage(@NonNull ComponentName admin,
+ @Nullable String message) {
+ if (mService != null) {
+ try {
+ mService.setLongSupportMessage(admin, message);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
+ * Called by a device admin to get the long support message.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return The message set by {@link #setLongSupportMessage(ComponentName, String)}
+ * or null if no message has been set.
+ */
+ public String getLongSupportMessage(@NonNull ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getLongSupportMessage(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Called by the system to get the short support message.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param userHandle user id the admin is running as.
+ * @return The message set by {@link #setShortSupportMessage(ComponentName, String)}
+ *
+ * @hide
+ */
+ public String getShortSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+ if (mService != null) {
+ try {
+ return mService.getShortSupportMessageForUser(admin, userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Called by the system to get the long support message.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param userHandle user id the admin is running as.
+ * @return The message set by {@link #setLongSupportMessage(ComponentName, String)}
+ *
+ * @hide
+ */
+ public String getLongSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+ if (mService != null) {
+ try {
+ return mService.getLongSupportMessageForUser(admin, userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return null;
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 30ce682ef888..f480a02b21a0 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -245,4 +245,12 @@ interface IDevicePolicyManager {
boolean isSystemOnlyUser(in ComponentName admin);
String getWifiMacAddress();
void reboot(in ComponentName admin);
+
+ void setShortSupportMessage(in ComponentName admin, in String message);
+ String getShortSupportMessage(in ComponentName admin);
+ void setLongSupportMessage(in ComponentName admin, in String message);
+ String getLongSupportMessage(in ComponentName admin);
+
+ String getShortSupportMessageForUser(in ComponentName admin, int userHandle);
+ String getLongSupportMessageForUser(in ComponentName admin, int userHandle);
}
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index d12595f7ac07..dec0d9107d3a 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -19,6 +19,7 @@ package android.content;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.AssetFileDescriptor;
+import android.database.CrossProcessCursorWrapper;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -32,27 +33,34 @@ import android.os.RemoteException;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
import java.io.FileNotFoundException;
import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
- * The public interface object used to interact with a {@link ContentProvider}. This is obtained by
- * calling {@link ContentResolver#acquireContentProviderClient}. This object must be released
- * using {@link #release} in order to indicate to the system that the {@link ContentProvider} is
- * no longer needed and can be killed to free up resources.
- *
- * <p>Note that you should generally create a new ContentProviderClient instance
- * for each thread that will be performing operations. Unlike
+ * The public interface object used to interact with a specific
+ * {@link ContentProvider}.
+ * <p>
+ * Instances can be obtained by calling
+ * {@link ContentResolver#acquireContentProviderClient} or
+ * {@link ContentResolver#acquireUnstableContentProviderClient}. Instances must
+ * be released using {@link #close()} in order to indicate to the system that
+ * the underlying {@link ContentProvider} is no longer needed and can be killed
+ * to free up resources.
+ * <p>
+ * Note that you should generally create a new ContentProviderClient instance
+ * for each thread that will be performing operations. Unlike
* {@link ContentResolver}, the methods here such as {@link #query} and
- * {@link #openFile} are not thread safe -- you must not call
- * {@link #release()} on the ContentProviderClient those calls are made from
- * until you are finished with the data they have returned.
+ * {@link #openFile} are not thread safe -- you must not call {@link #close()}
+ * on the ContentProviderClient those calls are made from until you are finished
+ * with the data they have returned.
*/
-public class ContentProviderClient {
+public class ContentProviderClient implements AutoCloseable {
private static final String TAG = "ContentProviderClient";
@GuardedBy("ContentProviderClient.class")
@@ -63,22 +71,23 @@ public class ContentProviderClient {
private final String mPackageName;
private final boolean mStable;
- private final CloseGuard mGuard = CloseGuard.get();
+ private final AtomicBoolean mClosed = new AtomicBoolean();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
private long mAnrTimeout;
private NotRespondingRunnable mAnrRunnable;
- private boolean mReleased;
-
/** {@hide} */
- ContentProviderClient(
+ @VisibleForTesting
+ public ContentProviderClient(
ContentResolver contentResolver, IContentProvider contentProvider, boolean stable) {
mContentResolver = contentResolver;
mContentProvider = contentProvider;
mPackageName = contentResolver.mPackageName;
+
mStable = stable;
- mGuard.open("release");
+ mCloseGuard.open("close");
}
/** {@hide} */
@@ -133,8 +142,9 @@ public class ContentProviderClient {
remoteCancellationSignal = mContentProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
- return mContentProvider.query(mPackageName, url, projection, selection, selectionArgs,
- sortOrder, remoteCancellationSignal);
+ final Cursor cursor = mContentProvider.query(mPackageName, url, projection, selection,
+ selectionArgs, sortOrder, remoteCancellationSignal);
+ return new CursorWrapperInner(cursor);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -446,29 +456,42 @@ public class ContentProviderClient {
}
/**
- * Call this to indicate to the system that the associated {@link ContentProvider} is no
- * longer needed by this {@link ContentProviderClient}.
- * @return true if this was release, false if it was already released
+ * Closes this client connection, indicating to the system that the
+ * underlying {@link ContentProvider} is no longer needed.
*/
+ @Override
+ public void close() {
+ closeInternal();
+ }
+
+ /**
+ * @deprecated replaced by {@link #close()}.
+ */
+ @Deprecated
public boolean release() {
- synchronized (this) {
- if (mReleased) {
- throw new IllegalStateException("Already released");
- }
- mReleased = true;
- mGuard.close();
+ return closeInternal();
+ }
+
+ private boolean closeInternal() {
+ mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
if (mStable) {
return mContentResolver.releaseProvider(mContentProvider);
} else {
return mContentResolver.releaseUnstableProvider(mContentProvider);
}
+ } else {
+ return false;
}
}
@Override
protected void finalize() throws Throwable {
- if (mGuard != null) {
- mGuard.warnIfOpen();
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
}
}
@@ -502,4 +525,29 @@ public class ContentProviderClient {
mContentResolver.appNotRespondingViaProvider(mContentProvider);
}
}
+
+ private final class CursorWrapperInner extends CrossProcessCursorWrapper {
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ CursorWrapperInner(Cursor cursor) {
+ super(cursor);
+ mCloseGuard.open("close");
+ }
+
+ @Override
+ public void close() {
+ mCloseGuard.close();
+ super.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+ }
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 9d0ebc20bdfb..5105ad64489c 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -20,6 +20,7 @@ import android.accounts.Account;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.AppGlobals;
@@ -47,11 +48,11 @@ import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
-import dalvik.system.CloseGuard;
-
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import dalvik.system.CloseGuard;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -59,9 +60,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* This class provides applications access to the content model.
@@ -514,8 +515,9 @@ public abstract class ContentResolver {
maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
// Wrap the cursor object into CursorWrapperInner object.
- CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
- stableProvider != null ? stableProvider : acquireProvider(uri));
+ final IContentProvider provider = (stableProvider != null) ? stableProvider
+ : acquireProvider(uri);
+ final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
stableProvider = null;
qCursor = null;
return wrapper;
@@ -1956,6 +1958,7 @@ public abstract class ContentResolver {
* @hide
* Returns the package names of syncadapters that match a given user and authority.
*/
+ @TestApi
public static String[] getSyncAdapterPackagesForAuthorityAsUser(String authority,
int userId) {
try {
@@ -2503,41 +2506,31 @@ public abstract class ContentResolver {
private final class CursorWrapperInner extends CrossProcessCursorWrapper {
private final IContentProvider mContentProvider;
- public static final String TAG="CursorWrapperInner";
+ private final AtomicBoolean mProviderReleased = new AtomicBoolean();
private final CloseGuard mCloseGuard = CloseGuard.get();
- private boolean mProviderReleased;
- CursorWrapperInner(Cursor cursor, IContentProvider icp) {
+ CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) {
super(cursor);
- mContentProvider = icp;
+ mContentProvider = contentProvider;
mCloseGuard.open("close");
}
@Override
public void close() {
+ mCloseGuard.close();
super.close();
- ContentResolver.this.releaseProvider(mContentProvider);
- mProviderReleased = true;
- if (mCloseGuard != null) {
- mCloseGuard.close();
+ if (mProviderReleased.compareAndSet(false, true)) {
+ ContentResolver.this.releaseProvider(mContentProvider);
}
}
@Override
protected void finalize() throws Throwable {
try {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
-
- if (!mProviderReleased && mContentProvider != null) {
- // Even though we are using CloseGuard, log this anyway so that
- // application developers always see the message in the log.
- Log.w(TAG, "Cursor finalized without prior close()");
- ContentResolver.this.releaseProvider(mContentProvider);
- }
+ mCloseGuard.warnIfOpen();
+ close();
} finally {
super.finalize();
}
@@ -2546,7 +2539,7 @@ public abstract class ContentResolver {
private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
private final IContentProvider mContentProvider;
- private boolean mProviderReleased;
+ private final AtomicBoolean mProviderReleased = new AtomicBoolean();
ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
super(pfd);
@@ -2555,9 +2548,8 @@ public abstract class ContentResolver {
@Override
public void releaseResources() {
- if (!mProviderReleased) {
+ if (mProviderReleased.compareAndSet(false, true)) {
ContentResolver.this.releaseProvider(mContentProvider);
- mProviderReleased = true;
}
}
}
@@ -2584,7 +2576,9 @@ public abstract class ContentResolver {
private static IContentService sContentService;
private final Context mContext;
+
final String mPackageName;
+
private static final String TAG = "ContentResolver";
/** @hide */
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 67bdad576af3..9894b9289b10 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -30,6 +30,7 @@ import android.annotation.StringRes;
import android.annotation.StyleRes;
import android.annotation.StyleableRes;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
@@ -3967,6 +3968,7 @@ public abstract class Context {
*
* @hide
*/
+ @TestApi
public abstract int getUserId();
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0f3ca10c8fa4..35cd2bef6093 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3604,6 +3604,15 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_USER_ID = "android.intent.extra.USER_ID";
/**
+ * An int representing the task id to be retrieved. This is used when a launch from recents is
+ * intercepted by another action such as credentials confirmation to remember which task should
+ * be resumed when complete.
+ *
+ * @hide
+ */
+ public static final String EXTRA_TASK_ID = "android.intent.extra.TASK_ID";
+
+ /**
* An Intent[] describing additional, alternate choices you would like shown with
* {@link #ACTION_CHOOSER}.
*
@@ -4169,11 +4178,18 @@ public class Intent implements Parcelable, Cloneable {
/**
* Internal flag used to indicate that a system component has done their
- * homework and verified their encryption-aware behavior.
+ * homework and verified that they correctly handle packages and components
+ * that come and go over time. In particular:
+ * <ul>
+ * <li>Apps installed on external storage, which will appear to be
+ * uninstalled while the the device is ejected.
+ * <li>Apps with encryption unaware components, which will appear to not
+ * exist while the device is locked.
+ * </ul>
*
* @hide
*/
- public static final int FLAG_DEBUG_ENCRYPTION_TRIAGED = 0x00000100;
+ public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100;
/**
* If set, the new activity is not kept in the history stack. As soon as
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 326735ec4f36..dedf07f5dcff 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -281,6 +281,29 @@ public class ActivityInfo extends ComponentInfo
* {@see android.app.Activity#setVrMode(boolean)}.
*/
public static final int FLAG_ENABLE_VR_MODE = 0x8000;
+
+ /**
+ * Bit in {@link #flags} indicating if the activity is resizeable to any dimension.
+ * See {@link android.R.attr#resizeableActivity}.
+ * @hide
+ */
+ public static final int FLAG_RESIZEABLE = 0x10000;
+
+ /**
+ * Bit in {@link #flags} indicating if the activity is supports picture-in-picture form of
+ * multi-window mode. See {@link android.R.attr#supportsPictureInPicture}.
+ * @hide
+ */
+ public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x20000;
+
+ /**
+ * Bit in {@link #flags} indicating if the activity is always focusable regardless of if it is
+ * in a task/stack whose activities are normally not focusable.
+ * See android.R.attr#alwaysFocusable.
+ * @hide
+ */
+ public static final int FLAG_ALWAYS_FOCUSABLE = 0x40000;
+
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the system user. Only works with broadcast receivers. Set from the
@@ -670,20 +693,6 @@ public class ActivityInfo extends ComponentInfo
*/
public String parentActivityName;
- /**
- * Value indicating if the activity is resizeable to any dimension.
- * See {@link android.R.attr#resizeableActivity}.
- * @hide
- */
- public boolean resizeable;
-
- /**
- * Value indicating if the activity is supports picture-in-picture form of multi-window mode.
- * See {@link android.R.attr#supportsPictureInPicture}.
- * @hide
- */
- public boolean supportsPip;
-
/** @hide */
public static final int LOCK_TASK_LAUNCH_MODE_DEFAULT = 0;
/** @hide */
@@ -735,8 +744,6 @@ public class ActivityInfo extends ComponentInfo
uiOptions = orig.uiOptions;
parentActivityName = orig.parentActivityName;
maxRecents = orig.maxRecents;
- resizeable = orig.resizeable;
- supportsPip = orig.supportsPip;
lockTaskLaunchMode = orig.lockTaskLaunchMode;
layout = orig.layout;
}
@@ -791,7 +798,6 @@ public class ActivityInfo extends ComponentInfo
pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
}
if ((flags&DUMP_FLAG_DETAILS) != 0) {
- pw.println(prefix + "resizeable=" + resizeable + " supportsPip=" + supportsPip);
pw.println(prefix + "lockTaskLaunchMode="
+ lockTaskLaunchModeToString(lockTaskLaunchMode));
}
@@ -829,8 +835,6 @@ public class ActivityInfo extends ComponentInfo
dest.writeString(parentActivityName);
dest.writeInt(persistableMode);
dest.writeInt(maxRecents);
- dest.writeInt(resizeable ? 1 : 0);
- dest.writeInt(supportsPip ? 1 : 0);
dest.writeInt(lockTaskLaunchMode);
if (layout != null) {
dest.writeInt(1);
@@ -871,8 +875,6 @@ public class ActivityInfo extends ComponentInfo
parentActivityName = source.readString();
persistableMode = source.readInt();
maxRecents = source.readInt();
- resizeable = (source.readInt() == 1);
- supportsPip = (source.readInt() == 1);
lockTaskLaunchMode = source.readInt();
if (source.readInt() == 1) {
layout = new Layout(source);
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index fe279d1d9b6f..411dfa253081 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.annotation.TestApi;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@@ -1069,6 +1070,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/**
* @hide
*/
+ @TestApi
public boolean isSystemApp() {
return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
@@ -1076,6 +1078,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/**
* @hide
*/
+ @TestApi
public boolean isPrivilegedApp() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
diff --git a/core/java/android/content/pm/ManifestDigest.java b/core/java/android/content/pm/ManifestDigest.java
deleted file mode 100644
index e7dc76488903..000000000000
--- a/core/java/android/content/pm/ManifestDigest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import com.android.internal.util.HexDump;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Slog;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.DigestInputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-
-import libcore.io.IoUtils;
-
-/**
- * Represents the manifest digest for a package. This is suitable for comparison
- * of two packages to know whether the manifests are identical.
- *
- * @hide
- */
-@SystemApi
-public class ManifestDigest implements Parcelable {
- private static final String TAG = "ManifestDigest";
-
- /** The digest of the manifest in our preferred order. */
- private final byte[] mDigest;
-
- /** What we print out first when toString() is called. */
- private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest=";
-
- /** Digest algorithm to use. */
- private static final String DIGEST_ALGORITHM = "SHA-256";
-
- ManifestDigest(byte[] digest) {
- mDigest = digest;
- }
-
- private ManifestDigest(Parcel source) {
- mDigest = source.createByteArray();
- }
-
- static ManifestDigest fromInputStream(InputStream fileIs) {
- if (fileIs == null) {
- return null;
- }
-
- final MessageDigest md;
- try {
- md = MessageDigest.getInstance(DIGEST_ALGORITHM);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(DIGEST_ALGORITHM + " must be available", e);
- }
-
- final DigestInputStream dis = new DigestInputStream(new BufferedInputStream(fileIs), md);
- try {
- byte[] readBuffer = new byte[8192];
- while (dis.read(readBuffer, 0, readBuffer.length) != -1) {
- // not using
- }
- } catch (IOException e) {
- Slog.w(TAG, "Could not read manifest");
- return null;
- } finally {
- IoUtils.closeQuietly(dis);
- }
-
- final byte[] digest = md.digest();
- return new ManifestDigest(digest);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof ManifestDigest)) {
- return false;
- }
-
- final ManifestDigest other = (ManifestDigest) o;
-
- return this == other || Arrays.equals(mDigest, other.mDigest);
- }
-
- @Override
- public int hashCode() {
- return Arrays.hashCode(mDigest);
- }
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX.length()
- + (mDigest.length * 3) + 1);
-
- sb.append(TO_STRING_PREFIX);
-
- final int N = mDigest.length;
- for (int i = 0; i < N; i++) {
- final byte b = mDigest[i];
- HexDump.appendByteAsHex(sb, b, false);
- sb.append(',');
- }
- sb.append('}');
-
- return sb.toString();
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeByteArray(mDigest);
- }
-
- public static final Parcelable.Creator<ManifestDigest> CREATOR
- = new Parcelable.Creator<ManifestDigest>() {
- public ManifestDigest createFromParcel(Parcel source) {
- return new ManifestDigest(source);
- }
-
- public ManifestDigest[] newArray(int size) {
- return new ManifestDigest[size];
- }
- };
-
-}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 69f508e54119..87502821735d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -27,6 +27,7 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.StringRes;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.annotation.XmlRes;
import android.app.PackageDeleteObserver;
import android.app.PackageInstallObserver;
@@ -93,6 +94,109 @@ public abstract class PackageManager {
}
/**
+ * As a guiding principle:
+ * <p>
+ * {@code GET_} flags are used to request additional data that may have been
+ * elided to save wire space.
+ * <p>
+ * {@code MATCH_} flags are used to include components or packages that
+ * would have otherwise been omitted from a result set by current system
+ * state.
+ */
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_ACTIVITIES,
+ GET_RECEIVERS,
+ GET_SERVICES,
+ GET_PROVIDERS,
+ GET_INSTRUMENTATION,
+ GET_INTENT_FILTERS,
+ GET_SIGNATURES,
+ GET_META_DATA,
+ GET_GIDS,
+ GET_SHARED_LIBRARY_FILES,
+ GET_URI_PERMISSION_PATTERNS,
+ GET_PERMISSIONS,
+ GET_CONFIGURATIONS,
+ MATCH_UNINSTALLED_PACKAGES,
+ MATCH_DISABLED_COMPONENTS,
+ MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PackageInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ GET_SHARED_LIBRARY_FILES,
+ MATCH_UNINSTALLED_PACKAGES,
+ MATCH_SYSTEM_ONLY,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ApplicationInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ GET_SHARED_LIBRARY_FILES,
+ MATCH_UNINSTALLED_PACKAGES,
+ MATCH_DISABLED_COMPONENTS,
+ MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+ MATCH_ALL,
+ MATCH_DEFAULT_ONLY,
+ MATCH_ENCRYPTION_AWARE,
+ MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+ MATCH_ENCRYPTION_UNAWARE,
+ MATCH_SYSTEM_ONLY,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ComponentInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ GET_SHARED_LIBRARY_FILES,
+ GET_RESOLVED_FILTER,
+ MATCH_UNINSTALLED_PACKAGES,
+ MATCH_DISABLED_COMPONENTS,
+ MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+ MATCH_ALL,
+ MATCH_DEFAULT_ONLY,
+ MATCH_ENCRYPTION_AWARE,
+ MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+ MATCH_ENCRYPTION_UNAWARE,
+ MATCH_SYSTEM_ONLY,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResolveInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PermissionInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PermissionGroupInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InstrumentationInfoFlags {}
+
+ /**
* {@link PackageInfo} flag: return information about
* activities in the package in {@link PackageInfo#activities}.
*/
@@ -161,9 +265,15 @@ public abstract class PackageManager {
public static final int GET_GIDS = 0x00000100;
/**
+ * @deprecated replaced with {@link #MATCH_DISABLED_COMPONENTS}
+ */
+ @Deprecated
+ public static final int GET_DISABLED_COMPONENTS = 0x00000200;
+
+ /**
* {@link PackageInfo} flag: include disabled components in the returned info.
*/
- public static final int GET_DISABLED_COMPONENTS = 0x00000200;
+ public static final int MATCH_DISABLED_COMPONENTS = 0x00000200;
/**
* {@link ApplicationInfo} flag: return the
@@ -190,6 +300,12 @@ public abstract class PackageManager {
public static final int GET_PERMISSIONS = 0x00001000;
/**
+ * @deprecated replaced with {@link #MATCH_UNINSTALLED_PACKAGES}
+ */
+ @Deprecated
+ public static final int GET_UNINSTALLED_PACKAGES = 0x00002000;
+
+ /**
* Flag parameter to retrieve some information about all applications (even
* uninstalled ones) which have data directories. This state could have
* resulted if applications have been deleted with flag
@@ -199,7 +315,7 @@ public abstract class PackageManager {
* Note: this flag may cause less information about currently installed
* applications to be returned.
*/
- public static final int GET_UNINSTALLED_PACKAGES = 0x00002000;
+ public static final int MATCH_UNINSTALLED_PACKAGES = 0x00002000;
/**
* {@link PackageInfo} flag: return information about
@@ -211,12 +327,18 @@ public abstract class PackageManager {
public static final int GET_CONFIGURATIONS = 0x00004000;
/**
+ * @deprecated replaced with {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}.
+ */
+ @Deprecated
+ public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
+
+ /**
* {@link PackageInfo} flag: include disabled components which are in
* that state only because of {@link #COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED}
* in the returned info. Note that if you set this flag, applications
* that are in this disabled state will be reported as enabled.
*/
- public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
+ public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
/**
* Resolution and querying flag: if set, only filters that support the
@@ -227,48 +349,55 @@ public abstract class PackageManager {
public static final int MATCH_DEFAULT_ONLY = 0x00010000;
/**
- * Querying flag: if set and if the platform is doing any filtering of the results, then
- * the filtering will not happen. This is a synonym for saying that all results should
- * be returned.
+ * Querying flag: if set and if the platform is doing any filtering of the
+ * results, then the filtering will not happen. This is a synonym for saying
+ * that all results should be returned.
+ * <p>
+ * <em>This flag should be used with extreme care.</em>
*/
public static final int MATCH_ALL = 0x00020000;
/**
- * {@link PackageInfo} flag: include only components which are encryption
- * unaware in the returned info, regardless of the current user state.
+ * Querying flag: include only components which are encryption unaware in
+ * the returned info, regardless of the current user state.
*/
- public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 0x00040000;
+ public static final int MATCH_ENCRYPTION_UNAWARE = 0x00040000;
/**
- * {@link PackageInfo} flag: include only components which are encryption
- * aware in the returned info, regardless of the current user state.
+ * Querying flag: include only components which are encryption aware in the
+ * returned info, regardless of the current user state.
*/
- public static final int MATCH_ENCRYPTION_AWARE_ONLY = 0x00080000;
+ public static final int MATCH_ENCRYPTION_AWARE = 0x00080000;
/**
- * {@link PackageInfo} flag: include both encryption aware and unaware
- * components in the returned info, regardless of the current user state.
+ * Querying flag: include both encryption aware and unaware components in
+ * the returned info, regardless of the current user state.
*/
- public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = MATCH_ENCRYPTION_AWARE_ONLY
- | MATCH_ENCRYPTION_UNAWARE_ONLY;
+ public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = MATCH_ENCRYPTION_AWARE
+ | MATCH_ENCRYPTION_UNAWARE;
/**
- * {@link PackageInfo} flag: include only components from applications that
- * are marked with {@link ApplicationInfo#FLAG_SYSTEM}.
- *
- * @hide
+ * Querying flag: include only components from applications that are marked
+ * with {@link ApplicationInfo#FLAG_SYSTEM}.
*/
public static final int MATCH_SYSTEM_ONLY = 0x00100000;
/**
- * {@link PackageInfo} flag: use the default encryption matching behavior
- * based on user state. Internal flag used to indicate that a system
- * component has done their homework and verified their encryption-aware
- * behavior.
+ * Internal flag used to indicate that a system component has done their
+ * homework and verified that they correctly handle packages and components
+ * that come and go over time. In particular:
+ * <ul>
+ * <li>Apps installed on external storage, which will appear to be
+ * uninstalled while the the device is ejected.
+ * <li>Apps with encryption unaware components, which will appear to not
+ * exist while the device is locked.
+ * </ul>
*
+ * @see #MATCH_UNINSTALLED_PACKAGES
+ * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
* @hide
*/
- public static final int MATCH_ENCRYPTION_DEFAULT = 0x10000000;
+ public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000;
/**
* Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
@@ -1819,7 +1948,6 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: This device supports ethernet.
- * @hide
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_ETHERNET = "android.hardware.ethernet";
@@ -2131,7 +2259,7 @@ public abstract class PackageManager {
* @see #GET_SIGNATURES
* @see #GET_UNINSTALLED_PACKAGES
*/
- public abstract PackageInfo getPackageInfo(String packageName, int flags)
+ public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags)
throws NameNotFoundException;
/**
@@ -2171,8 +2299,8 @@ public abstract class PackageManager {
* @see #GET_UNINSTALLED_PACKAGES
*/
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
- public abstract PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
- throws NameNotFoundException;
+ public abstract PackageInfo getPackageInfoAsUser(String packageName,
+ @PackageInfoFlags int flags, int userId) throws NameNotFoundException;
/**
* Map from the current package names in use on the device to whatever
@@ -2253,7 +2381,7 @@ public abstract class PackageManager {
*
* @return Returns an integer uid who owns the given package name.
*/
- public abstract int getPackageUid(String packageName, int userHandle)
+ public abstract int getPackageUidAsUser(String packageName, int userId)
throws NameNotFoundException;
/**
@@ -2270,7 +2398,7 @@ public abstract class PackageManager {
* @return Returns a {@link PermissionInfo} containing information about the
* permission.
*/
- public abstract PermissionInfo getPermissionInfo(String name, int flags)
+ public abstract PermissionInfo getPermissionInfo(String name, @PermissionInfoFlags int flags)
throws NameNotFoundException;
/**
@@ -2289,7 +2417,7 @@ public abstract class PackageManager {
* about all of the permissions in the given group.
*/
public abstract List<PermissionInfo> queryPermissionsByGroup(String group,
- int flags) throws NameNotFoundException;
+ @PermissionInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular group of
@@ -2307,7 +2435,7 @@ public abstract class PackageManager {
* about the permission.
*/
public abstract PermissionGroupInfo getPermissionGroupInfo(String name,
- int flags) throws NameNotFoundException;
+ @PermissionGroupInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the known permission groups in the system.
@@ -2318,7 +2446,8 @@ public abstract class PackageManager {
* @return Returns a list of {@link PermissionGroupInfo} containing
* information about all of the known permission groups.
*/
- public abstract List<PermissionGroupInfo> getAllPermissionGroups(int flags);
+ public abstract List<PermissionGroupInfo> getAllPermissionGroups(
+ @PermissionGroupInfoFlags int flags);
/**
* Retrieve all of the information we know about a particular
@@ -2348,7 +2477,7 @@ public abstract class PackageManager {
* @see #GET_UNINSTALLED_PACKAGES
*/
public abstract ApplicationInfo getApplicationInfo(String packageName,
- int flags) throws NameNotFoundException;
+ @ApplicationInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular activity
@@ -2371,7 +2500,7 @@ public abstract class PackageManager {
* @see #GET_SHARED_LIBRARY_FILES
*/
public abstract ActivityInfo getActivityInfo(ComponentName component,
- int flags) throws NameNotFoundException;
+ @ComponentInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular receiver
@@ -2394,7 +2523,7 @@ public abstract class PackageManager {
* @see #GET_SHARED_LIBRARY_FILES
*/
public abstract ActivityInfo getReceiverInfo(ComponentName component,
- int flags) throws NameNotFoundException;
+ @ComponentInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular service
@@ -2416,7 +2545,7 @@ public abstract class PackageManager {
* @see #GET_SHARED_LIBRARY_FILES
*/
public abstract ServiceInfo getServiceInfo(ComponentName component,
- int flags) throws NameNotFoundException;
+ @ComponentInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular content
@@ -2438,7 +2567,7 @@ public abstract class PackageManager {
* @see #GET_SHARED_LIBRARY_FILES
*/
public abstract ProviderInfo getProviderInfo(ComponentName component,
- int flags) throws NameNotFoundException;
+ @ComponentInfoFlags int flags) throws NameNotFoundException;
/**
* Return a List of all packages that are installed
@@ -2474,7 +2603,7 @@ public abstract class PackageManager {
* @see #GET_SIGNATURES
* @see #GET_UNINSTALLED_PACKAGES
*/
- public abstract List<PackageInfo> getInstalledPackages(int flags);
+ public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags);
/**
* Return a List of all installed packages that are currently
@@ -2507,7 +2636,7 @@ public abstract class PackageManager {
* @see #GET_UNINSTALLED_PACKAGES
*/
public abstract List<PackageInfo> getPackagesHoldingPermissions(
- String[] permissions, int flags);
+ String[] permissions, @PackageInfoFlags int flags);
/**
* Return a List of all packages that are installed on the device, for a specific user.
@@ -2546,7 +2675,8 @@ public abstract class PackageManager {
*
* @hide
*/
- public abstract List<PackageInfo> getInstalledPackages(int flags, int userId);
+ public abstract List<PackageInfo> getInstalledPackagesAsUser(@PackageInfoFlags int flags,
+ int userId);
/**
* Check whether a particular package has been granted a particular
@@ -2886,7 +3016,7 @@ public abstract class PackageManager {
* @see #GET_SHARED_LIBRARY_FILES
* @see #GET_UNINSTALLED_PACKAGES
*/
- public abstract List<ApplicationInfo> getInstalledApplications(int flags);
+ public abstract List<ApplicationInfo> getInstalledApplications(@ApplicationInfoFlags int flags);
/**
* Gets the ephemeral applications the user recently used. Requires
@@ -3021,7 +3151,7 @@ public abstract class PackageManager {
* @see #GET_INTENT_FILTERS
* @see #GET_RESOLVED_FILTER
*/
- public abstract ResolveInfo resolveActivity(Intent intent, int flags);
+ public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);
/**
* Determine the best action to perform for a given Intent for a given user. This
@@ -3054,7 +3184,8 @@ public abstract class PackageManager {
*
* @hide
*/
- public abstract ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId);
+ public abstract ResolveInfo resolveActivityAsUser(Intent intent, @ResolveInfoFlags int flags,
+ int userId);
/**
* Retrieve all activities that can be performed for the given intent.
@@ -3077,7 +3208,7 @@ public abstract class PackageManager {
* @see #GET_RESOLVED_FILTER
*/
public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
- int flags);
+ @ResolveInfoFlags int flags);
/**
* Retrieve all activities that can be performed for the given intent, for a specific user.
@@ -3101,8 +3232,7 @@ public abstract class PackageManager {
* @hide
*/
public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
- int flags, int userId);
-
+ @ResolveInfoFlags int flags, int userId);
/**
* Retrieve a set of activities that should be presented to the user as
@@ -3134,7 +3264,7 @@ public abstract class PackageManager {
* @see #GET_RESOLVED_FILTER
*/
public abstract List<ResolveInfo> queryIntentActivityOptions(
- ComponentName caller, Intent[] specifics, Intent intent, int flags);
+ ComponentName caller, Intent[] specifics, Intent intent, @ResolveInfoFlags int flags);
/**
* Retrieve all receivers that can handle a broadcast of the given intent.
@@ -3151,7 +3281,7 @@ public abstract class PackageManager {
* @see #GET_RESOLVED_FILTER
*/
public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
- int flags);
+ @ResolveInfoFlags int flags);
/**
* Retrieve all receivers that can handle a broadcast of the given intent, for a specific
@@ -3170,8 +3300,8 @@ public abstract class PackageManager {
* @see #GET_RESOLVED_FILTER
* @hide
*/
- public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
- int flags, int userId);
+ public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+ @ResolveInfoFlags int flags, int userId);
/**
* Determine the best service to handle for a given Intent.
@@ -3187,7 +3317,7 @@ public abstract class PackageManager {
* @see #GET_INTENT_FILTERS
* @see #GET_RESOLVED_FILTER
*/
- public abstract ResolveInfo resolveService(Intent intent, int flags);
+ public abstract ResolveInfo resolveService(Intent intent, @ResolveInfoFlags int flags);
/**
* Retrieve all services that can match the given intent.
@@ -3205,7 +3335,7 @@ public abstract class PackageManager {
* @see #GET_RESOLVED_FILTER
*/
public abstract List<ResolveInfo> queryIntentServices(Intent intent,
- int flags);
+ @ResolveInfoFlags int flags);
/**
* Retrieve all services that can match the given intent for a given user.
@@ -3226,11 +3356,11 @@ public abstract class PackageManager {
* @hide
*/
public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent,
- int flags, int userId);
+ @ResolveInfoFlags int flags, int userId);
/** {@hide} */
public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
- Intent intent, int flags, int userId);
+ Intent intent, @ResolveInfoFlags int flags, int userId);
/**
* Retrieve all providers that can match the given intent.
@@ -3244,7 +3374,8 @@ public abstract class PackageManager {
* @see #GET_INTENT_FILTERS
* @see #GET_RESOLVED_FILTER
*/
- public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags);
+ public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent,
+ @ResolveInfoFlags int flags);
/**
* Find a single content provider by its base path name.
@@ -3256,7 +3387,7 @@ public abstract class PackageManager {
* else null.
*/
public abstract ProviderInfo resolveContentProvider(String name,
- int flags);
+ @ComponentInfoFlags int flags);
/**
* Find a single content provider by its base path name.
@@ -3269,7 +3400,8 @@ public abstract class PackageManager {
* else null.
* @hide
*/
- public abstract ProviderInfo resolveContentProviderAsUser(String name, int flags, int userId);
+ public abstract ProviderInfo resolveContentProviderAsUser(String name,
+ @ComponentInfoFlags int flags, int userId);
/**
* Retrieve content provider information.
@@ -3290,7 +3422,7 @@ public abstract class PackageManager {
* <em>If there are no matching providers, null is returned.</em>
*/
public abstract List<ProviderInfo> queryContentProviders(
- String processName, int uid, int flags);
+ String processName, int uid, @ComponentInfoFlags int flags);
/**
* Retrieve all of the information we know about a particular
@@ -3307,8 +3439,8 @@ public abstract class PackageManager {
* @return InstrumentationInfo containing information about the
* instrumentation.
*/
- public abstract InstrumentationInfo getInstrumentationInfo(
- ComponentName className, int flags) throws NameNotFoundException;
+ public abstract InstrumentationInfo getInstrumentationInfo(ComponentName className,
+ @InstrumentationInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve information about available instrumentation code. May be used
@@ -3324,8 +3456,8 @@ public abstract class PackageManager {
* matching available Instrumentation. Returns an empty list if
* there is no instrumentation available for the given package.
*/
- public abstract List<InstrumentationInfo> queryInstrumentation(
- String targetPackage, int flags);
+ public abstract List<InstrumentationInfo> queryInstrumentation(String targetPackage,
+ @InstrumentationInfoFlags int flags);
/**
* Retrieve an image from a package. This is a low-level API used by
@@ -3761,14 +3893,13 @@ public abstract class PackageManager {
* @see #GET_SIGNATURES
*
*/
- public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
+ public PackageInfo getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags) {
final PackageParser parser = new PackageParser();
final File apkFile = new File(archiveFilePath);
try {
PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
if ((flags & GET_SIGNATURES) != 0) {
parser.collectCertificates(pkg, 0);
- parser.collectManifestDigest(pkg);
}
PackageUserState state = new PackageUserState();
return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
@@ -3828,14 +3959,12 @@ public abstract class PackageManager {
* @param verificationURI The location of the supplementary verification
* file. This can be a 'file:' or a 'content:' URI. May be
* {@code null}.
- * @param manifestDigest an object that holds the digest of the package
- * which can be used to verify ownership. May be {@code null}.
* @param encryptionParams if the package to be installed is encrypted,
* these parameters describing the encryption and authentication
* used. May be {@code null}.
* @hide
* @deprecated Use {@link #installPackageWithVerification(Uri,
- * PackageInstallObserver, int, String, Uri, ManifestDigest,
+ * PackageInstallObserver, int, String, Uri,
* ContainerEncryptionParams)} instead. This method will
* continue to be supported but the older observer interface
* will not get additional failure details.
@@ -3843,7 +3972,7 @@ public abstract class PackageManager {
// @SystemApi
public abstract void installPackageWithVerification(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
- Uri verificationURI, ManifestDigest manifestDigest,
+ Uri verificationURI,
ContainerEncryptionParams encryptionParams);
/**
@@ -3952,8 +4081,6 @@ public abstract class PackageManager {
* @param verificationURI The location of the supplementary verification
* file. This can be a 'file:' or a 'content:' URI. May be
* {@code null}.
- * @param manifestDigest an object that holds the digest of the package
- * which can be used to verify ownership. May be {@code null}.
* @param encryptionParams if the package to be installed is encrypted,
* these parameters describing the encryption and authentication
* used. May be {@code null}.
@@ -3961,7 +4088,7 @@ public abstract class PackageManager {
*/
public abstract void installPackageWithVerification(Uri packageURI,
PackageInstallObserver observer, int flags, String installerPackageName,
- Uri verificationURI, ManifestDigest manifestDigest,
+ Uri verificationURI,
ContainerEncryptionParams encryptionParams);
/**
@@ -4105,7 +4232,7 @@ public abstract class PackageManager {
*
* @hide
*/
- public abstract int getIntentVerificationStatus(String packageName, int userId);
+ public abstract int getIntentVerificationStatusAsUser(String packageName, int userId);
/**
* Allow to change the status of a Intent Verification status for all IntentFilter of an App.
@@ -4127,7 +4254,7 @@ public abstract class PackageManager {
*
* @hide
*/
- public abstract boolean updateIntentVerificationStatus(String packageName, int status,
+ public abstract boolean updateIntentVerificationStatusAsUser(String packageName, int status,
int userId);
/**
@@ -4168,7 +4295,8 @@ public abstract class PackageManager {
*
* @hide
*/
- public abstract String getDefaultBrowserPackageName(int userId);
+ @TestApi
+ public abstract String getDefaultBrowserPackageNameAsUser(int userId);
/**
* Set the default Browser package name for a specific user.
@@ -4182,7 +4310,7 @@ public abstract class PackageManager {
*
* @hide
*/
- public abstract boolean setDefaultBrowserPackageName(String packageName, int userId);
+ public abstract boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId);
/**
* Change the installer associated with a given package. There are limitations
@@ -4354,7 +4482,7 @@ public abstract class PackageManager {
* should have the {@link android.Manifest.permission#GET_PACKAGE_SIZE} permission.
*
* @param packageName The name of the package whose size information is to be retrieved
- * @param userHandle The user whose size information should be retrieved.
+ * @param userId The user whose size information should be retrieved.
* @param observer An observer callback to get notified when the operation
* is complete.
* {@link android.content.pm.IPackageStatsObserver#onGetStatsCompleted(PackageStats, boolean)}
@@ -4365,17 +4493,17 @@ public abstract class PackageManager {
*
* @hide
*/
- public abstract void getPackageSizeInfo(String packageName, int userHandle,
+ public abstract void getPackageSizeInfoAsUser(String packageName, int userId,
IPackageStatsObserver observer);
/**
- * Like {@link #getPackageSizeInfo(String, int, IPackageStatsObserver)}, but
+ * Like {@link #getPackageSizeInfoAsUser(String, int, IPackageStatsObserver)}, but
* returns the size for the calling user.
*
* @hide
*/
public void getPackageSizeInfo(String packageName, IPackageStatsObserver observer) {
- getPackageSizeInfo(packageName, UserHandle.myUserId(), observer);
+ getPackageSizeInfoAsUser(packageName, UserHandle.myUserId(), observer);
}
/**
@@ -4423,7 +4551,7 @@ public abstract class PackageManager {
* @see #GET_SERVICES
* @see #GET_SIGNATURES
*/
- public abstract List<PackageInfo> getPreferredPackages(int flags);
+ public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags);
/**
* @deprecated This is a protected API that should not have been available
@@ -4454,7 +4582,7 @@ public abstract class PackageManager {
to.
* @hide
*/
- public void addPreferredActivity(IntentFilter filter, int match,
+ public void addPreferredActivityAsUser(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, int userId) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f445cf8208b6..236cf64ae8ce 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1032,31 +1032,6 @@ public class PackageParser {
}
/**
- * Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
- * APK. If it successfully scanned the package and found the
- * {@code AndroidManifest.xml}, {@code true} is returned.
- */
- public void collectManifestDigest(Package pkg) throws PackageParserException {
- pkg.manifestDigest = null;
-
- // TODO: extend to gather digest for split APKs
- try {
- final StrictJarFile jarFile = new StrictJarFile(pkg.baseCodePath);
- try {
- final ZipEntry je = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
- if (je != null) {
- pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je));
- }
- } finally {
- jarFile.close();
- }
- } catch (IOException | RuntimeException e) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
- "Failed to collect manifest digest");
- }
- }
-
- /**
* Collect certificates from all the APKs described in the given package,
* populating {@link Package#mSignatures}. Also asserts that all APK
* contents are signed correctly and consistently.
@@ -3223,12 +3198,19 @@ public class PackageParser {
a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
}
- a.info.resizeable = sa.getBoolean(
- R.styleable.AndroidManifestActivity_resizeableActivity,
- owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N);
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
+ owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N)) {
+ a.info.flags |= ActivityInfo.FLAG_RESIZEABLE;
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+ }
+ }
- a.info.supportsPip = a.info.resizeable ? sa.getBoolean(
- R.styleable.AndroidManifestActivity_supportsPictureInPicture, false) : false;
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
+ a.info.flags |= ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+ }
a.info.screenOrientation = sa.getInt(
R.styleable.AndroidManifestActivity_screenOrientation,
@@ -4492,12 +4474,6 @@ public class PackageParser {
/* The required account type without which this application will not function */
public String mRequiredAccountType;
- /**
- * Digest suitable for comparing whether this package's manifest is the
- * same as another.
- */
- public ManifestDigest manifestDigest;
-
public String mOverlayTarget;
public int mOverlayPriority;
public boolean mTrustedOverlay;
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index cfb447334406..945858e6d3c6 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -24,6 +24,7 @@ import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -50,6 +51,10 @@ public class ParceledListSlice<T extends Parcelable> implements Parcelable {
private final List<T> mList;
+ public static <T extends Parcelable> ParceledListSlice<T> emptyList() {
+ return new ParceledListSlice<T>(Collections.<T> emptyList());
+ }
+
public ParceledListSlice(List<T> list) {
mList = list;
}
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index d5d300760c8a..c9be6edab424 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -172,7 +172,8 @@ public class ResolveInfo implements Parcelable {
*/
public boolean handleAllWebDataURI;
- private ComponentInfo getComponentInfo() {
+ /** {@hide} */
+ public ComponentInfo getComponentInfo() {
if (activityInfo != null) return activityInfo;
if (serviceInfo != null) return serviceInfo;
if (providerInfo != null) return providerInfo;
diff --git a/core/java/android/content/pm/VerificationParams.java b/core/java/android/content/pm/VerificationParams.java
index e5119b621ee5..f90d295b8478 100644
--- a/core/java/android/content/pm/VerificationParams.java
+++ b/core/java/android/content/pm/VerificationParams.java
@@ -16,7 +16,6 @@
package android.content.pm;
-import android.content.pm.ManifestDigest;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -51,12 +50,6 @@ public class VerificationParams implements Parcelable {
private int mInstallerUid;
/**
- * An object that holds the digest of the package which can be used to
- * verify ownership.
- */
- private final ManifestDigest mManifestDigest;
-
- /**
* Creates verification specifications for installing with application verification.
*
* @param verificationURI The location of the supplementary verification
@@ -67,16 +60,13 @@ public class VerificationParams implements Parcelable {
* May be {@code null}.
* @param originatingUid UID of the application that the install request originated
* from, or NO_UID if not present
- * @param manifestDigest an object that holds the digest of the package
- * which can be used to verify ownership. May be {@code null}.
*/
public VerificationParams(Uri verificationURI, Uri originatingURI, Uri referrer,
- int originatingUid, ManifestDigest manifestDigest) {
+ int originatingUid) {
mVerificationURI = verificationURI;
mOriginatingURI = originatingURI;
mReferrer = referrer;
mOriginatingUid = originatingUid;
- mManifestDigest = manifestDigest;
mInstallerUid = NO_UID;
}
@@ -97,10 +87,6 @@ public class VerificationParams implements Parcelable {
return mOriginatingUid;
}
- public ManifestDigest getManifestDigest() {
- return mManifestDigest;
- }
-
/** @return NO_UID when not set */
public int getInstallerUid() {
return mInstallerUid;
@@ -155,14 +141,6 @@ public class VerificationParams implements Parcelable {
return false;
}
- if (mManifestDigest == null) {
- if (other.mManifestDigest != null) {
- return false;
- }
- } else if (!mManifestDigest.equals(other.mManifestDigest)) {
- return false;
- }
-
if (mInstallerUid != other.mInstallerUid) {
return false;
}
@@ -178,8 +156,7 @@ public class VerificationParams implements Parcelable {
hash += 7 * (mOriginatingURI == null ? 1 : mOriginatingURI.hashCode());
hash += 11 * (mReferrer == null ? 1 : mReferrer.hashCode());
hash += 13 * mOriginatingUid;
- hash += 17 * (mManifestDigest == null ? 1 : mManifestDigest.hashCode());
- hash += 19 * mInstallerUid;
+ hash += 17 * mInstallerUid;
return hash;
}
@@ -196,8 +173,6 @@ public class VerificationParams implements Parcelable {
sb.append(mReferrer.toString());
sb.append(",mOriginatingUid=");
sb.append(mOriginatingUid);
- sb.append(",mManifestDigest=");
- sb.append(mManifestDigest.toString());
sb.append(",mInstallerUid=");
sb.append(mInstallerUid);
sb.append('}');
@@ -211,7 +186,6 @@ public class VerificationParams implements Parcelable {
dest.writeParcelable(mOriginatingURI, 0);
dest.writeParcelable(mReferrer, 0);
dest.writeInt(mOriginatingUid);
- dest.writeParcelable(mManifestDigest, 0);
dest.writeInt(mInstallerUid);
}
@@ -221,7 +195,6 @@ public class VerificationParams implements Parcelable {
mOriginatingURI = source.readParcelable(Uri.class.getClassLoader());
mReferrer = source.readParcelable(Uri.class.getClassLoader());
mOriginatingUid = source.readInt();
- mManifestDigest = source.readParcelable(ManifestDigest.class.getClassLoader());
mInstallerUid = source.readInt();
}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 7669053cc803..7b0b98d4389c 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -16,6 +16,11 @@
package android.content.res;
+import android.annotation.AnyRes;
+import android.annotation.ArrayRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.util.SparseArray;
@@ -142,80 +147,95 @@ public final class AssetManager implements AutoCloseable {
}
/**
- * Retrieve the string value associated with a particular resource
- * identifier for the current configuration / skin.
+ * Retrieves the string value associated with a particular resource
+ * identifier for the current configuration.
+ *
+ * @param resId the resource identifier to load
+ * @return the string value, or {@code null}
*/
- /*package*/ final CharSequence getResourceText(int ident) {
+ @Nullable
+ final CharSequence getResourceText(@StringRes int resId) {
synchronized (this) {
- TypedValue tmpValue = mValue;
- int block = loadResourceValue(ident, (short) 0, tmpValue, true);
- if (block >= 0) {
- if (tmpValue.type == TypedValue.TYPE_STRING) {
- return mStringBlocks[block].get(tmpValue.data);
- }
- return tmpValue.coerceToString();
+ final TypedValue outValue = mValue;
+ if (getResourceValue(resId, 0, outValue, true)) {
+ return outValue.coerceToString();
}
+ return null;
}
- return null;
}
/**
- * Retrieve the string value associated with a particular resource
- * identifier for the current configuration / skin.
+ * Retrieves the string value associated with a particular resource
+ * identifier for the current configuration.
+ *
+ * @param resId the resource identifier to load
+ * @param bagEntryId
+ * @return the string value, or {@code null}
*/
- /*package*/ final CharSequence getResourceBagText(int ident, int bagEntryId) {
+ @Nullable
+ final CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) {
synchronized (this) {
- TypedValue tmpValue = mValue;
- int block = loadResourceBagValue(ident, bagEntryId, tmpValue, true);
- if (block >= 0) {
- if (tmpValue.type == TypedValue.TYPE_STRING) {
- return mStringBlocks[block].get(tmpValue.data);
- }
- return tmpValue.coerceToString();
+ final TypedValue outValue = mValue;
+ final int block = loadResourceBagValue(resId, bagEntryId, outValue, true);
+ if (block < 0) {
+ return null;
}
+ if (outValue.type == TypedValue.TYPE_STRING) {
+ return mStringBlocks[block].get(outValue.data);
+ }
+ return outValue.coerceToString();
}
- return null;
}
/**
- * Retrieve the string array associated with a particular resource
- * identifier.
- * @param id Resource id of the string array
+ * Retrieves the string array associated with a particular resource
+ * identifier for the current configuration.
+ *
+ * @param resId the resource identifier of the string array
+ * @return the string array, or {@code null}
*/
- /*package*/ final String[] getResourceStringArray(final int id) {
- String[] retArray = getArrayStringResource(id);
- return retArray;
+ @Nullable
+ final String[] getResourceStringArray(@ArrayRes int resId) {
+ return getArrayStringResource(resId);
}
-
- /*package*/ final boolean getResourceValue(int ident,
- int density,
- TypedValue outValue,
- boolean resolveRefs)
- {
- int block = loadResourceValue(ident, (short) density, outValue, resolveRefs);
- if (block >= 0) {
- if (outValue.type != TypedValue.TYPE_STRING) {
- return true;
- }
+ /**
+ * Populates {@code outValue} with the data associated a particular
+ * resource identifier for the current configuration.
+ *
+ * @param resId the resource identifier to load
+ * @param densityDpi the density bucket for which to load the resource
+ * @param outValue the typed value in which to put the data
+ * @param resolveRefs {@code true} to resolve references, {@code false}
+ * to leave them unresolved
+ * @return {@code true} if the data was loaded into {@code outValue},
+ * {@code false} otherwise
+ */
+ final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
+ boolean resolveRefs) {
+ final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
+ if (block < 0) {
+ return false;
+ }
+ if (outValue.type == TypedValue.TYPE_STRING) {
outValue.string = mStringBlocks[block].get(outValue.data);
- return true;
}
- return false;
+ return true;
}
/**
* Retrieve the text array associated with a particular resource
* identifier.
- * @param id Resource id of the string array
+ *
+ * @param resId the resource id of the string array
*/
- /*package*/ final CharSequence[] getResourceTextArray(final int id) {
- int[] rawInfoArray = getArrayStringInfo(id);
- int rawInfoArrayLen = rawInfoArray.length;
+ final CharSequence[] getResourceTextArray(@ArrayRes int resId) {
+ final int[] rawInfoArray = getArrayStringInfo(resId);
+ final int rawInfoArrayLen = rawInfoArray.length;
final int infoArrayLen = rawInfoArrayLen / 2;
int block;
int index;
- CharSequence[] retArray = new CharSequence[infoArrayLen];
+ final CharSequence[] retArray = new CharSequence[infoArrayLen];
for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
block = rawInfoArray[i];
index = rawInfoArray[i + 1];
@@ -223,32 +243,45 @@ public final class AssetManager implements AutoCloseable {
}
return retArray;
}
-
- /*package*/ final boolean getThemeValue(long theme, int ident,
- TypedValue outValue, boolean resolveRefs) {
- int block = loadThemeAttributeValue(theme, ident, outValue, resolveRefs);
- if (block >= 0) {
- if (outValue.type != TypedValue.TYPE_STRING) {
- return true;
- }
- StringBlock[] blocks = mStringBlocks;
- if (blocks == null) {
- ensureStringBlocks();
- blocks = mStringBlocks;
- }
+
+ /**
+ * Populates {@code outValue} with the data associated with a particular
+ * resource identifier for the current configuration. Resolves theme
+ * attributes against the specified theme.
+ *
+ * @param theme the native pointer of the theme
+ * @param resId the resource identifier to load
+ * @param outValue the typed value in which to put the data
+ * @param resolveRefs {@code true} to resolve references, {@code false}
+ * to leave them unresolved
+ * @return {@code true} if the data was loaded into {@code outValue},
+ * {@code false} otherwise
+ */
+ final boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue,
+ boolean resolveRefs) {
+ final int block = loadThemeAttributeValue(theme, resId, outValue, resolveRefs);
+ if (block < 0) {
+ return false;
+ }
+ if (outValue.type == TypedValue.TYPE_STRING) {
+ final StringBlock[] blocks = ensureStringBlocks();
outValue.string = blocks[block].get(outValue.data);
- return true;
}
- return false;
+ return true;
}
- /*package*/ final void ensureStringBlocks() {
- if (mStringBlocks == null) {
- synchronized (this) {
- if (mStringBlocks == null) {
- makeStringBlocks(sSystem.mStringBlocks);
- }
+ /**
+ * Ensures the string blocks are loaded.
+ *
+ * @return the string blocks
+ */
+ @NonNull
+ final StringBlock[] ensureStringBlocks() {
+ synchronized (this) {
+ if (mStringBlocks == null) {
+ makeStringBlocks(sSystem.mStringBlocks);
}
+ return mStringBlocks;
}
}
@@ -698,6 +731,18 @@ public final class AssetManager implements AutoCloseable {
*/
public native final String[] getLocales();
+ /**
+ * Same as getLocales(), except that locales that are only provided by the system (i.e. those
+ * present in framework-res.apk or its overlays) will not be listed.
+ *
+ * For example, if the "system" assets support English, French, and German, and the additional
+ * assets support Cherokee and French, getLocales() would return
+ * [Cherokee, English, French, German], while getNonSystemLocales() would return
+ * [Cherokee, French].
+ * {@hide}
+ */
+ public native final String[] getNonSystemLocales();
+
/** {@hide} */
public native final Configuration[] getSizeConfigurations();
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 60c6e825e1be..7b56eebf34ac 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -151,8 +151,9 @@ public class Resources {
private boolean mPreloading;
+ // Cyclical cache used for recently-accessed XML files.
private int mLastCachedXmlBlockIndex = -1;
- private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
+ private final String[] mCachedXmlBlockFiles = new String[4];
private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
final AssetManager mAssets;
@@ -866,6 +867,11 @@ public class Resources {
try {
getValueForDensity(id, density, value, true);
+ // If the drawable's XML lives in our current density qualifier,
+ // it's okay to use a scaled version from the cache. Otherwise, we
+ // need to actually load the drawable from XML.
+ final boolean useCache = value.density == mMetrics.densityDpi;
+
/*
* Pretend the requested density is actually the display density. If
* the drawable returned is not the requested density, then force it
@@ -881,7 +887,7 @@ public class Resources {
}
}
- return loadDrawable(value, id, theme);
+ return loadDrawable(value, id, theme, useCache);
} finally {
releaseTempTypedValue(value);
}
@@ -1976,7 +1982,21 @@ public class Resources {
if (setLocalesToDefault || mResolvedLocale == null
|| (configChanges & Configuration.NATIVE_CONFIG_LOCALE) != 0) {
- mResolvedLocale = locales.getFirstMatch(mAssets.getLocales());
+ if (locales.size() == 1) {
+ // This is an optimization to avoid the JNI call(s) when the result of
+ // getFirstMatchWithEnglishSupported() does not depend on the supported locales.
+ mResolvedLocale = locales.getPrimary();
+ } else {
+ String[] supportedLocales = mAssets.getNonSystemLocales();
+ if (LocaleList.isPseudoLocalesOnly(supportedLocales)) {
+ // We fallback to all locales (including system locales) if there was no
+ // locale specifically supported by the assets. This is to properly support
+ // apps that only rely on the shared system assets and don't need assets of
+ // their own.
+ supportedLocales = mAssets.getLocales();
+ }
+ mResolvedLocale = locales.getFirstMatchWithEnglishSupported(supportedLocales);
+ }
}
mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
adjustLanguageTag(mResolvedLocale.toLanguageTag()),
@@ -2351,16 +2371,17 @@ public class Resources {
* tools.
*/
public final void flushLayoutCache() {
- synchronized (mCachedXmlBlockIds) {
- // First see if this block is in our cache.
- final int num = mCachedXmlBlockIds.length;
- for (int i=0; i<num; i++) {
- mCachedXmlBlockIds[i] = -0;
- XmlBlock oldBlock = mCachedXmlBlocks[i];
+ final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
+ final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+ synchronized (cachedXmlBlockFiles) {
+ final int num = cachedXmlBlockFiles.length;
+ for (int i = 0; i < num; i++) {
+ final XmlBlock oldBlock = cachedXmlBlocks[i];
if (oldBlock != null) {
oldBlock.close();
}
- mCachedXmlBlocks[i] = null;
+ cachedXmlBlockFiles[i] = null;
+ cachedXmlBlocks[i] = null;
}
}
}
@@ -2437,6 +2458,12 @@ public class Resources {
@Nullable
Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
+ return loadDrawable(value, id, theme, true);
+ }
+
+ @Nullable
+ Drawable loadDrawable(TypedValue value, int id, Theme theme, boolean useCache)
+ throws NotFoundException {
try {
if (TRACE_FOR_PRELOAD) {
// Log only framework resources
@@ -2463,16 +2490,17 @@ public class Resources {
}
// First, check whether we have a cached version of this drawable
- // that was inflated against the specified theme.
- if (!mPreloading) {
+ // that was inflated against the specified theme. Skip the cache if
+ // we're currently preloading or we're not using the cache.
+ if (!mPreloading && useCache) {
final Drawable cachedDrawable = caches.getInstance(key, theme);
if (cachedDrawable != null) {
return cachedDrawable;
}
}
- // Next, check preloaded drawables. These may contain unresolved theme
- // attributes.
+ // Next, check preloaded drawables. Preloaded drawables may contain
+ // unresolved theme attributes.
final ConstantState cs;
if (isColorDrawable) {
cs = sPreloadedColorDrawables.get(key);
@@ -2500,8 +2528,9 @@ public class Resources {
}
// If we were able to obtain a drawable, store it in the appropriate
- // cache: preload, not themed, null theme, or theme-specific.
- if (dr != null) {
+ // cache: preload, not themed, null theme, or theme-specific. Don't
+ // pollute the cache with drawables loaded from a foreign density.
+ if (dr != null && useCache) {
dr.setChangingConfigurations(value.changingConfigurations);
cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
}
@@ -2730,7 +2759,16 @@ public class Resources {
return csl;
}
- /*package*/ XmlResourceParser loadXmlResourceParser(int id, String type)
+ /**
+ * Loads an XML parser for the specified file.
+ *
+ * @param id the resource identifier for the file
+ * @param type the type of resource (used for logging)
+ * @return a parser for the specified XML file
+ * @throws NotFoundException if the file could not be loaded
+ */
+ @NonNull
+ XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type)
throws NotFoundException {
final TypedValue value = obtainTempTypedValue(id);
try {
@@ -2744,53 +2782,58 @@ public class Resources {
releaseTempTypedValue(value);
}
}
-
- /*package*/ XmlResourceParser loadXmlResourceParser(String file, int id,
- int assetCookie, String type) throws NotFoundException {
+
+ /**
+ * Loads an XML parser for the specified file.
+ *
+ * @param file the path for the XML file to parse
+ * @param id the resource identifier for the file
+ * @param assetCookie the asset cookie for the file
+ * @param type the type of resource (used for logging)
+ * @return a parser for the specified XML file
+ * @throws NotFoundException if the file could not be loaded
+ */
+ @NonNull
+ XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id,
+ int assetCookie, @NonNull String type) throws NotFoundException {
if (id != 0) {
try {
- // These may be compiled...
- synchronized (mCachedXmlBlockIds) {
+ final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
+ final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+ synchronized (cachedXmlBlockFiles) {
// First see if this block is in our cache.
- final int num = mCachedXmlBlockIds.length;
- for (int i=0; i<num; i++) {
- if (mCachedXmlBlockIds[i] == id) {
- //System.out.println("**** REUSING XML BLOCK! id="
- // + id + ", index=" + i);
- return mCachedXmlBlocks[i].newParser();
+ final int num = cachedXmlBlockFiles.length;
+ for (int i = 0; i < num; i++) {
+ if (cachedXmlBlockFiles[i] != null
+ && cachedXmlBlockFiles[i].equals(file)) {
+ return cachedXmlBlocks[i].newParser();
}
}
// Not in the cache, create a new block and put it at
// the next slot in the cache.
- XmlBlock block = mAssets.openXmlBlockAsset(
- assetCookie, file);
+ final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
if (block != null) {
- int pos = mLastCachedXmlBlockIndex+1;
- if (pos >= num) pos = 0;
+ final int pos = (mLastCachedXmlBlockIndex + 1) % num;
mLastCachedXmlBlockIndex = pos;
- XmlBlock oldBlock = mCachedXmlBlocks[pos];
+ final XmlBlock oldBlock = cachedXmlBlocks[pos];
if (oldBlock != null) {
oldBlock.close();
}
- mCachedXmlBlockIds[pos] = id;
- mCachedXmlBlocks[pos] = block;
- //System.out.println("**** CACHING NEW XML BLOCK! id="
- // + id + ", index=" + pos);
+ cachedXmlBlockFiles[pos] = file;
+ cachedXmlBlocks[pos] = block;
return block.newParser();
}
}
} catch (Exception e) {
- NotFoundException rnf = new NotFoundException(
- "File " + file + " from xml type " + type + " resource ID #0x"
- + Integer.toHexString(id));
+ final NotFoundException rnf = new NotFoundException("File " + file
+ + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
rnf.initCause(e);
throw rnf;
}
}
- throw new NotFoundException(
- "File " + file + " from xml type " + type + " resource ID #0x"
+ throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
+ Integer.toHexString(id));
}
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index ec76b8a6633e..a66ea49f2022 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -33,6 +33,7 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
/**
@@ -90,13 +91,18 @@ public final class NetworkScorerAppManager {
* @return the list of scorers, or the empty list if there are no valid scorers.
*/
public static Collection<NetworkScorerAppData> getAllValidScorers(Context context) {
- List<NetworkScorerAppData> scorers = new ArrayList<>();
+ // Network scorer apps can only run as the primary user so exit early if we're not the
+ // primary user.
+ if (UserHandle.getCallingUserId() != 0 /*USER_SYSTEM*/) {
+ return Collections.emptyList();
+ }
+ List<NetworkScorerAppData> scorers = new ArrayList<>();
PackageManager pm = context.getPackageManager();
// Only apps installed under the primary user of the device can be scorers.
// TODO: http://b/23422763
List<ResolveInfo> receivers =
- pm.queryBroadcastReceivers(SCORE_INTENT, 0 /* flags */, UserHandle.USER_SYSTEM);
+ pm.queryBroadcastReceiversAsUser(SCORE_INTENT, 0 /* flags */, UserHandle.USER_SYSTEM);
for (ResolveInfo receiver : receivers) {
// This field is a misnomer, see android.content.pm.ResolveInfo#activityInfo
final ActivityInfo receiverInfo = receiver.activityInfo;
@@ -105,8 +111,9 @@ public final class NetworkScorerAppManager {
continue;
}
if (!permission.BROADCAST_NETWORK_PRIVILEGED.equals(receiverInfo.permission)) {
- // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which means
- // anyone could trigger network scoring and flood the framework with score requests.
+ // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which
+ // means anyone could trigger network scoring and flood the framework with score
+ // requests.
continue;
}
if (pm.checkPermission(permission.SCORE_NETWORKS, receiverInfo.packageName) !=
@@ -128,8 +135,8 @@ public final class NetworkScorerAppManager {
}
}
- // NOTE: loadLabel will attempt to load the receiver's label and fall back to the app
- // label if none is present.
+ // NOTE: loadLabel will attempt to load the receiver's label and fall back to the
+ // app label if none is present.
scorers.add(new NetworkScorerAppData(receiverInfo.packageName,
receiverInfo.applicationInfo.uid, receiverInfo.loadLabel(pm),
configurationActivityClassName));
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index d619c0a8e117..c7d4c65d99c0 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -371,40 +371,44 @@ public final class NfcActivityManager extends IAppCallback.Stub
flags = state.flags;
activity = state.activity;
}
-
- // Make callbacks without lock
- if (ndefCallback != null) {
- message = ndefCallback.createNdefMessage(event);
- }
- if (urisCallback != null) {
- uris = urisCallback.createBeamUris(event);
- if (uris != null) {
- ArrayList<Uri> validUris = new ArrayList<Uri>();
- for (Uri uri : uris) {
- if (uri == null) {
- Log.e(TAG, "Uri not allowed to be null.");
- continue;
- }
- String scheme = uri.getScheme();
- if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
- !scheme.equalsIgnoreCase("content"))) {
- Log.e(TAG, "Uri needs to have " +
- "either scheme file or scheme content");
- continue;
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ // Make callbacks without lock
+ if (ndefCallback != null) {
+ message = ndefCallback.createNdefMessage(event);
+ }
+ if (urisCallback != null) {
+ uris = urisCallback.createBeamUris(event);
+ if (uris != null) {
+ ArrayList<Uri> validUris = new ArrayList<Uri>();
+ for (Uri uri : uris) {
+ if (uri == null) {
+ Log.e(TAG, "Uri not allowed to be null.");
+ continue;
+ }
+ String scheme = uri.getScheme();
+ if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
+ !scheme.equalsIgnoreCase("content"))) {
+ Log.e(TAG, "Uri needs to have " +
+ "either scheme file or scheme content");
+ continue;
+ }
+ uri = ContentProvider.maybeAddUserId(uri, UserHandle.myUserId());
+ validUris.add(uri);
}
- uri = ContentProvider.maybeAddUserId(uri, UserHandle.myUserId());
- validUris.add(uri);
- }
- uris = validUris.toArray(new Uri[validUris.size()]);
+ uris = validUris.toArray(new Uri[validUris.size()]);
+ }
}
- }
- if (uris != null && uris.length > 0) {
- for (Uri uri : uris) {
- // Grant the NFC process permission to read these URIs
- activity.grantUriPermission("com.android.nfc", uri,
- Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ if (uris != null && uris.length > 0) {
+ for (Uri uri : uris) {
+ // Grant the NFC process permission to read these URIs
+ activity.grantUriPermission("com.android.nfc", uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
return new BeamShareData(message, uris, new UserHandle(UserHandle.myUserId()), flags);
}
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index f946ca7ed415..2498bff64d98 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import java.io.PrintWriter;
@@ -161,6 +162,7 @@ public final class UserHandle implements Parcelable {
* Returns the app id (or base uid) for a given uid, stripping out the user id from it.
* @hide
*/
+ @TestApi
public static int getAppId(int uid) {
return uid % PER_USER_RANGE;
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 16696af950bc..037916a94e5f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -57,6 +57,10 @@ public class UserManager {
* Authenticator.
* The default value is <code>false</code>.
*
+ * <p>From {@link android.os.Build.VERSION_CODES#N} a profile or device owner app can still
+ * use {@link android.accounts.AccountManager} APIs to add or remove accounts when account
+ * management is disallowed.
+ *
* <p/>Key for user restrictions.
* <p/>Type: Boolean
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index 8fa7ab90ebad..9a80e375ceb2 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -16,6 +16,7 @@
package android.print;
+import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.print.IPrinterDiscoveryObserver;
import android.print.IPrintDocumentAdapter;
@@ -53,6 +54,19 @@ interface IPrintManager {
void stopPrinterDiscovery(in IPrinterDiscoveryObserver observer, int userId);
void validatePrinters(in List<PrinterId> printerIds, int userId);
void startPrinterStateTracking(in PrinterId printerId, int userId);
+
+ /**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @param userId the id of the user requesting the printer
+ * @return the custom icon to be used for the printer or null if the icon is
+ * not yet available
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ Icon getCustomPrinterIcon(in PrinterId printerId, int userId);
+
void stopPrinterStateTracking(in PrinterId printerId, int userId);
void destroyPrinterDiscoverySession(in IPrinterDiscoveryObserver observer,
int userId);
diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl
index b7cfbea43646..c3625b8fb029 100644
--- a/core/java/android/print/IPrintSpooler.aidl
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -17,9 +17,11 @@
package android.print;
import android.content.ComponentName;
+import android.graphics.drawable.Icon;
import android.os.ParcelFileDescriptor;
import android.print.IPrintSpoolerClient;
import android.print.IPrintSpoolerCallbacks;
+import android.print.PrinterId;
import android.print.PrinterInfo;
import android.print.PrintAttributes;
import android.print.PrintJobId;
@@ -58,6 +60,39 @@ oneway interface IPrintSpooler {
*/
void setStatus(in PrintJobId printJobId, in CharSequence status);
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ * @param callbacks the callback to call once icon is stored in case
+ * @param sequence the sequence number of the call
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ void onCustomPrinterIconLoaded(in PrinterId printerId, in Icon icon,
+ in IPrintSpoolerCallbacks callbacks, in int sequence);
+
+ /**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @param callbacks the callback to call once icon is retrieved
+ * @param sequence the sequence number of the call
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ void getCustomPrinterIcon(in PrinterId printerId,
+ in IPrintSpoolerCallbacks callbacks, in int sequence);
+
+ /**
+ * Clear all state from the custom printer icon cache.
+ *
+ * @param callbacks the callback to call once cache is cleared
+ * @param sequence the sequence number of the call
+ */
+ void clearCustomPrinterIconCache(in IPrintSpoolerCallbacks callbacks,
+ in int sequence);
+
void setPrintJobTag(in PrintJobId printJobId, String tag, IPrintSpoolerCallbacks callback,
int sequence);
void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
diff --git a/core/java/android/print/IPrintSpoolerCallbacks.aidl b/core/java/android/print/IPrintSpoolerCallbacks.aidl
index 45c5332965da..23d706a1cd1b 100644
--- a/core/java/android/print/IPrintSpoolerCallbacks.aidl
+++ b/core/java/android/print/IPrintSpoolerCallbacks.aidl
@@ -16,7 +16,9 @@
package android.print;
+import android.graphics.drawable.Icon;
import android.print.PrintJobInfo;
+import android.print.PrinterId;
import java.util.List;
/**
@@ -32,4 +34,27 @@ oneway interface IPrintSpoolerCallbacks {
void onSetPrintJobStateResult(boolean success, int sequence);
void onSetPrintJobTagResult(boolean success, int sequence);
void onGetPrintJobInfoResult(in PrintJobInfo printJob, int sequence);
+
+ /**
+ * Deliver the result of a request of a custom printer icon.
+ *
+ * @param icon the icon that was retrieved, or null if no icon could be
+ * found
+ * @param sequence the sequence number of the call to get the icon
+ */
+ void onGetCustomPrinterIconResult(in Icon icon, int sequence);
+
+ /**
+ * Declare that the print spooler cached a custom printer icon.
+ *
+ * @param sequence the sequence number of the call to cache the icon
+ */
+ void onCustomPrinterIconCached(int sequence);
+
+ /**
+ * Declare that the custom printer icon cache was cleared.
+ *
+ * @param sequence the sequence number of the call to clear the cache
+ */
+ void customPrinterIconCacheCleared(int sequence);
}
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
index 8bc157a9fcad..57c7718c3370 100644
--- a/core/java/android/print/PageRange.java
+++ b/core/java/android/print/PageRange.java
@@ -16,6 +16,8 @@
package android.print;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
@@ -42,7 +44,7 @@ public final class PageRange implements Parcelable {
* @throws IllegalArgumentException If start is less than zero or end
* is less than zero or start greater than end.
*/
- public PageRange(int start, int end) {
+ public PageRange(@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
if (start < 0) {
throw new IllegalArgumentException("start cannot be less than zero.");
}
@@ -56,7 +58,7 @@ public final class PageRange implements Parcelable {
mEnd = end;
}
- private PageRange (Parcel parcel) {
+ private PageRange(@NonNull Parcel parcel) {
this(parcel.readInt(), parcel.readInt());
}
@@ -65,7 +67,7 @@ public final class PageRange implements Parcelable {
*
* @return The start page index.
*/
- public int getStart() {
+ public @IntRange(from = 0) int getStart() {
return mStart;
}
@@ -74,7 +76,7 @@ public final class PageRange implements Parcelable {
*
* @return The end page index.
*/
- public int getEnd() {
+ public @IntRange(from = 0) int getEnd() {
return mEnd;
}
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index 2afbb99b3a26..8892e3430fe4 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -16,6 +16,10 @@
package android.print;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources.NotFoundException;
@@ -27,6 +31,8 @@ import android.util.Log;
import com.android.internal.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Map;
/**
@@ -37,6 +43,13 @@ import java.util.Map;
* 10 mills (thousand of an inch) on all sides, and be black and white.
*/
public final class PrintAttributes implements Parcelable {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ COLOR_MODE_MONOCHROME, COLOR_MODE_COLOR
+ })
+ public @interface ColorMode {
+ }
/** Color mode: Monochrome color scheme, for example one color is used. */
public static final int COLOR_MODE_MONOCHROME = 1 << 0;
/** Color mode: Color color scheme, for example many colors are used. */
@@ -45,6 +58,13 @@ public final class PrintAttributes implements Parcelable {
private static final int VALID_COLOR_MODES =
COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ DUPLEX_MODE_NONE, DUPLEX_MODE_LONG_EDGE, DUPLEX_MODE_SHORT_EDGE
+ })
+ public @interface DuplexMode {
+ }
/** Duplex mode: No duplexing. */
public static final int DUPLEX_MODE_NONE = 1 << 0;
/** Duplex mode: Pages are turned sideways along the long edge - like a book. */
@@ -66,7 +86,7 @@ public final class PrintAttributes implements Parcelable {
/* hide constructor */
}
- private PrintAttributes(Parcel parcel) {
+ private PrintAttributes(@NonNull Parcel parcel) {
mMediaSize = (parcel.readInt() == 1) ? MediaSize.createFromParcel(parcel) : null;
mResolution = (parcel.readInt() == 1) ? Resolution.createFromParcel(parcel) : null;
mMinMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
@@ -79,7 +99,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The media size or <code>null</code> if not set.
*/
- public MediaSize getMediaSize() {
+ public @Nullable MediaSize getMediaSize() {
return mMediaSize;
}
@@ -99,7 +119,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The resolution or <code>null</code> if not set.
*/
- public Resolution getResolution() {
+ public @Nullable Resolution getResolution() {
return mResolution;
}
@@ -127,7 +147,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The margins or <code>null</code> if not set.
*/
- public Margins getMinMargins() {
+ public @Nullable Margins getMinMargins() {
return mMinMargins;
}
@@ -158,7 +178,7 @@ public final class PrintAttributes implements Parcelable {
* @see #COLOR_MODE_COLOR
* @see #COLOR_MODE_MONOCHROME
*/
- public int getColorMode() {
+ public @ColorMode int getColorMode() {
return mColorMode;
}
@@ -199,7 +219,7 @@ public final class PrintAttributes implements Parcelable {
* @see #DUPLEX_MODE_LONG_EDGE
* @see #DUPLEX_MODE_SHORT_EDGE
*/
- public int getDuplexMode() {
+ public @DuplexMode int getDuplexMode() {
return mDuplexMode;
}
@@ -828,7 +848,8 @@ public final class PrintAttributes implements Parcelable {
* or the widthMils is less than or equal to zero or the heightMils is less
* than or equal to zero.
*/
- public MediaSize(String id, String label, int widthMils, int heightMils) {
+ public MediaSize(@NonNull String id, @NonNull String label,
+ @IntRange(from = 1) int widthMils, @IntRange(from = 1) int heightMils) {
if (TextUtils.isEmpty(id)) {
throw new IllegalArgumentException("id cannot be empty.");
}
@@ -872,7 +893,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The unique media size id.
*/
- public String getId() {
+ public @NonNull String getId() {
return mId;
}
@@ -882,7 +903,7 @@ public final class PrintAttributes implements Parcelable {
* @param packageManager The package manager for loading the label.
* @return The human readable label.
*/
- public String getLabel(PackageManager packageManager) {
+ public @NonNull String getLabel(@NonNull PackageManager packageManager) {
if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
try {
return packageManager.getResourcesForApplication(
@@ -903,7 +924,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The media width.
*/
- public int getWidthMils() {
+ public @IntRange(from = 1) int getWidthMils() {
return mWidthMils;
}
@@ -912,7 +933,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The media height.
*/
- public int getHeightMils() {
+ public @IntRange(from = 1) int getHeightMils() {
return mHeightMils;
}
@@ -934,7 +955,7 @@ public final class PrintAttributes implements Parcelable {
* @return New instance in landscape orientation if this one
* is in landscape, otherwise this instance.
*/
- public MediaSize asPortrait() {
+ public @NonNull MediaSize asPortrait() {
if (isPortrait()) {
return this;
}
@@ -951,7 +972,7 @@ public final class PrintAttributes implements Parcelable {
* @return New instance in landscape orientation if this one
* is in portrait, otherwise this instance.
*/
- public MediaSize asLandscape() {
+ public @NonNull MediaSize asLandscape() {
if (!isPortrait()) {
return this;
}
@@ -1063,7 +1084,8 @@ public final class PrintAttributes implements Parcelable {
* or the horizontalDpi is less than or equal to zero or the verticalDpi is
* less than or equal to zero.
*/
- public Resolution(String id, String label, int horizontalDpi, int verticalDpi) {
+ public Resolution(@NonNull String id, @NonNull String label,
+ @IntRange(from = 1) int horizontalDpi, @IntRange(from = 1) int verticalDpi) {
if (TextUtils.isEmpty(id)) {
throw new IllegalArgumentException("id cannot be empty.");
}
@@ -1094,7 +1116,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The unique resolution id.
*/
- public String getId() {
+ public @NonNull String getId() {
return mId;
}
@@ -1103,7 +1125,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The human readable label.
*/
- public String getLabel() {
+ public @NonNull String getLabel() {
return mLabel;
}
@@ -1112,7 +1134,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The horizontal resolution.
*/
- public int getHorizontalDpi() {
+ public @IntRange(from = 1) int getHorizontalDpi() {
return mHorizontalDpi;
}
@@ -1121,7 +1143,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The vertical resolution.
*/
- public int getVerticalDpi() {
+ public @IntRange(from = 1) int getVerticalDpi() {
return mVerticalDpi;
}
@@ -1204,7 +1226,8 @@ public final class PrintAttributes implements Parcelable {
* @param rightMils The right margin in mils (thousands of an inch).
* @param bottomMils The bottom margin in mils (thousands of an inch).
*/
- public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
+ public Margins(@IntRange(from = 0) int leftMils, @IntRange(from = 0) int topMils,
+ @IntRange(from = 0) int rightMils, @IntRange(from = 0) int bottomMils) {
mTopMils = topMils;
mLeftMils = leftMils;
mRightMils = rightMils;
@@ -1216,7 +1239,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The left margin.
*/
- public int getLeftMils() {
+ public @IntRange(from = 0) int getLeftMils() {
return mLeftMils;
}
@@ -1225,7 +1248,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The top margin.
*/
- public int getTopMils() {
+ public @IntRange(from = 0) int getTopMils() {
return mTopMils;
}
@@ -1234,7 +1257,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The right margin.
*/
- public int getRightMils() {
+ public @IntRange(from = 0) int getRightMils() {
return mRightMils;
}
@@ -1243,7 +1266,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The bottom margin.
*/
- public int getBottomMils() {
+ public @IntRange(from = 0) int getBottomMils() {
return mBottomMils;
}
@@ -1368,7 +1391,7 @@ public final class PrintAttributes implements Parcelable {
* @param mediaSize The media size.
* @return This builder.
*/
- public Builder setMediaSize(MediaSize mediaSize) {
+ public @NonNull Builder setMediaSize(@NonNull MediaSize mediaSize) {
mAttributes.setMediaSize(mediaSize);
return this;
}
@@ -1379,7 +1402,7 @@ public final class PrintAttributes implements Parcelable {
* @param resolution The resolution.
* @return This builder.
*/
- public Builder setResolution(Resolution resolution) {
+ public @NonNull Builder setResolution(@NonNull Resolution resolution) {
mAttributes.setResolution(resolution);
return this;
}
@@ -1391,7 +1414,7 @@ public final class PrintAttributes implements Parcelable {
* @param margins The margins.
* @return This builder.
*/
- public Builder setMinMargins(Margins margins) {
+ public @NonNull Builder setMinMargins(@NonNull Margins margins) {
mAttributes.setMinMargins(margins);
return this;
}
@@ -1405,7 +1428,7 @@ public final class PrintAttributes implements Parcelable {
* @see PrintAttributes#COLOR_MODE_MONOCHROME
* @see PrintAttributes#COLOR_MODE_COLOR
*/
- public Builder setColorMode(int colorMode) {
+ public @NonNull Builder setColorMode(@ColorMode int colorMode) {
mAttributes.setColorMode(colorMode);
return this;
}
@@ -1420,7 +1443,7 @@ public final class PrintAttributes implements Parcelable {
* @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
* @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
*/
- public Builder setDuplexMode(int duplexMode) {
+ public @NonNull Builder setDuplexMode(@DuplexMode int duplexMode) {
mAttributes.setDuplexMode(duplexMode);
return this;
}
@@ -1430,7 +1453,7 @@ public final class PrintAttributes implements Parcelable {
*
* @return The new instance.
*/
- public PrintAttributes build() {
+ public @NonNull PrintAttributes build() {
return mAttributes;
}
}
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index 44e6410f64d5..db3b6f47af43 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -16,10 +16,16 @@
package android.print;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This class encapsulates information about a document for printing
* purposes. This meta-data is used by the platform and print services,
@@ -74,6 +80,13 @@ public final class PrintDocumentInfo implements Parcelable {
*/
public static final int PAGE_COUNT_UNKNOWN = -1;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ CONTENT_TYPE_UNKNOWN, CONTENT_TYPE_DOCUMENT, CONTENT_TYPE_PHOTO
+ })
+ public @interface ContentType {
+ }
/**
* Content type: unknown.
*/
@@ -116,9 +129,9 @@ public final class PrintDocumentInfo implements Parcelable {
/**
* Creates a new instance.
*
- * @param Prototype from which to clone.
+ * @param prototype from which to clone.
*/
- private PrintDocumentInfo(PrintDocumentInfo prototype) {
+ private PrintDocumentInfo(@NonNull PrintDocumentInfo prototype) {
mName = prototype.mName;
mPageCount = prototype.mPageCount;
mContentType = prototype.mContentType;
@@ -143,7 +156,7 @@ public final class PrintDocumentInfo implements Parcelable {
*
* @return The document name.
*/
- public String getName() {
+ public @NonNull String getName() {
return mName;
}
@@ -154,7 +167,7 @@ public final class PrintDocumentInfo implements Parcelable {
*
* @see #PAGE_COUNT_UNKNOWN
*/
- public int getPageCount() {
+ public @IntRange(from = -1) int getPageCount() {
return mPageCount;
}
@@ -167,7 +180,7 @@ public final class PrintDocumentInfo implements Parcelable {
* @see #CONTENT_TYPE_DOCUMENT
* @see #CONTENT_TYPE_PHOTO
*/
- public int getContentType() {
+ public @ContentType int getContentType() {
return mContentType;
}
@@ -176,7 +189,7 @@ public final class PrintDocumentInfo implements Parcelable {
*
* @return The data size.
*/
- public long getDataSize() {
+ public @IntRange(from = 0) long getDataSize() {
return mDataSize;
}
@@ -187,7 +200,7 @@ public final class PrintDocumentInfo implements Parcelable {
*
* @hide
*/
- public void setDataSize(long dataSize) {
+ public void setDataSize(@IntRange(from = 0) long dataSize) {
mDataSize = dataSize;
}
@@ -288,7 +301,7 @@ public final class PrintDocumentInfo implements Parcelable {
* is the file name if the content it describes is saved as a PDF.
* Cannot be empty.
*/
- public Builder(String name) {
+ public Builder(@NonNull String name) {
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("name cannot be empty");
}
@@ -302,10 +315,11 @@ public final class PrintDocumentInfo implements Parcelable {
* <strong>Default: </strong> {@link #PAGE_COUNT_UNKNOWN}
* </p>
*
- * @param pageCount The number of pages. Must be greater than
- * or equal to zero or {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}.
+ * @param pageCount The number of pages. Must be greater than or equal to zero or
+ * {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}.
+ * @return This builder.
*/
- public Builder setPageCount(int pageCount) {
+ public @NonNull Builder setPageCount(@IntRange(from = -1) int pageCount) {
if (pageCount < 0 && pageCount != PAGE_COUNT_UNKNOWN) {
throw new IllegalArgumentException("pageCount"
+ " must be greater than or equal to zero or"
@@ -322,12 +336,12 @@ public final class PrintDocumentInfo implements Parcelable {
* </p>
*
* @param type The content type.
- *
+ * @return This builder.
* @see #CONTENT_TYPE_UNKNOWN
* @see #CONTENT_TYPE_DOCUMENT
* @see #CONTENT_TYPE_PHOTO
*/
- public Builder setContentType(int type) {
+ public @NonNull Builder setContentType(@ContentType int type) {
mPrototype.mContentType = type;
return this;
}
@@ -337,7 +351,7 @@ public final class PrintDocumentInfo implements Parcelable {
*
* @return The new instance.
*/
- public PrintDocumentInfo build() {
+ public @NonNull PrintDocumentInfo build() {
// Zero pages is the same as unknown as in this case
// we will have to ask for all pages and look a the
// wiritten PDF file for the page count.
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index 0abe2193249e..777baabd955a 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -16,6 +16,9 @@
package android.print;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
/**
* This class represents a print job from the perspective of an
* application. It contains behavior methods for performing operations
@@ -41,7 +44,7 @@ public final class PrintJob {
*
* @return The id.
*/
- public PrintJobId getId() {
+ public @NonNull PrintJobId getId() {
return mCachedInfo.getId();
}
@@ -55,7 +58,7 @@ public final class PrintJob {
*
* @return The print job info.
*/
- public PrintJobInfo getInfo() {
+ public @Nullable PrintJobInfo getInfo() {
if (isInImmutableState()) {
return mCachedInfo;
}
diff --git a/core/java/android/print/PrintJobId.java b/core/java/android/print/PrintJobId.java
index 01550e2a7413..a2ee02b7bc49 100644
--- a/core/java/android/print/PrintJobId.java
+++ b/core/java/android/print/PrintJobId.java
@@ -16,6 +16,7 @@
package android.print;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -91,14 +92,14 @@ public final class PrintJobId implements Parcelable {
*
* @hide
*/
- public String flattenToString() {
+ public @NonNull String flattenToString() {
return mValue;
}
/**
* Unflattens a print job id from a string.
*
- * @string The string.
+ * @param string The string.
* @return The unflattened id, or null if the string is malformed.
*
* @hide
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 7148c8757830..21836b3a6109 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -17,6 +17,9 @@
package android.print;
import android.annotation.FloatRange;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Bundle;
@@ -25,6 +28,8 @@ import android.os.Parcelable;
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
/**
@@ -35,6 +40,15 @@ import java.util.Arrays;
*/
public final class PrintJobInfo implements Parcelable {
+ /** @hide */
+ @IntDef({
+ STATE_CREATED, STATE_QUEUED, STATE_STARTED, STATE_BLOCKED, STATE_COMPLETED,
+ STATE_FAILED, STATE_CANCELED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {
+ }
+
/**
* Constant for matching any print job state.
*
@@ -200,7 +214,7 @@ public final class PrintJobInfo implements Parcelable {
mAdvancedOptions = other.mAdvancedOptions;
}
- private PrintJobInfo(Parcel parcel) {
+ private PrintJobInfo(@NonNull Parcel parcel) {
mId = parcel.readParcelable(null);
mLabel = parcel.readString();
mPrinterId = parcel.readParcelable(null);
@@ -230,7 +244,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @return The id.
*/
- public PrintJobId getId() {
+ public @NonNull PrintJobId getId() {
return mId;
}
@@ -241,7 +255,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @hide
*/
- public void setId(PrintJobId id) {
+ public void setId(@NonNull PrintJobId id) {
this.mId = id;
}
@@ -250,7 +264,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @return The label.
*/
- public String getLabel() {
+ public @NonNull String getLabel() {
return mLabel;
}
@@ -261,7 +275,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @hide
*/
- public void setLabel(String label) {
+ public void setLabel(@NonNull String label) {
mLabel = label;
}
@@ -270,7 +284,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @return The target printer id.
*/
- public PrinterId getPrinterId() {
+ public @Nullable PrinterId getPrinterId() {
return mPrinterId;
}
@@ -281,7 +295,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @hide
*/
- public void setPrinterId(PrinterId printerId) {
+ public void setPrinterId(@NonNull PrinterId printerId) {
mPrinterId = printerId;
}
@@ -292,7 +306,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @hide
*/
- public String getPrinterName() {
+ public @Nullable String getPrinterName() {
return mPrinterName;
}
@@ -303,7 +317,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @hide
*/
- public void setPrinterName(String printerName) {
+ public void setPrinterName(@NonNull String printerName) {
mPrinterName = printerName;
}
@@ -320,7 +334,7 @@ public final class PrintJobInfo implements Parcelable {
* @see #STATE_FAILED
* @see #STATE_CANCELED
*/
- public int getState() {
+ public @State int getState() {
return mState;
}
@@ -431,7 +445,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @return The number of copies or zero if not set.
*/
- public int getCopies() {
+ public @IntRange(from = 0) int getCopies() {
return mCopies;
}
@@ -454,7 +468,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @return The included pages or <code>null</code> if not set.
*/
- public PageRange[] getPages() {
+ public @Nullable PageRange[] getPages() {
return mPageRanges;
}
@@ -474,7 +488,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @return The attributes.
*/
- public PrintAttributes getAttributes() {
+ public @NonNull PrintAttributes getAttributes() {
return mAttributes;
}
@@ -713,7 +727,7 @@ public final class PrintJobInfo implements Parcelable {
* @param prototype Prototype to use as a starting point.
* Can be <code>null</code>.
*/
- public Builder(PrintJobInfo prototype) {
+ public Builder(@Nullable PrintJobInfo prototype) {
mPrototype = (prototype != null)
? new PrintJobInfo(prototype)
: new PrintJobInfo();
@@ -724,7 +738,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @param copies The number of copies.
*/
- public void setCopies(int copies) {
+ public void setCopies(@IntRange(from = 1) int copies) {
mPrototype.mCopies = copies;
}
@@ -733,7 +747,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @param attributes The attributes.
*/
- public void setAttributes(PrintAttributes attributes) {
+ public void setAttributes(@NonNull PrintAttributes attributes) {
mPrototype.mAttributes = attributes;
}
@@ -742,7 +756,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @param pages The included pages.
*/
- public void setPages(PageRange[] pages) {
+ public void setPages(@NonNull PageRange[] pages) {
mPrototype.mPageRanges = pages;
}
@@ -774,7 +788,7 @@ public final class PrintJobInfo implements Parcelable {
* @param key The option key.
* @param value The option value.
*/
- public void putAdvancedOption(String key, String value) {
+ public void putAdvancedOption(@NonNull String key, @Nullable String value) {
if (mPrototype.mAdvancedOptions == null) {
mPrototype.mAdvancedOptions = new Bundle();
}
@@ -787,7 +801,7 @@ public final class PrintJobInfo implements Parcelable {
* @param key The option key.
* @param value The option value.
*/
- public void putAdvancedOption(String key, int value) {
+ public void putAdvancedOption(@NonNull String key, int value) {
if (mPrototype.mAdvancedOptions == null) {
mPrototype.mAdvancedOptions = new Bundle();
}
@@ -799,7 +813,7 @@ public final class PrintJobInfo implements Parcelable {
*
* @return The new instance.
*/
- public PrintJobInfo build() {
+ public @NonNull PrintJobInfo build() {
return mPrototype;
}
}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 3fb812e401f7..3eb487461e5c 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -16,11 +16,14 @@
package android.print;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.content.Context;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
+import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -180,6 +183,8 @@ public final class PrintManager {
*
* @param context The current context in which to operate.
* @param service The backing system service.
+ * @param userId The user id in which to operate.
+ * @param appId The application id in which to operate.
* @hide
*/
public PrintManager(Context context, IPrintManager service, int userId, int appId) {
@@ -290,6 +295,7 @@ public final class PrintManager {
/**
* Gets a print job given its id.
*
+ * @param printJobId The id of the print job.
* @return The print job list.
* @see PrintJob
* @hide
@@ -311,12 +317,35 @@ public final class PrintManager {
}
/**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @return the custom icon to be used for the printer or null if the icon is
+ * not yet available
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ * @hide
+ */
+ public Icon getCustomPrinterIcon(PrinterId printerId) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return null;
+ }
+ try {
+ return mService.getCustomPrinterIcon(printerId, mUserId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error getting custom printer icon", re);
+ }
+ return null;
+ }
+
+ /**
* Gets the print jobs for this application.
*
* @return The print job list.
* @see PrintJob
*/
- public List<PrintJob> getPrintJobs() {
+ public @NonNull List<PrintJob> getPrintJobs() {
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
return Collections.emptyList();
@@ -411,8 +440,9 @@ public final class PrintManager {
*
* @see PrintJob
*/
- public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
- PrintAttributes attributes) {
+ public @NonNull PrintJob print(@NonNull String printJobName,
+ @NonNull PrintDocumentAdapter documentAdapter,
+ @Nullable PrintAttributes attributes) {
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
return null;
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index 96f318526384..d13879ba6914 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -16,8 +16,11 @@
package android.print;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.print.PrintAttributes.ColorMode;
+import android.print.PrintAttributes.DuplexMode;
import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
@@ -121,7 +124,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
*
* @return The media sizes.
*/
- public List<MediaSize> getMediaSizes() {
+ public @NonNull List<MediaSize> getMediaSizes() {
return Collections.unmodifiableList(mMediaSizes);
}
@@ -130,7 +133,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
*
* @return The resolutions.
*/
- public List<Resolution> getResolutions() {
+ public @NonNull List<Resolution> getResolutions() {
return Collections.unmodifiableList(mResolutions);
}
@@ -140,7 +143,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
*
* @return The minimal margins.
*/
- public Margins getMinMargins() {
+ public @NonNull Margins getMinMargins() {
return mMinMargins;
}
@@ -152,7 +155,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
* @see PrintAttributes#COLOR_MODE_COLOR
* @see PrintAttributes#COLOR_MODE_MONOCHROME
*/
- public int getColorModes() {
+ public @ColorMode int getColorModes() {
return mColorModes;
}
@@ -165,7 +168,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
* @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
* @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
*/
- public int getDuplexModes() {
+ public @DuplexMode int getDuplexModes() {
return mDuplexModes;
}
@@ -174,7 +177,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
*
* @return The default attributes.
*/
- public PrintAttributes getDefaults() {
+ public @NonNull PrintAttributes getDefaults() {
PrintAttributes.Builder builder = new PrintAttributes.Builder();
builder.setMinMargins(mMinMargins);
@@ -425,7 +428,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
*
* @throws IllegalArgumentException If the printer id is <code>null</code>.
*/
- public Builder(PrinterId printerId) {
+ public Builder(@NonNull PrinterId printerId) {
if (printerId == null) {
throw new IllegalArgumentException("printerId cannot be null.");
}
@@ -446,7 +449,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
*
* @see PrintAttributes.MediaSize
*/
- public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) {
+ public @NonNull Builder addMediaSize(@NonNull MediaSize mediaSize, boolean isDefault) {
if (mPrototype.mMediaSizes == null) {
mPrototype.mMediaSizes = new ArrayList<MediaSize>();
}
@@ -474,7 +477,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
*
* @see PrintAttributes.Resolution
*/
- public Builder addResolution(Resolution resolution, boolean isDefault) {
+ public @NonNull Builder addResolution(@NonNull Resolution resolution, boolean isDefault) {
if (mPrototype.mResolutions == null) {
mPrototype.mResolutions = new ArrayList<Resolution>();
}
@@ -502,7 +505,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
*
* @see PrintAttributes.Margins
*/
- public Builder setMinMargins(Margins margins) {
+ public @NonNull Builder setMinMargins(@NonNull Margins margins) {
if (margins == null) {
throw new IllegalArgumentException("margins cannot be null");
}
@@ -532,7 +535,8 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
* @see PrintAttributes#COLOR_MODE_COLOR
* @see PrintAttributes#COLOR_MODE_MONOCHROME
*/
- public Builder setColorModes(int colorModes, int defaultColorMode) {
+ public @NonNull Builder setColorModes(@ColorMode int colorModes,
+ @ColorMode int defaultColorMode) {
int currentModes = colorModes;
while (currentModes > 0) {
final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
@@ -562,7 +566,8 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
* @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
* @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
*/
- public Builder setDuplexModes(int duplexModes, int defaultDuplexMode) {
+ public @NonNull Builder setDuplexModes(@DuplexMode int duplexModes,
+ @DuplexMode int defaultDuplexMode) {
int currentModes = duplexModes;
while (currentModes > 0) {
final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
@@ -589,7 +594,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
*
* @throws IllegalStateException If a required attribute was not specified.
*/
- public PrinterCapabilitiesInfo build() {
+ public @NonNull PrinterCapabilitiesInfo build() {
if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) {
throw new IllegalStateException("No media size specified.");
}
diff --git a/core/java/android/print/PrinterId.java b/core/java/android/print/PrinterId.java
index a3f3b2bfee11..83efe8020d98 100644
--- a/core/java/android/print/PrinterId.java
+++ b/core/java/android/print/PrinterId.java
@@ -16,6 +16,7 @@
package android.print;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
@@ -65,7 +66,7 @@ public final class PrinterId implements Parcelable {
*
* @return The printer name.
*/
- public String getLocalId() {
+ public @NonNull String getLocalId() {
return mLocalId;
}
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index 7fcc81f41006..afef9c0dac27 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -16,10 +16,26 @@
package android.print;
+import android.annotation.DrawableRes;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This class represents the description of a printer. Instances of
* this class are created by print services to report to the system
@@ -30,6 +46,13 @@ import android.text.TextUtils;
*/
public final class PrinterInfo implements Parcelable {
+ /** @hide */
+ @IntDef({
+ STATUS_IDLE, STATUS_BUSY, STATUS_UNAVAILABLE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Status {
+ }
/** Printer status: the printer is idle and ready to print. */
public static final int STATUS_IDLE = 1;
@@ -41,6 +64,18 @@ public final class PrinterInfo implements Parcelable {
private PrinterId mId;
+ /** Resource inside the printer's services's package to be used as an icon */
+ private int mIconResourceId;
+
+ /** If a custom icon can be loaded for the printer */
+ private boolean mHasCustomPrinterIcon;
+
+ /** The generation of the icon in the cache. */
+ private int mCustomPrinterIconGen;
+
+ /** Intent that launches the activity showing more information about the printer. */
+ private PendingIntent mInfoIntent;
+
private String mName;
private int mStatus;
@@ -77,6 +112,10 @@ public final class PrinterInfo implements Parcelable {
} else {
mCapabilities = null;
}
+ mIconResourceId = other.mIconResourceId;
+ mHasCustomPrinterIcon = other.mHasCustomPrinterIcon;
+ mCustomPrinterIconGen = other.mCustomPrinterIconGen;
+ mInfoIntent = other.mInfoIntent;
}
/**
@@ -84,16 +123,64 @@ public final class PrinterInfo implements Parcelable {
*
* @return The printer id.
*/
- public PrinterId getId() {
+ public @NonNull PrinterId getId() {
return mId;
}
/**
+ * Get the icon to be used for this printer. If no per printer icon is available, the printer's
+ * service's icon is returned. If the printer has a custom icon this icon might get requested
+ * asynchronously. Once the icon is loaded the discovery sessions will be notified that the
+ * printer changed.
+ *
+ * @param context The context that will be using the icons
+ * @return The icon to be used for the printer or null if no icon could be found.
+ * @hide
+ */
+ @TestApi
+ public @Nullable Drawable loadIcon(@NonNull Context context) {
+ Drawable drawable = null;
+ PackageManager packageManager = context.getPackageManager();
+
+ if (mHasCustomPrinterIcon) {
+ PrintManager printManager = (PrintManager) context
+ .getSystemService(Context.PRINT_SERVICE);
+
+ Icon icon = printManager.getCustomPrinterIcon(mId);
+
+ if (icon != null) {
+ drawable = icon.loadDrawable(context);
+ }
+ }
+
+ if (drawable == null) {
+ try {
+ String packageName = mId.getServiceName().getPackageName();
+ PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
+ ApplicationInfo appInfo = packageInfo.applicationInfo;
+
+ // If no custom icon is available, try the icon from the resources
+ if (mIconResourceId != 0) {
+ drawable = packageManager.getDrawable(packageName, mIconResourceId, appInfo);
+ }
+
+ // Fall back to the printer's service's icon if no per printer icon could be found
+ if (drawable == null) {
+ drawable = appInfo.loadIcon(packageManager);
+ }
+ } catch (NameNotFoundException e) {
+ }
+ }
+
+ return drawable;
+ }
+
+ /**
* Get the printer name.
*
* @return The printer name.
*/
- public String getName() {
+ public @Nullable String getName() {
return mName;
}
@@ -106,7 +193,7 @@ public final class PrinterInfo implements Parcelable {
* @see #STATUS_IDLE
* @see #STATUS_UNAVAILABLE
*/
- public int getStatus() {
+ public @Status int getStatus() {
return mStatus;
}
@@ -115,16 +202,28 @@ public final class PrinterInfo implements Parcelable {
*
* @return The description.
*/
- public String getDescription() {
+ public @Nullable String getDescription() {
return mDescription;
}
/**
+ * Get the {@link PendingIntent} that launches the activity showing more information about the
+ * printer.
+ *
+ * @return the {@link PendingIntent} that launches the activity showing more information about
+ * the printer or null if it is not configured
+ * @hide
+ */
+ public @Nullable PendingIntent getInfoIntent() {
+ return mInfoIntent;
+ }
+
+ /**
* Gets the printer capabilities.
*
* @return The capabilities.
*/
- public PrinterCapabilitiesInfo getCapabilities() {
+ public @Nullable PrinterCapabilitiesInfo getCapabilities() {
return mCapabilities;
}
@@ -134,6 +233,10 @@ public final class PrinterInfo implements Parcelable {
mStatus = parcel.readInt();
mDescription = parcel.readString();
mCapabilities = parcel.readParcelable(null);
+ mIconResourceId = parcel.readInt();
+ mHasCustomPrinterIcon = parcel.readByte() != 0;
+ mCustomPrinterIconGen = parcel.readInt();
+ mInfoIntent = parcel.readParcelable(null);
}
@Override
@@ -148,6 +251,10 @@ public final class PrinterInfo implements Parcelable {
parcel.writeInt(mStatus);
parcel.writeString(mDescription);
parcel.writeParcelable(mCapabilities, flags);
+ parcel.writeInt(mIconResourceId);
+ parcel.writeByte((byte) (mHasCustomPrinterIcon ? 1 : 0));
+ parcel.writeInt(mCustomPrinterIconGen);
+ parcel.writeParcelable(mInfoIntent, flags);
}
@Override
@@ -159,21 +266,22 @@ public final class PrinterInfo implements Parcelable {
result = prime * result + mStatus;
result = prime * result + ((mDescription != null) ? mDescription.hashCode() : 0);
result = prime * result + ((mCapabilities != null) ? mCapabilities.hashCode() : 0);
+ result = prime * result + mIconResourceId;
+ result = prime * result + (mHasCustomPrinterIcon ? 1 : 0);
+ result = prime * result + mCustomPrinterIconGen;
+ result = prime * result + ((mInfoIntent != null) ? mInfoIntent.hashCode() : 0);
return result;
}
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- PrinterInfo other = (PrinterInfo) obj;
+ /**
+ * Compare two {@link PrinterInfo printerInfos} in all aspects beside being null and the
+ * {@link #mStatus}.
+ *
+ * @param other the other {@link PrinterInfo}
+ * @return true iff the infos are equivalent
+ * @hide
+ */
+ public boolean equalsIgnoringStatus(PrinterInfo other) {
if (mId == null) {
if (other.mId != null) {
return false;
@@ -184,9 +292,6 @@ public final class PrinterInfo implements Parcelable {
if (!TextUtils.equals(mName, other.mName)) {
return false;
}
- if (mStatus != other.mStatus) {
- return false;
- }
if (!TextUtils.equals(mDescription, other.mDescription)) {
return false;
}
@@ -197,6 +302,43 @@ public final class PrinterInfo implements Parcelable {
} else if (!mCapabilities.equals(other.mCapabilities)) {
return false;
}
+ if (mIconResourceId != other.mIconResourceId) {
+ return false;
+ }
+ if (mHasCustomPrinterIcon != other.mHasCustomPrinterIcon) {
+ return false;
+ }
+ if (mCustomPrinterIconGen != other.mCustomPrinterIconGen) {
+ return false;
+ }
+ if (mInfoIntent == null) {
+ if (other.mInfoIntent != null) {
+ return false;
+ }
+ } else if (!mInfoIntent.equals(other.mInfoIntent)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ PrinterInfo other = (PrinterInfo) obj;
+ if (!equalsIgnoringStatus(other)) {
+ return false;
+ }
+ if (mStatus != other.mStatus) {
+ return false;
+ }
return true;
}
@@ -209,6 +351,10 @@ public final class PrinterInfo implements Parcelable {
builder.append(", status=").append(mStatus);
builder.append(", description=").append(mDescription);
builder.append(", capabilities=").append(mCapabilities);
+ builder.append(", iconResId=").append(mIconResourceId);
+ builder.append(", hasCustomPrinterIcon=").append(mHasCustomPrinterIcon);
+ builder.append(", customPrinterIconGen=").append(mCustomPrinterIconGen);
+ builder.append(", infoIntent=").append(mInfoIntent);
builder.append("\"}");
return builder.toString();
}
@@ -228,7 +374,7 @@ public final class PrinterInfo implements Parcelable {
* @throws IllegalArgumentException If the printer id is null, or the
* printer name is empty or the status is not a valid one.
*/
- public Builder(PrinterId printerId, String name, int status) {
+ public Builder(@NonNull PrinterId printerId, @NonNull String name, @Status int status) {
if (printerId == null) {
throw new IllegalArgumentException("printerId cannot be null.");
}
@@ -249,7 +395,7 @@ public final class PrinterInfo implements Parcelable {
*
* @param other Other info from which to start building.
*/
- public Builder(PrinterInfo other) {
+ public Builder(@NonNull PrinterInfo other) {
mPrototype = new PrinterInfo();
mPrototype.copyFrom(other);
}
@@ -264,19 +410,50 @@ public final class PrinterInfo implements Parcelable {
* @see PrinterInfo#STATUS_BUSY
* @see PrinterInfo#STATUS_UNAVAILABLE
*/
- public Builder setStatus(int status) {
+ public @NonNull Builder setStatus(@Status int status) {
mPrototype.mStatus = status;
return this;
}
/**
+ * Set a drawable resource as icon for this printer. If no icon is set the printer's
+ * service's icon is used for the printer.
+ *
+ * @param iconResourceId The resource ID of the icon.
+ * @return This builder.
+ * @see PrinterInfo.Builder#setHasCustomPrinterIcon
+ */
+ public @NonNull Builder setIconResourceId(@DrawableRes int iconResourceId) {
+ mPrototype.mIconResourceId = iconResourceId;
+ return this;
+ }
+
+ /**
+ * Declares that the print service can load a custom per printer's icon. If both
+ * {@link PrinterInfo.Builder#setIconResourceId} and a custom icon are set the resource icon
+ * is shown while the custom icon loads but then the custom icon is used. If
+ * {@link PrinterInfo.Builder#setIconResourceId} is not set the printer's service's icon is
+ * shown while loading.
+ * <p>
+ * The icon is requested asynchronously and only when needed via
+ * {@link android.printservice.PrinterDiscoverySession#onRequestCustomPrinterIcon}.
+ * </p>
+ *
+ * @return This builder.
+ */
+ public @NonNull Builder setHasCustomPrinterIcon() {
+ mPrototype.mHasCustomPrinterIcon = true;
+ return this;
+ }
+
+ /**
* Sets the <strong>localized</strong> printer name which
* is shown to the user
*
* @param name The name.
* @return This builder.
*/
- public Builder setName(String name) {
+ public @NonNull Builder setName(@NonNull String name) {
mPrototype.mName = name;
return this;
}
@@ -288,18 +465,30 @@ public final class PrinterInfo implements Parcelable {
* @param description The description.
* @return This builder.
*/
- public Builder setDescription(String description) {
+ public @NonNull Builder setDescription(@NonNull String description) {
mPrototype.mDescription = description;
return this;
}
/**
+ * Sets the {@link PendingIntent} that launches an activity showing more information about
+ * the printer.
+ *
+ * @param infoIntent The {@link PendingIntent intent}.
+ * @return This builder.
+ */
+ public @NonNull Builder setInfoIntent(@NonNull PendingIntent infoIntent) {
+ mPrototype.mInfoIntent = infoIntent;
+ return this;
+ }
+
+ /**
* Sets the printer capabilities.
*
* @param capabilities The capabilities.
* @return This builder.
*/
- public Builder setCapabilities(PrinterCapabilitiesInfo capabilities) {
+ public @NonNull Builder setCapabilities(@NonNull PrinterCapabilitiesInfo capabilities) {
mPrototype.mCapabilities = capabilities;
return this;
}
@@ -309,7 +498,7 @@ public final class PrinterInfo implements Parcelable {
*
* @return A new {@link PrinterInfo}.
*/
- public PrinterInfo build() {
+ public @NonNull PrinterInfo build() {
return mPrototype;
}
@@ -318,6 +507,19 @@ public final class PrinterInfo implements Parcelable {
|| status == STATUS_BUSY
|| status == STATUS_UNAVAILABLE);
}
+
+ /**
+ * Increments the generation number of the custom printer icon. As the {@link PrinterInfo}
+ * does not match the previous one anymore, users of the {@link PrinterInfo} will reload the
+ * icon if needed.
+ *
+ * @return This builder.
+ * @hide
+ */
+ public @NonNull Builder incCustomPrinterIconGen() {
+ mPrototype.mCustomPrinterIconGen++;
+ return this;
+ }
}
public static final Parcelable.Creator<PrinterInfo> CREATOR =
diff --git a/core/java/android/print/pdf/PrintedPdfDocument.java b/core/java/android/print/pdf/PrintedPdfDocument.java
index 2d8aafa1a573..df7c05477a1a 100644
--- a/core/java/android/print/pdf/PrintedPdfDocument.java
+++ b/core/java/android/print/pdf/PrintedPdfDocument.java
@@ -16,26 +16,25 @@
package android.print.pdf;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.pdf.PdfDocument;
-import android.graphics.pdf.PdfDocument.Page;
-import android.graphics.pdf.PdfDocument.PageInfo;
import android.print.PrintAttributes;
import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
/**
- * This class is a helper for creating a PDF file for given print
- * attributes. It is useful for implementing printing via the native
- * Android graphics APIs.
+ * This class is a helper for creating a PDF file for given print attributes. It is useful for
+ * implementing printing via the native Android graphics APIs.
* <p>
- * This class computes the page width, page height, and content rectangle
- * from the provided print attributes and these precomputed values can be
- * accessed via {@link #getPageWidth()}, {@link #getPageHeight()}, and
- * {@link #getPageContentRect()}, respectively. The {@link #startPage(int)}
- * methods creates pages whose {@link PageInfo} is initialized with the
- * precomputed values for width, height, and content rectangle.
+ * This class computes the page width, page height, and content rectangle from the provided print
+ * attributes and these precomputed values can be accessed via {@link #getPageWidth()},
+ * {@link #getPageHeight()}, and {@link #getPageContentRect()}, respectively. The
+ * {@link #startPage(int)} methods creates pages whose
+ * {@link android.graphics.pdf.PdfDocument.PageInfo PageInfo} is initialized with the precomputed
+ * values for width, height, and content rectangle.
* <p>
* A typical use of the APIs looks like this:
* </p>
@@ -81,7 +80,7 @@ public class PrintedPdfDocument extends PdfDocument {
* @param context Context instance for accessing resources.
* @param attributes The print attributes.
*/
- public PrintedPdfDocument(Context context, PrintAttributes attributes) {
+ public PrintedPdfDocument(@NonNull Context context, @NonNull PrintAttributes attributes) {
MediaSize mediaSize = attributes.getMediaSize();
// Compute the size of the target canvas from the attributes.
@@ -105,28 +104,28 @@ public class PrintedPdfDocument extends PdfDocument {
}
/**
- * Starts a new page. The page is created using width, height and content
- * rectangle computed from the print attributes passed in the constructor
- * and the given page number to create an appropriate {@link PageInfo}.
+ * Starts a new page. The page is created using width, height and content rectangle computed
+ * from the print attributes passed in the constructor and the given page number to create an
+ * appropriate {@link android.graphics.pdf.PdfDocument.PageInfo PageInfo}.
* <p>
- * After the page is created you can draw arbitrary content on the page's
- * canvas which you can get by calling {@link Page#getCanvas() Page.getCanvas()}.
+ * After the page is created you can draw arbitrary content on the page's canvas which you can
+ * get by calling {@link android.graphics.pdf.PdfDocument.Page#getCanvas() Page.getCanvas()}.
* After you are done drawing the content you should finish the page by calling
- * {@link #finishPage(Page)}. After the page is finished you should no longer
- * access the page or its canvas.
+ * {@link #finishPage(Page)}. After the page is finished you should no longer access the page or
+ * its canvas.
* </p>
* <p>
- * <strong>Note:</strong> Do not call this method after {@link #close()}.
- * Also do not call this method if the last page returned by this method
- * is not finished by calling {@link #finishPage(Page)}.
+ * <strong>Note:</strong> Do not call this method after {@link #close()}. Also do not call this
+ * method if the last page returned by this method is not finished by calling
+ * {@link #finishPage(Page)}.
* </p>
*
- * @param pageNumber The page number. Must be a positive value.
+ * @param pageNumber The page number. Must be a non negative.
* @return A blank page.
*
* @see #finishPage(Page)
*/
- public Page startPage(int pageNumber) {
+ public @NonNull Page startPage(@IntRange(from = 0) int pageNumber) {
PageInfo pageInfo = new PageInfo
.Builder(mPageWidth, mPageHeight, pageNumber)
.setContentRect(mContentRect)
@@ -139,7 +138,7 @@ public class PrintedPdfDocument extends PdfDocument {
*
* @return The page width in PostScript points (1/72th of an inch).
*/
- public int getPageWidth() {
+ public @IntRange(from = 0) int getPageWidth() {
return mPageWidth;
}
@@ -148,7 +147,7 @@ public class PrintedPdfDocument extends PdfDocument {
*
* @return The page height in PostScript points (1/72th of an inch).
*/
- public int getPageHeight() {
+ public @IntRange(from = 0) int getPageHeight() {
return mPageHeight;
}
@@ -158,7 +157,7 @@ public class PrintedPdfDocument extends PdfDocument {
*
* @return The content rectangle.
*/
- public Rect getPageContentRect() {
+ public @NonNull Rect getPageContentRect() {
return mContentRect;
}
}
diff --git a/core/java/android/printservice/CustomPrinterIconCallback.java b/core/java/android/printservice/CustomPrinterIconCallback.java
new file mode 100644
index 000000000000..ea9ea8bf43f6
--- /dev/null
+++ b/core/java/android/printservice/CustomPrinterIconCallback.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.printservice;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.drawable.Icon;
+import android.os.RemoteException;
+import android.print.PrinterId;
+import android.util.Log;
+
+
+/**
+ * Callback for {@link PrinterDiscoverySession#onRequestCustomPrinterIcon}.
+ */
+public class CustomPrinterIconCallback {
+ /** The printer the call back is for */
+ private final @NonNull PrinterId mPrinterId;
+ private final @NonNull IPrintServiceClient mObserver;
+ private static final String LOG_TAG = "CustomPrinterIconCallback";
+
+ /**
+ * Create a callback class to be used once a icon is loaded
+ *
+ * @param printerId The printer the icon should be loaded for
+ * @param observer The observer that needs to be notified about the update.
+ */
+ CustomPrinterIconCallback(@NonNull PrinterId printerId, @NonNull IPrintServiceClient observer) {
+ mPrinterId = printerId;
+ mObserver = observer;
+ }
+
+ /**
+ * Provide a new icon for a printer. Can be called more than once to update the icon.
+ *
+ * @param icon The new icon for the printer or null to unset the current icon
+ * @return true iff the icon could be updated
+ */
+ public boolean onCustomPrinterIconLoaded(@Nullable Icon icon) {
+ try {
+ mObserver.onCustomPrinterIconLoaded(mPrinterId, icon);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG , "Could not update icon", e);
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/core/java/android/printservice/IPrintService.aidl b/core/java/android/printservice/IPrintService.aidl
index ee3661937395..3750d7ae1a9f 100644
--- a/core/java/android/printservice/IPrintService.aidl
+++ b/core/java/android/printservice/IPrintService.aidl
@@ -10,7 +10,7 @@
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
+ * See the License for the specific language governing permissions and
* limitations under the License.
*/
@@ -35,6 +35,15 @@ oneway interface IPrintService {
void stopPrinterDiscovery();
void validatePrinters(in List<PrinterId> printerIds);
void startPrinterStateTracking(in PrinterId printerId);
+
+ /**
+ * Request the custom icon for a printer.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ void requestCustomPrinterIcon(in PrinterId printerId);
+
void stopPrinterStateTracking(in PrinterId printerId);
void destroyPrinterDiscoverySession();
}
diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl
index b4baa4851392..0ae1e180ec9e 100644
--- a/core/java/android/printservice/IPrintServiceClient.aidl
+++ b/core/java/android/printservice/IPrintServiceClient.aidl
@@ -16,6 +16,7 @@
package android.printservice;
+import android.graphics.drawable.Icon;
import android.os.ParcelFileDescriptor;
import android.print.PrintJobInfo;
import android.print.PrinterId;
@@ -53,4 +54,13 @@ interface IPrintServiceClient {
void onPrintersAdded(in ParceledListSlice printers);
void onPrintersRemoved(in ParceledListSlice printerIds);
+
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ void onCustomPrinterIconLoaded(in PrinterId printerId, in Icon icon);
}
diff --git a/core/java/android/printservice/PrintDocument.java b/core/java/android/printservice/PrintDocument.java
index e43f2a836376..0121ae13e32f 100644
--- a/core/java/android/printservice/PrintDocument.java
+++ b/core/java/android/printservice/PrintDocument.java
@@ -16,6 +16,8 @@
package android.printservice;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.print.PrintDocumentInfo;
@@ -54,7 +56,7 @@ public final class PrintDocument {
*
* @return The document info.
*/
- public PrintDocumentInfo getInfo() {
+ public @NonNull PrintDocumentInfo getInfo() {
PrintService.throwIfNotCalledOnMainThread();
return mInfo;
}
@@ -69,7 +71,7 @@ public final class PrintDocument {
*
* @return A file descriptor for reading the data.
*/
- public ParcelFileDescriptor getData() {
+ public @Nullable ParcelFileDescriptor getData() {
PrintService.throwIfNotCalledOnMainThread();
ParcelFileDescriptor source = null;
ParcelFileDescriptor sink = null;
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 86fc292cb003..6414b6a2230c 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -344,7 +344,7 @@ public final class PrintJob {
* @return True if the tag was set, false otherwise.
*/
@MainThread
- public boolean setTag(String tag) {
+ public boolean setTag(@NonNull String tag) {
PrintService.throwIfNotCalledOnMainThread();
if (isInImmutableState()) {
return false;
@@ -364,7 +364,8 @@ public final class PrintJob {
*
* @see #setTag(String)
*/
- public String getTag() {
+ @MainThread
+ public @Nullable String getTag() {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().getTag();
}
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 6295822c7e4a..d0037b762560 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -16,6 +16,7 @@
package android.printservice;
+import android.annotation.Nullable;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
@@ -191,30 +192,29 @@ public abstract class PrintService extends Service {
/**
* If you declared an optional activity with advanced print options via the
- * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
- * attribute, this extra is used to pass in the currently constructed {@link
- * PrintJobInfo} to your activity allowing you to modify it. After you are
- * done, you must return the modified {@link PrintJobInfo} via the same extra.
+ * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity} attribute,
+ * this extra is used to pass in the currently constructed {@link PrintJobInfo} to your activity
+ * allowing you to modify it. After you are done, you must return the modified
+ * {@link PrintJobInfo} via the same extra.
* <p>
- * You cannot modify the passed in {@link PrintJobInfo} directly, rather you
- * should build another one using the {@link PrintJobInfo.Builder} class. You
- * can specify any standard properties and add advanced, printer specific,
- * ones via {@link PrintJobInfo.Builder#putAdvancedOption(String, String)
- * PrintJobInfo.Builder.putAdvancedOption(String, String)} and {@link
- * PrintJobInfo.Builder#putAdvancedOption(String, int)
- * PrintJobInfo.Builder.putAdvancedOption(String, int)}. The advanced options
- * are not interpreted by the system, they will not be visible to applications,
- * and can only be accessed by your print service via {@link
- * PrintJob#getAdvancedStringOption(String) PrintJob.getAdvancedStringOption(String)}
- * and {@link PrintJob#getAdvancedIntOption(String) PrintJob.getAdvancedIntOption(String)}.
+ * You cannot modify the passed in {@link PrintJobInfo} directly, rather you should build
+ * another one using the {@link android.print.PrintJobInfo.Builder PrintJobInfo.Builder} class.
+ * You can specify any standard properties and add advanced, printer specific, ones via
+ * {@link android.print.PrintJobInfo.Builder#putAdvancedOption(String, String)
+ * PrintJobInfo.Builder.putAdvancedOption(String, String)} and
+ * {@link android.print.PrintJobInfo.Builder#putAdvancedOption(String, int)
+ * PrintJobInfo.Builder.putAdvancedOption(String, int)}. The advanced options are not
+ * interpreted by the system, they will not be visible to applications, and can only be accessed
+ * by your print service via {@link PrintJob#getAdvancedStringOption(String)
+ * PrintJob.getAdvancedStringOption(String)} and {@link PrintJob#getAdvancedIntOption(String)
+ * PrintJob.getAdvancedIntOption(String)}.
* </p>
* <p>
- * If the advanced print options activity offers changes to the standard print
- * options, you can get the current {@link android.print.PrinterInfo} using the
- * {@link #EXTRA_PRINTER_INFO} extra which will allow you to present the user
- * with UI options supported by the current printer. For example, if the current
- * printer does not support a given media size, you should not offer it in the
- * advanced print options UI.
+ * If the advanced print options activity offers changes to the standard print options, you can
+ * get the current {@link android.print.PrinterInfo PrinterInfo} using the
+ * {@link #EXTRA_PRINTER_INFO} extra which will allow you to present the user with UI options
+ * supported by the current printer. For example, if the current printer does not support a
+ * given media size, you should not offer it in the advanced print options UI.
* </p>
*
* @see #EXTRA_PRINTER_INFO
@@ -275,9 +275,10 @@ public abstract class PrintService extends Service {
/**
* Callback asking you to create a new {@link PrinterDiscoverySession}.
*
+ * @return The created session.
* @see PrinterDiscoverySession
*/
- protected abstract PrinterDiscoverySession onCreatePrinterDiscoverySession();
+ protected abstract @Nullable PrinterDiscoverySession onCreatePrinterDiscoverySession();
/**
* Called when cancellation of a print job is requested. The service
@@ -368,6 +369,7 @@ public abstract class PrintService extends Service {
mHandler.sendEmptyMessage(ServiceHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION);
}
+ @Override
public void startPrinterDiscovery(List<PrinterId> priorityList) {
mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_DISCOVERY,
priorityList).sendToTarget();
@@ -391,6 +393,12 @@ public abstract class PrintService extends Service {
}
@Override
+ public void requestCustomPrinterIcon(PrinterId printerId) {
+ mHandler.obtainMessage(ServiceHandler.MSG_REQUEST_CUSTOM_PRINTER_ICON,
+ printerId).sendToTarget();
+ }
+
+ @Override
public void stopPrinterStateTracking(PrinterId printerId) {
mHandler.obtainMessage(ServiceHandler.MSG_STOP_PRINTER_STATE_TRACKING,
printerId).sendToTarget();
@@ -423,10 +431,11 @@ public abstract class PrintService extends Service {
public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
public static final int MSG_VALIDATE_PRINTERS = 5;
public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
- public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
- public static final int MSG_ON_PRINTJOB_QUEUED = 8;
- public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 9;
- public static final int MSG_SET_CLIENT = 10;
+ public static final int MSG_REQUEST_CUSTOM_PRINTER_ICON = 7;
+ public static final int MSG_STOP_PRINTER_STATE_TRACKING = 8;
+ public static final int MSG_ON_PRINTJOB_QUEUED = 9;
+ public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 10;
+ public static final int MSG_SET_CLIENT = 11;
public ServiceHandler(Looper looper) {
super(looper, null, true);
@@ -508,6 +517,17 @@ public abstract class PrintService extends Service {
}
} break;
+ case MSG_REQUEST_CUSTOM_PRINTER_ICON: {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "MSG_REQUEST_CUSTOM_PRINTER_ICON "
+ + getPackageName());
+ }
+ if (mDiscoverySession != null) {
+ PrinterId printerId = (PrinterId) message.obj;
+ mDiscoverySession.requestCustomPrinterIcon(printerId);
+ }
+ } break;
+
case MSG_STOP_PRINTER_STATE_TRACKING: {
if (DEBUG) {
Log.i(LOG_TAG, "MSG_STOP_PRINTER_STATE_TRACKING "
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index a2c6c09e4932..b33ef8304556 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -98,8 +98,7 @@ public final class PrintServiceInfo implements Parcelable {
*
* @param resolveInfo The service resolve info.
* @param context Context for accessing resources.
- * @throws XmlPullParserException If a XML parsing error occurs.
- * @throws IOException If a I/O error occurs.
+ * @return The created instance.
*/
public static PrintServiceInfo create(ResolveInfo resolveInfo, Context context) {
String settingsActivityName = null;
@@ -220,10 +219,12 @@ public final class PrintServiceInfo implements Parcelable {
/**
* {@inheritDoc}
*/
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel parcel, int flagz) {
parcel.writeString(mId);
parcel.writeParcelable(mResolveInfo, 0);
@@ -275,10 +276,12 @@ public final class PrintServiceInfo implements Parcelable {
public static final Parcelable.Creator<PrintServiceInfo> CREATOR =
new Parcelable.Creator<PrintServiceInfo>() {
+ @Override
public PrintServiceInfo createFromParcel(Parcel parcel) {
return new PrintServiceInfo(parcel);
}
+ @Override
public PrintServiceInfo[] newArray(int size) {
return new PrintServiceInfo[size];
}
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index 17cb68f1cfcc..cd5a903c4e69 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -16,6 +16,7 @@
package android.printservice;
+import android.annotation.NonNull;
import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
import android.print.PrinterCapabilitiesInfo;
@@ -138,7 +139,7 @@ public abstract class PrinterDiscoverySession {
* @see #removePrinters(List)
* @see #isDestroyed()
*/
- public final List<PrinterInfo> getPrinters() {
+ public final @NonNull List<PrinterInfo> getPrinters() {
PrintService.throwIfNotCalledOnMainThread();
if (mIsDestroyed) {
return Collections.emptyList();
@@ -161,7 +162,7 @@ public abstract class PrinterDiscoverySession {
* @see #getPrinters()
* @see #isDestroyed()
*/
- public final void addPrinters(List<PrinterInfo> printers) {
+ public final void addPrinters(@NonNull List<PrinterInfo> printers) {
PrintService.throwIfNotCalledOnMainThread();
// If the session is destroyed - nothing do to.
@@ -225,7 +226,7 @@ public abstract class PrinterDiscoverySession {
* @see #getPrinters()
* @see #isDestroyed()
*/
- public final void removePrinters(List<PrinterId> printerIds) {
+ public final void removePrinters(@NonNull List<PrinterId> printerIds) {
PrintService.throwIfNotCalledOnMainThread();
// If the session is destroyed - nothing do to.
@@ -350,7 +351,7 @@ public abstract class PrinterDiscoverySession {
* @see #removePrinters(List)
* @see #isPrinterDiscoveryStarted()
*/
- public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
+ public abstract void onStartPrinterDiscovery(@NonNull List<PrinterId> priorityList);
/**
* Callback notifying you that you should stop printer discovery.
@@ -372,10 +373,10 @@ public abstract class PrinterDiscoverySession {
*
* @param printerIds The printers to validate.
*
- * @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
+ * @see android.print.PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
* PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
*/
- public abstract void onValidatePrinters(List<PrinterId> printerIds);
+ public abstract void onValidatePrinters(@NonNull List<PrinterId> printerIds);
/**
* Callback asking you to start tracking the state of a printer. Tracking
@@ -400,10 +401,24 @@ public abstract class PrinterDiscoverySession {
* @param printerId The printer to start tracking.
*
* @see #onStopPrinterStateTracking(PrinterId)
- * @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
+ * @see android.print.PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
* PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
*/
- public abstract void onStartPrinterStateTracking(PrinterId printerId);
+ public abstract void onStartPrinterStateTracking(@NonNull PrinterId printerId);
+
+ /**
+ * Request the custom icon for a printer. Once the icon is available use
+ * {@link CustomPrinterIconCallback#onCustomPrinterIconLoaded} to send the data to the print
+ * service.
+ *
+ * @param printerId The printer to icon belongs to.
+ * @param callback Callback for returning the icon to the print spooler.
+ *
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
+ @NonNull CustomPrinterIconCallback callback) {
+ }
/**
* Callback asking you to stop tracking the state of a printer. The passed
@@ -414,7 +429,7 @@ public abstract class PrinterDiscoverySession {
*
* @see #onStartPrinterStateTracking(PrinterId)
*/
- public abstract void onStopPrinterStateTracking(PrinterId printerId);
+ public abstract void onStopPrinterStateTracking(@NonNull PrinterId printerId);
/**
* Gets the printers that should be tracked. These are printers that are
@@ -434,7 +449,7 @@ public abstract class PrinterDiscoverySession {
* @see #onStopPrinterStateTracking(PrinterId)
* @see #isDestroyed()
*/
- public final List<PrinterId> getTrackedPrinters() {
+ public final @NonNull List<PrinterId> getTrackedPrinters() {
PrintService.throwIfNotCalledOnMainThread();
if (mIsDestroyed) {
return Collections.emptyList();
@@ -476,7 +491,7 @@ public abstract class PrinterDiscoverySession {
return mIsDiscoveryStarted;
}
- void startPrinterDiscovery(List<PrinterId> priorityList) {
+ void startPrinterDiscovery(@NonNull List<PrinterId> priorityList) {
if (!mIsDestroyed) {
mIsDiscoveryStarted = true;
sendOutOfDiscoveryPeriodPrinterChanges();
@@ -494,13 +509,13 @@ public abstract class PrinterDiscoverySession {
}
}
- void validatePrinters(List<PrinterId> printerIds) {
+ void validatePrinters(@NonNull List<PrinterId> printerIds) {
if (!mIsDestroyed && mObserver != null) {
onValidatePrinters(printerIds);
}
}
- void startPrinterStateTracking(PrinterId printerId) {
+ void startPrinterStateTracking(@NonNull PrinterId printerId) {
if (!mIsDestroyed && mObserver != null
&& !mTrackedPrinters.contains(printerId)) {
mTrackedPrinters.add(printerId);
@@ -508,7 +523,21 @@ public abstract class PrinterDiscoverySession {
}
}
- void stopPrinterStateTracking(PrinterId printerId) {
+ /**
+ * Request the custom icon for a printer.
+ *
+ * @param printerId The printer to icon belongs to.
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ void requestCustomPrinterIcon(@NonNull PrinterId printerId) {
+ if (!mIsDestroyed && mObserver != null) {
+ CustomPrinterIconCallback callback = new CustomPrinterIconCallback(printerId,
+ mObserver);
+ onRequestCustomPrinterIcon(printerId, callback);
+ }
+ }
+
+ void stopPrinterStateTracking(@NonNull PrinterId printerId) {
if (!mIsDestroyed && mObserver != null
&& mTrackedPrinters.remove(printerId)) {
onStopPrinterStateTracking(printerId);
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 48b3c1a1b064..89ac27c9a816 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -384,8 +384,14 @@ public final class MediaStore {
public interface MediaColumns extends BaseColumns {
/**
- * The data stream for the file
- * <P>Type: DATA STREAM</P>
+ * Path to the file on disk.
+ * <p>
+ * Note that apps may not have filesystem permissions to directly access
+ * this path. Instead of trying to open this path directly, apps should
+ * use {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+ * access.
+ * <p>
+ * Type: TEXT
*/
public static final String DATA = "_data";
@@ -1149,8 +1155,15 @@ public final class MediaStore {
public static final String DEFAULT_SORT_ORDER = "image_id ASC";
/**
- * The data stream for the thumbnail
- * <P>Type: DATA STREAM</P>
+ * Path to the thumbnail file on disk.
+ * <p>
+ * Note that apps may not have filesystem permissions to directly
+ * access this path. Instead of trying to open this path directly,
+ * apps should use
+ * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+ * access.
+ * <p>
+ * Type: TEXT
*/
public static final String DATA = "_data";
@@ -1596,8 +1609,15 @@ public final class MediaStore {
public static final String NAME = "name";
/**
- * The data stream for the playlist file
- * <P>Type: DATA STREAM</P>
+ * Path to the playlist file on disk.
+ * <p>
+ * Note that apps may not have filesystem permissions to directly
+ * access this path. Instead of trying to open this path directly,
+ * apps should use
+ * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+ * access.
+ * <p>
+ * Type: TEXT
*/
public static final String DATA = "_data";
@@ -2192,8 +2212,15 @@ public final class MediaStore {
public static final String DEFAULT_SORT_ORDER = "video_id ASC";
/**
- * The data stream for the thumbnail
- * <P>Type: DATA STREAM</P>
+ * Path to the thumbnail file on disk.
+ * <p>
+ * Note that apps may not have filesystem permissions to directly
+ * access this path. Instead of trying to open this path directly,
+ * apps should use
+ * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+ * access.
+ * <p>
+ * Type: TEXT
*/
public static final String DATA = "_data";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b883f9c736d0..d0f21592dfb8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -19,6 +19,7 @@ package android.provider;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.Application;
@@ -4349,6 +4350,7 @@ public final class Settings {
* The currently selected voice interaction service flattened ComponentName.
* @hide
*/
+ @TestApi
public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
/**
@@ -6374,6 +6376,13 @@ public final class Settings {
public static final String DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES
= "force_resizable_activities";
+ /**
+ * Whether to enable experimental freeform support for windows.
+ * @hide
+ */
+ public static final String DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT
+ = "enable_freeform_support";
+
/**
* Whether user has enabled development settings.
*/
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index 46aa1af247de..37ec72589570 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -68,7 +68,6 @@ public class NetworkSecurityPolicy {
* TLS or STARTTLS) is permitted for communicating with {@code hostname} for this process.
*
* @see #isCleartextTrafficPermitted()
- * @hide
*/
public boolean isCleartextTrafficPermitted(String hostname) {
return libcore.net.NetworkSecurityPolicy.getInstance()
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java
index 71d9d5d0e04d..4de36cd2c0a9 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -120,6 +120,32 @@ public final class ApplicationConfig {
return mTrustManager;
}
+ /**
+ * Returns {@code true} if cleartext traffic is permitted for this application, which is the
+ * case only if all configurations permit cleartext traffic. For finer-grained policy use
+ * {@link #isCleartextTrafficPermitted(String)}.
+ */
+ public boolean isCleartextTrafficPermitted() {
+ ensureInitialized();
+ if (mConfigs != null) {
+ for (Pair<Domain, NetworkSecurityConfig> entry : mConfigs) {
+ if (!entry.second.isCleartextTrafficPermitted()) {
+ return false;
+ }
+ }
+ }
+
+ return mDefaultConfig.isCleartextTrafficPermitted();
+ }
+
+ /**
+ * Returns {@code true} if cleartext traffic is permitted for this application when connecting
+ * to {@code hostname}.
+ */
+ public boolean isCleartextTrafficPermitted(String hostname) {
+ return getConfigForHostname(hostname).isCleartextTrafficPermitted();
+ }
+
private void ensureInitialized() {
synchronized(mLock) {
if (mInitialized) {
diff --git a/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
new file mode 100644
index 000000000000..e7d17c27c2c9
--- /dev/null
+++ b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
@@ -0,0 +1,40 @@
+/**
+ * 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.security.net.config;
+
+/**
+ * {@link libcore.net.NetworkSecurityPolicy} based on an {@link ApplicationConfig}.
+ *
+ * @hide
+ */
+public class ConfigNetworkSecurityPolicy extends libcore.net.NetworkSecurityPolicy {
+ private final ApplicationConfig mConfig;
+
+ public ConfigNetworkSecurityPolicy(ApplicationConfig config) {
+ mConfig = config;
+ }
+
+ @Override
+ public boolean isCleartextTrafficPermitted() {
+ return mConfig.isCleartextTrafficPermitted();
+ }
+
+ @Override
+ public boolean isCleartextTrafficPermitted(String hostname) {
+ return mConfig.isCleartextTrafficPermitted(hostname);
+ }
+}
diff --git a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
index 5ebc7ac5f242..0f6687341395 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
@@ -40,5 +40,6 @@ public final class NetworkSecurityConfigProvider extends Provider {
throw new RuntimeException("Failed to install provider as highest priority provider."
+ " Provider was installed at position " + pos);
}
+ libcore.net.NetworkSecurityPolicy.setInstance(new ConfigNetworkSecurityPolicy(config));
}
}
diff --git a/core/java/android/service/notification/INotificationAssistant.aidl b/core/java/android/service/notification/INotificationAssistant.aidl
deleted file mode 100644
index 5c5f358b99b9..000000000000
--- a/core/java/android/service/notification/INotificationAssistant.aidl
+++ /dev/null
@@ -1,37 +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.service.notification;
-
-import android.service.notification.NotificationAdjustment;
-import android.service.notification.IStatusBarNotificationHolder;
-import android.service.notification.NotificationRankingUpdate;
-
-/** @hide */
-interface INotificationAssistant
-{
- void onListenerConnected(in NotificationRankingUpdate update);
- void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
- in NotificationRankingUpdate update);
- void onNotificationRankingUpdate(in NotificationRankingUpdate update);
- void onListenerHintsChanged(int hints);
- void onInterruptionFilterChanged(int interruptionFilter);
- NotificationAdjustment onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
- void onNotificationVisibilityChanged(String key, long time, boolean visible);
- void onNotificationClick(String key, long time);
- void onNotificationActionClick(String key, long time, int actionIndex);
- void onNotificationRemoved(String key, long time, int reason);
-} \ No newline at end of file
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index e6bf6ba97492..a0de17f4b7cf 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -23,6 +23,7 @@ import android.service.notification.NotificationRankingUpdate;
/** @hide */
oneway interface INotificationListener
{
+ // listeners and assistants
void onListenerConnected(in NotificationRankingUpdate update);
void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
in NotificationRankingUpdate update);
@@ -31,4 +32,11 @@ oneway interface INotificationListener
void onNotificationRankingUpdate(in NotificationRankingUpdate update);
void onListenerHintsChanged(int hints);
void onInterruptionFilterChanged(int interruptionFilter);
+
+ // assistants only
+ void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
+ void onNotificationVisibilityChanged(String key, long time, boolean visible);
+ void onNotificationClick(String key, long time);
+ void onNotificationActionClick(String key, long time, int actionIndex);
+ void onNotificationRemovedReason(String key, long time, int reason);
}
diff --git a/core/java/android/service/notification/NotificationAdjustment.java b/core/java/android/service/notification/NotificationAdjustment.java
deleted file mode 100644
index c5f0db9bf5f1..000000000000
--- a/core/java/android/service/notification/NotificationAdjustment.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package android.service.notification;
-
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class NotificationAdjustment implements Parcelable {
- int mImportance;
- CharSequence mExplanation;
- Uri mReference;
-
- /**
- * Create a notification importance adjustment.
- *
- * @param importance The final importance of the notification.
- * @param explanation A human-readable justification for the adjustment.
- * @param reference A reference to an external object that augments the
- * explanation, such as a
- * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
- * or null.
- */
- public NotificationAdjustment(int importance, CharSequence explanation, Uri reference) {
- mImportance = importance;
- mExplanation = explanation;
- mReference = reference;
- }
-
- private NotificationAdjustment(Parcel source) {
- this(source.readInt(), source.readCharSequence(),
- (Uri) source.readParcelable(NotificationAdjustment.class.getClassLoader()));
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mImportance);
- dest.writeCharSequence(mExplanation);
- dest.writeParcelable(mReference, 0);
- }
-
- public static final Parcelable.Creator<NotificationAdjustment> CREATOR
- = new Parcelable.Creator<NotificationAdjustment>() {
- @Override
- public NotificationAdjustment createFromParcel(Parcel source) {
- return new NotificationAdjustment(source);
- }
-
- @Override
- public NotificationAdjustment[] newArray(int size) {
- return new NotificationAdjustment[size];
- }
- };
-}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 7ce5e1f9da9c..3a8956ec15d9 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -20,8 +20,11 @@ import android.annotation.SdkConstant;
import android.app.Notification;
import android.content.Intent;
import android.net.Uri;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
/**
* A service that helps the user manage notifications by modifying the
@@ -39,6 +42,8 @@ import android.os.Parcelable;
* &lt;/service></pre>
*/
public abstract class NotificationAssistantService extends NotificationListenerService {
+ private static final String TAG = "NotificationAssistant";
+
/**
* The {@link Intent} that must be declared as handled by the service.
*/
@@ -85,6 +90,36 @@ 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;
+ public class Adjustment {
+ int mImportance;
+ CharSequence mExplanation;
+ Uri mReference;
+
+ /**
+ * Create a notification importance adjustment.
+ *
+ * @param importance The final importance of the notification.
+ * @param explanation A human-readable justification for the adjustment.
+ * @param reference A reference to an external object that augments the
+ * explanation, such as a
+ * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
+ * or null.
+ */
+ public Adjustment(int importance, CharSequence explanation, Uri reference) {
+ mImportance = importance;
+ mExplanation = explanation;
+ mReference = reference;
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (mWrapper == null) {
+ mWrapper = new NotificationAssistantWrapper();
+ }
+ return mWrapper;
+ }
+
/**
* A notification was posted by an app. Called before alert.
*
@@ -93,7 +128,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS
* @param user true if the initial importance reflects an explicit user preference.
* @return an adjustment or null to take no action, within 100ms.
*/
- abstract public NotificationAdjustment onNotificationEnqueued(StatusBarNotification sbn,
+ abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
int importance, boolean user);
/**
@@ -150,9 +185,15 @@ public abstract class NotificationAssistantService extends NotificationListenerS
* @param key the notification key
* @param adjustment the new importance with an explanation
*/
- public final void adjustImportance(String key, NotificationAdjustment adjustment)
+ public final void adjustImportance(String key, Adjustment adjustment)
{
- // TODO: pack up the adjustment and send it to the NotificationManager.
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().setImportanceFromAssistant(mWrapper, key,
+ adjustment.mImportance, adjustment.mExplanation);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
}
/**
@@ -160,7 +201,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS
* be fired when the host notification is deleted, or when this annotation
* is removed or replaced.
*
- * @param key the notification key
+ * @param key the key of the notification to be annotated
* @param annotation the new annotation object
*/
public final void setAnnotation(String key, Notification annotation)
@@ -171,10 +212,74 @@ public abstract class NotificationAssistantService extends NotificationListenerS
/**
* Remove the annotation from a notification.
*
- * @param key the notification key
+ * @param key the key of the notification to be cleansed of annotatons
*/
public final void clearAnnotation(String key)
{
// TODO: ask the NotificationManager to clear the annotation.
}
+
+ private class NotificationAssistantWrapper extends NotificationListenerWrapper {
+ @Override
+ public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
+ int importance, boolean user) throws RemoteException {
+ StatusBarNotification sbn;
+ try {
+ sbn = sbnHolder.get();
+ } catch (RemoteException e) {
+ Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
+ return;
+ }
+
+ try {
+ Adjustment adjustment =
+ NotificationAssistantService.this.onNotificationEnqueued(sbn, importance, user);
+ if (adjustment != null) {
+ adjustImportance(sbn.getKey(), adjustment);
+ }
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onNotificationEnqueued", t);
+ }
+ }
+
+ @Override
+ public void onNotificationVisibilityChanged(String key, long time, boolean visible)
+ throws RemoteException {
+ try {
+ NotificationAssistantService.this.onNotificationVisibilityChanged(key, time,
+ visible);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onNotificationVisibilityChanged", t);
+ }
+ }
+
+ @Override
+ public void onNotificationClick(String key, long time) throws RemoteException {
+ try {
+ NotificationAssistantService.this.onNotificationClick(key, time);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onNotificationClick", t);
+ }
+ }
+
+ @Override
+ public void onNotificationActionClick(String key, long time, int actionIndex)
+ throws RemoteException {
+ try {
+ NotificationAssistantService.this.onNotificationActionClick(key, time, actionIndex);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onNotificationActionClick", t);
+ }
+ }
+
+ @Override
+ public void onNotificationRemovedReason(String key, long time, int reason)
+ throws RemoteException {
+ try {
+ NotificationAssistantService.this.onNotificationRemoved(key, time, reason);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onNotificationRemoved", t);
+ }
+ }
+ }
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 1e62edc6634f..b42d9eaf9cb5 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -15,6 +15,7 @@
*/
package android.service.notification;
+import android.service.notification.IStatusBarNotificationHolder;
import android.annotation.SystemApi;
import android.annotation.SdkConstant;
@@ -122,6 +123,8 @@ public abstract class NotificationListenerService extends Service {
NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
public static final int SUPPRESSED_EFFECT_PEEK =
NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+ public static final int SUPPRESSED_EFFECT_SCREEN_ON =
+ NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
/**
* The full trim of the StatusBarNotification including all its features.
@@ -151,7 +154,8 @@ public abstract class NotificationListenerService extends Service {
@SystemApi
public static final int TRIM_LIGHT = 1;
- private INotificationListenerWrapper mWrapper = null;
+ /** @hide */
+ protected NotificationListenerWrapper mWrapper = null;
private RankingMap mRankingMap;
private INotificationManager mNoMan;
@@ -291,7 +295,8 @@ public abstract class NotificationListenerService extends Service {
// optional
}
- private final INotificationManager getNotificationInterface() {
+ /** @hide */
+ protected final INotificationManager getNotificationInterface() {
if (mNoMan == null) {
mNoMan = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
@@ -634,12 +639,13 @@ public abstract class NotificationListenerService extends Service {
@Override
public IBinder onBind(Intent intent) {
if (mWrapper == null) {
- mWrapper = new INotificationListenerWrapper();
+ mWrapper = new NotificationListenerWrapper();
}
return mWrapper;
}
- private boolean isBound() {
+ /** @hide */
+ protected boolean isBound() {
if (mWrapper == null) {
Log.w(TAG, "Notification listener service not yet bound.");
return false;
@@ -664,7 +670,7 @@ public abstract class NotificationListenerService extends Service {
int currentUser) throws RemoteException {
mSystemContext = context;
if (mWrapper == null) {
- mWrapper = new INotificationListenerWrapper();
+ mWrapper = new NotificationListenerWrapper();
}
INotificationManager noMan = getNotificationInterface();
noMan.registerListener(mWrapper, componentName, currentUser);
@@ -716,7 +722,8 @@ public abstract class NotificationListenerService extends Service {
}
}
- private class INotificationListenerWrapper extends INotificationListener.Stub {
+ /** @hide */
+ protected class NotificationListenerWrapper extends INotificationListener.Stub {
@Override
public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
NotificationRankingUpdate update) {
@@ -817,6 +824,35 @@ public abstract class NotificationListenerService extends Service {
Log.w(TAG, "Error running onInterruptionFilterChanged", t);
}
}
+
+ @Override
+ public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder,
+ int importance, boolean user) throws RemoteException {
+ // no-op in the listener
+ }
+
+ @Override
+ public void onNotificationVisibilityChanged(String key, long time, boolean visible)
+ throws RemoteException {
+ // no-op in the listener
+ }
+
+ @Override
+ public void onNotificationClick(String key, long time) throws RemoteException {
+ // no-op in the listener
+ }
+
+ @Override
+ public void onNotificationActionClick(String key, long time, int actionIndex)
+ throws RemoteException {
+ // no-op in the listener
+ }
+
+ @Override
+ public void onNotificationRemovedReason(String key, long time, int reason)
+ throws RemoteException {
+ // no-op in the listener
+ }
}
private void applyUpdate(NotificationRankingUpdate update) {
@@ -927,7 +963,8 @@ public abstract class NotificationListenerService extends Service {
/**
* Returns the type(s) of visual effects that should be suppressed for this notification.
- * See {@link #SUPPRESSED_EFFECT_LIGHTS}, {@link #SUPPRESSED_EFFECT_PEEK}}.
+ * See {@link #SUPPRESSED_EFFECT_LIGHTS}, {@link #SUPPRESSED_EFFECT_PEEK},
+ * {@link #SUPPRESSED_EFFECT_SCREEN_ON}.
*/
public int getSuppressedVisualEffects() {
return mSuppressedVisualEffects;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 541623d736f1..468884347fc5 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -79,6 +79,7 @@ public class ZenModeConfig implements Parcelable {
private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
private static final boolean DEFAULT_ALLOW_PEEK = true;
private static final boolean DEFAULT_ALLOW_LIGHTS = true;
+ private static final boolean DEFAULT_ALLOW_SCREEN_ON = true;
private static final int XML_VERSION = 2;
private static final String ZEN_TAG = "zen";
@@ -95,6 +96,7 @@ public class ZenModeConfig implements Parcelable {
private static final String ALLOW_ATT_EVENTS = "events";
private static final String ALLOW_ATT_PEEK = "peek";
private static final String ALLOW_ATT_LIGHTS = "lights";
+ private static final String ALLOW_ATT_SCREEN_ON = "screen_on";
private static final String CONDITION_TAG = "condition";
private static final String CONDITION_ATT_COMPONENT = "component";
@@ -128,6 +130,7 @@ public class ZenModeConfig implements Parcelable {
public int user = UserHandle.USER_SYSTEM;
public boolean allowPeek = DEFAULT_ALLOW_PEEK;
public boolean allowLights = DEFAULT_ALLOW_LIGHTS;
+ public boolean allowScreenOn = DEFAULT_ALLOW_SCREEN_ON;
public ZenRule manualRule;
public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
@@ -156,6 +159,7 @@ public class ZenModeConfig implements Parcelable {
}
allowPeek = source.readInt() == 1;
allowLights = source.readInt() == 1;
+ allowScreenOn = source.readInt() == 1;
}
@Override
@@ -185,6 +189,7 @@ public class ZenModeConfig implements Parcelable {
}
dest.writeInt(allowPeek ? 1 : 0);
dest.writeInt(allowLights ? 1 : 0);
+ dest.writeInt(allowScreenOn ? 1 : 0);
}
@Override
@@ -200,6 +205,7 @@ public class ZenModeConfig implements Parcelable {
.append(",allowEvents=").append(allowEvents)
.append(",allowPeek=").append(allowPeek)
.append(",allowLights=").append(allowLights)
+ .append(",allowScreenOn=").append(allowScreenOn)
.append(",automaticRules=").append(automaticRules)
.append(",manualRule=").append(manualRule)
.append(']').toString();
@@ -240,6 +246,9 @@ public class ZenModeConfig implements Parcelable {
if (allowLights != to.allowLights) {
d.addLine("allowLights", allowLights, to.allowLights);
}
+ if (allowScreenOn != to.allowScreenOn) {
+ d.addLine("allowScreenOn", allowScreenOn, to.allowScreenOn);
+ }
final ArraySet<String> allRules = new ArraySet<>();
addKeys(allRules, automaticRules);
addKeys(allRules, to.automaticRules);
@@ -339,6 +348,7 @@ public class ZenModeConfig implements Parcelable {
&& other.allowEvents == allowEvents
&& other.allowPeek == allowPeek
&& other.allowLights == allowLights
+ && other.allowScreenOn == allowScreenOn
&& other.user == user
&& Objects.equals(other.automaticRules, automaticRules)
&& Objects.equals(other.manualRule, manualRule);
@@ -348,7 +358,7 @@ public class ZenModeConfig implements Parcelable {
public int hashCode() {
return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowCallsFrom,
allowMessagesFrom, allowReminders, allowEvents, allowPeek, allowLights,
- user, automaticRules, manualRule);
+ allowScreenOn, user, automaticRules, manualRule);
}
private static String toDayList(int[] days) {
@@ -435,6 +445,8 @@ public class ZenModeConfig implements Parcelable {
}
rt.allowPeek = safeBoolean(parser, ALLOW_ATT_PEEK, DEFAULT_ALLOW_PEEK);
rt.allowLights = safeBoolean(parser, ALLOW_ATT_LIGHTS, DEFAULT_ALLOW_LIGHTS);
+ rt.allowScreenOn =
+ safeBoolean(parser, ALLOW_ATT_SCREEN_ON, DEFAULT_ALLOW_SCREEN_ON);
} else if (MANUAL_TAG.equals(tag)) {
rt.manualRule = readRuleXml(parser);
} else if (AUTOMATIC_TAG.equals(tag)) {
@@ -465,6 +477,7 @@ public class ZenModeConfig implements Parcelable {
out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom));
out.attribute(null, ALLOW_ATT_PEEK, Boolean.toString(allowPeek));
out.attribute(null, ALLOW_ATT_LIGHTS, Boolean.toString(allowLights));
+ out.attribute(null, ALLOW_ATT_SCREEN_ON, Boolean.toString(allowScreenOn));
out.endTag(null, ALLOW_TAG);
if (manualRule != null) {
@@ -643,6 +656,9 @@ public class ZenModeConfig implements Parcelable {
if (!allowLights) {
suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
}
+ if (!allowScreenOn) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+ }
priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders);
priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders);
return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders,
@@ -681,6 +697,8 @@ public class ZenModeConfig implements Parcelable {
if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
allowPeek = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) == 0;
allowLights = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) == 0;
+ allowScreenOn =
+ (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_SCREEN_ON) == 0;
}
}
diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl
index 7e70501de39b..75da82fc43c0 100644
--- a/core/java/android/service/quicksettings/IQSService.aidl
+++ b/core/java/android/service/quicksettings/IQSService.aidl
@@ -24,4 +24,5 @@ import android.service.quicksettings.Tile;
interface IQSService {
void updateQsTile(in Tile tile);
void onShowDialog(in Tile tile);
+ void setTileMode(in ComponentName component, int mode);
}
diff --git a/core/java/android/service/quicksettings/IQSTileService.aidl b/core/java/android/service/quicksettings/IQSTileService.aidl
index 63a4c5e30df9..4997f754d2a7 100644
--- a/core/java/android/service/quicksettings/IQSTileService.aidl
+++ b/core/java/android/service/quicksettings/IQSTileService.aidl
@@ -22,6 +22,7 @@ import android.service.quicksettings.IQSService;
* @hide
*/
oneway interface IQSTileService {
+ void setQSService(in IQSService service);
void setQSTile(in Tile tile);
void onTileAdded();
void onTileRemoved();
diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java
index a53fc59d362c..6104913642f8 100644
--- a/core/java/android/service/quicksettings/Tile.java
+++ b/core/java/android/service/quicksettings/Tile.java
@@ -37,11 +37,12 @@ public final class Tile implements Parcelable {
private static final String TAG = "Tile";
private ComponentName mComponentName;
- private IQSService mService;
private Icon mIcon;
private CharSequence mLabel;
private CharSequence mContentDescription;
+ private IQSService mService;
+
/**
* @hide
*/
@@ -52,8 +53,14 @@ public final class Tile implements Parcelable {
/**
* @hide
*/
- public Tile(ComponentName componentName, IQSService service) {
+ public Tile(ComponentName componentName) {
mComponentName = componentName;
+ }
+
+ /**
+ * @hide
+ */
+ public void setService(IQSService service) {
mService = service;
}
@@ -65,6 +72,13 @@ public final class Tile implements Parcelable {
}
/**
+ * @hide
+ */
+ public IQSService getQsService() {
+ return mService;
+ }
+
+ /**
* Gets the current icon for the tile.
*/
public Icon getIcon() {
@@ -137,21 +151,8 @@ public final class Tile implements Parcelable {
}
}
- /**
- * @hide
- * Notifies the IQSService that this tile is showing a dialog.
- */
- void onShowDialog() {
- try {
- mService.onShowDialog(this);
- } catch (RemoteException e) {
- Log.e(TAG, "Couldn't onShowDialog");
- }
- }
-
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeStrongInterface(mService);
if (mComponentName != null) {
dest.writeByte((byte) 1);
mComponentName.writeToParcel(dest, flags);
@@ -169,7 +170,6 @@ public final class Tile implements Parcelable {
}
private void readFromParcel(Parcel source) {
- mService = IQSService.Stub.asInterface(source.readStrongBinder());
if (source.readByte() != 0) {
mComponentName = ComponentName.CREATOR.createFromParcel(source);
} else {
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index d8787b4caca7..9b50ef5e1a38 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -15,8 +15,11 @@
*/
package android.service.quicksettings;
+import android.Manifest;
import android.app.Dialog;
import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
@@ -26,29 +29,29 @@ import android.os.RemoteException;
import android.view.WindowManager;
/**
- * A QSTileService provides the user a tile that can be added to Quick Settings.
+ * A TileService provides the user a tile that can be added to Quick Settings.
* Quick Settings is a space provided that allows the user to change settings and
* take quick actions without leaving the context of their current app.
*
- * <p>The lifecycle of a QSTileService is different from some other services in
+ * <p>The lifecycle of a TileService is different from some other services in
* that it may be unbound during parts of its lifecycle. Any of the following
* lifecycle events can happen indepently in a separate binding/creation of the
* service.</p>
*
* <ul>
- * <li>When a tile is added by the user its QSTileService will be bound to and
+ * <li>When a tile is added by the user its TileService will be bound to and
* {@link #onTileAdded()} will be called.</li>
*
* <li>When a tile should be up to date and listing will be indicated by
* {@link #onStartListening()} and {@link #onStopListening()}.</li>
*
- * <li>When the user removes a tile from Quick Settings {@link #onStopListening()}
+ * <li>When the user removes a tile from Quick Settings {@link #onTileRemoved()}
* will be called.</li>
* </ul>
- * <p>QSTileService will be detected by tiles that match the {@value #ACTION_QS_TILE}
+ * <p>TileService will be detected by tiles that match the {@value #ACTION_QS_TILE}
* and require the permission "android.permission.BIND_QUICK_SETTINGS_TILE".
* The label and icon for the service will be used as the default label and
- * icon for the tile. Here is an example QSTileService declaration.</p>
+ * icon for the tile. Here is an example TileService declaration.</p>
* <pre class="prettyprint">
* {@literal
* <service
@@ -67,15 +70,52 @@ import android.view.WindowManager;
public class TileService extends Service {
/**
- * Action that identifies a Service as being a QSTileService.
+ * Action that identifies a Service as being a TileService.
*/
public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ /**
+ * The tile mode hasn't been set yet.
+ * @hide
+ */
+ public static final int TILE_MODE_UNSET = 0;
+
+ /**
+ * Constant to be returned by {@link #onTileAdded}.
+ * <p>
+ * Passive mode is the default mode for tiles. The System will tell the tile
+ * when it is most important to update by putting it in the listening state.
+ */
+ public static final int TILE_MODE_PASSIVE = 1;
+
+ /**
+ * Constant to be returned by {@link #onTileAdded}.
+ * <p>
+ * Active mode is for tiles which already listen and keep track of their state in their
+ * own process. These tiles may request to send an update to the System while their process
+ * is alive using {@link #requestListeningState}. The System will only bind these tiles
+ * on its own when a click needs to occur.
+ */
+ public static final int TILE_MODE_ACTIVE = 2;
+
+ /**
+ * Used to notify SysUI that Listening has be requested.
+ * @hide
+ */
+ public static final String ACTION_REQUEST_LISTENING
+ = "android.service.quicksettings.action.REQUEST_LISTENING";
+
+ /**
+ * @hide
+ */
+ public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
+
private final H mHandler = new H(Looper.getMainLooper());
private boolean mListening = false;
private Tile mTile;
private IBinder mToken;
+ private IQSService mService;
@Override
public void onDestroy() {
@@ -92,8 +132,12 @@ public class TileService extends Service {
* Note that this is not guaranteed to be called between {@link #onCreate()}
* and {@link #onStartListening()}, it will only be called when the tile is added
* and not on subsequent binds.
+ *
+ * @see #TILE_MODE_PASSIVE
+ * @see #TILE_MODE_ACTIVE
*/
- public void onTileAdded() {
+ public int onTileAdded() {
+ return TILE_MODE_PASSIVE;
}
/**
@@ -138,7 +182,10 @@ public class TileService extends Service {
dialog.getWindow().getAttributes().token = mToken;
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_QS_DIALOG);
dialog.show();
- getQsTile().onShowDialog();
+ try {
+ mService.onShowDialog(mTile);
+ } catch (RemoteException e) {
+ }
}
/**
@@ -156,6 +203,11 @@ public class TileService extends Service {
public IBinder onBind(Intent intent) {
return new IQSTileService.Stub() {
@Override
+ public void setQSService(IQSService service) throws RemoteException {
+ mHandler.obtainMessage(H.MSG_SET_SERVICE, service).sendToTarget();
+ }
+
+ @Override
public void setQSTile(Tile tile) throws RemoteException {
mHandler.obtainMessage(H.MSG_SET_TILE, tile).sendToTarget();
}
@@ -194,6 +246,7 @@ public class TileService extends Service {
private static final int MSG_TILE_ADDED = 4;
private static final int MSG_TILE_REMOVED = 5;
private static final int MSG_TILE_CLICKED = 6;
+ private static final int MSG_SET_SERVICE = 7;
public H(Looper looper) {
super(looper);
@@ -202,13 +255,34 @@ public class TileService extends Service {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
+ case MSG_SET_SERVICE:
+ mService = (IQSService) msg.obj;
+ if (mTile != null) {
+ mTile.setService(mService);
+ }
+ break;
case MSG_SET_TILE:
mTile = (Tile) msg.obj;
+ if (mService != null && mTile != null) {
+ mTile.setService(mService);
+ }
break;
case MSG_TILE_ADDED:
- TileService.this.onTileAdded();
+ int mode = TileService.this.onTileAdded();
+ if (mService == null) {
+ return;
+ }
+ try {
+ mService.setTileMode(new ComponentName(TileService.this,
+ TileService.this.getClass()), mode);
+ } catch (RemoteException e) {
+ }
break;
case MSG_TILE_REMOVED:
+ if (mListening) {
+ mListening = false;
+ TileService.this.onStopListening();
+ }
TileService.this.onTileRemoved();
break;
case MSG_STOP_LISTENING:
@@ -230,4 +304,16 @@ public class TileService extends Service {
}
}
}
+
+ /**
+ * Requests that a tile be put in the listening state so it can send an update.
+ *
+ * This method is only applicable to tiles that return {@link #TILE_MODE_ACTIVE} from
+ * {@link #onTileAdded()}, and will do nothing otherwise.
+ */
+ public static final void requestListeningState(Context context, ComponentName component) {
+ Intent intent = new Intent(ACTION_REQUEST_LISTENING);
+ intent.putExtra(EXTRA_COMPONENT, component);
+ context.sendBroadcast(intent, Manifest.permission.BIND_QUICK_SETTINGS_TILE);
+ }
}
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index c1192776ed4f..fbd992466f5f 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -218,7 +218,7 @@ public class Linkify {
ArrayList<LinkSpec> links = new ArrayList<LinkSpec>();
if ((mask & WEB_URLS) != 0) {
- gatherLinks(links, text, Patterns.WEB_URL,
+ gatherLinks(links, text, Patterns.AUTOLINK_WEB_URL,
new String[] { "http://", "https://", "rtsp://" },
sUrlMatchFilter, null);
}
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index 1becfb4a0e23..f22cde0c1ca7 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -28,12 +28,6 @@ import com.android.internal.annotations.GuardedBy;
import java.util.HashSet;
import java.util.Locale;
-// TODO: We don't except too many LocaleLists to exist at the same time, and
-// we need access to the data at native level, so we should pass the data
-// down to the native level, create a map of every list seen there, take a
-// pointer back, and just keep that pointer in the Java-level object, so
-// things could be copied very quickly.
-
/**
* LocaleList is an immutable list of Locales, typically used to keep an
* ordered user preferences for locales.
@@ -219,6 +213,20 @@ public final class LocaleList implements Parcelable {
}
}
+ private static final String STRING_EN_XA = "en-XA";
+ private static final String STRING_AR_XB = "ar-XB";
+ private static final Locale LOCALE_EN_XA = new Locale("en", "XA");
+ private static final Locale LOCALE_AR_XB = new Locale("ar", "XB");
+ private static final int NUM_PSEUDO_LOCALES = 2;
+
+ private static boolean isPseudoLocale(String locale) {
+ return STRING_EN_XA.equals(locale) || STRING_AR_XB.equals(locale);
+ }
+
+ private static boolean isPseudoLocale(Locale locale) {
+ return LOCALE_EN_XA.equals(locale) || LOCALE_AR_XB.equals(locale);
+ }
+
private static int matchScore(Locale supported, Locale desired) {
if (supported.equals(desired)) {
return 1; // return early so we don't do unnecessary computation
@@ -226,6 +234,11 @@ public final class LocaleList implements Parcelable {
if (!supported.getLanguage().equals(desired.getLanguage())) {
return 0;
}
+ if (isPseudoLocale(supported) || isPseudoLocale(desired)) {
+ // The locales are not the same, but the languages are the same, and one of the locales
+ // is a pseudo-locale. So this is not a match.
+ return 0;
+ }
// There is no match if the two locales use different scripts. This will most imporantly
// take care of traditional vs simplified Chinese.
final String supportedScr = getLikelyScript(supported);
@@ -233,24 +246,26 @@ public final class LocaleList implements Parcelable {
return supportedScr.equals(desiredScr) ? 1 : 0;
}
- /**
- * Returns the first match in the locale list given an unordered array of supported locales
- * in BCP47 format.
- *
- * If the locale list is empty, null would be returned.
- */
- @Nullable
- public Locale getFirstMatch(String[] supportedLocales) {
+ private static final Locale EN_LATN = Locale.forLanguageTag("en-Latn");
+
+ private Locale computeFirstMatch(String[] supportedLocales, boolean assumeEnglishIsSupported) {
if (mList.length == 1) { // just one locale, perhaps the most common scenario
return mList[0];
}
if (mList.length == 0) { // empty locale list
return null;
}
- // TODO: Figure out what to if en-XA or ar-XB are in the locale list
int bestIndex = Integer.MAX_VALUE;
- for (String tag : supportedLocales) {
- final Locale supportedLocale = Locale.forLanguageTag(tag);
+ final int numSupportedLocales =
+ supportedLocales.length + (assumeEnglishIsSupported ? 1 : 0);
+ for (int i = 0; i < numSupportedLocales; i++) {
+ final Locale supportedLocale;
+ if (assumeEnglishIsSupported) {
+ // Try English first, so we can return early if it's in the LocaleList
+ supportedLocale = (i == 0) ? EN_LATN : Locale.forLanguageTag(supportedLocales[i-1]);
+ } else {
+ supportedLocale = Locale.forLanguageTag(supportedLocales[i]);
+ }
// We expect the average length of locale lists used for locale resolution to be
// smaller than three, so it's OK to do this as an O(mn) algorithm.
for (int idx = 0; idx < mList.length; idx++) {
@@ -271,6 +286,47 @@ public final class LocaleList implements Parcelable {
}
}
+ /**
+ * Returns the first match in the locale list given an unordered array of supported locales
+ * in BCP47 format.
+ *
+ * If the locale list is empty, null would be returned.
+ */
+ @Nullable
+ public Locale getFirstMatch(String[] supportedLocales) {
+ return computeFirstMatch(supportedLocales, false /* assume English is not supported */);
+ }
+
+ /**
+ * Same as getFirstMatch(), but with English assumed to be supported, even if it's not.
+ * {@hide}
+ */
+ @Nullable
+ public Locale getFirstMatchWithEnglishSupported(String[] supportedLocales) {
+ return computeFirstMatch(supportedLocales, true /* assume English is supported */);
+ }
+
+ /**
+ * Returns true if the array of locale tags only contains empty locales and pseudolocales.
+ * Assumes that there is no repetition in the input.
+ * {@hide}
+ */
+ public static boolean isPseudoLocalesOnly(String[] supportedLocales) {
+ if (supportedLocales.length > NUM_PSEUDO_LOCALES + 1) {
+ // This is for optimization. Since there's no repetition in the input, if we have more
+ // than the number of pseudo-locales plus one for the empty string, it's guaranteed
+ // that we have some meaninful locale in the list, so the list is not "practically
+ // empty".
+ return false;
+ }
+ for (String locale : supportedLocales) {
+ if (!locale.isEmpty() && !isPseudoLocale(locale)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private final static Object sLock = new Object();
@GuardedBy("sLock")
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index f17a16c066f0..78d5bcd90624 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -82,6 +82,10 @@ public class PathParser {
}
}
+ public long getNativePtr() {
+ return mNativePathData;
+ }
+
/**
* Update the path data to match the source.
* Before calling this, make sure canMorph(target, source) is true.
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 2cc91b9dfe97..9f2bcfd3a136 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -109,11 +109,137 @@ public class Patterns {
+ "|z[amw]))";
/**
- * Good characters for Internationalized Resource Identifiers (IRI).
- * This comprises most common used Unicode characters allowed in IRI
- * as detailed in RFC 3987.
- * Specifically, those two byte Unicode characters are not included.
+ * Regular expression to match all IANA top-level domains.
+ *
+ * List accurate as of 2015/11/24. List taken from:
+ * http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+ * This pattern is auto-generated by frameworks/ex/common/tools/make-iana-tld-pattern.py
+ *
+ * @hide
*/
+ static final String IANA_TOP_LEVEL_DOMAINS =
+ "(?:"
+ + "(?:aaa|aarp|abb|abbott|abogado|academy|accenture|accountant|accountants|aco|active"
+ + "|actor|ads|adult|aeg|aero|afl|agency|aig|airforce|airtel|allfinanz|alsace|amica|amsterdam"
+ + "|android|apartments|app|apple|aquarelle|aramco|archi|army|arpa|arte|asia|associates"
+ + "|attorney|auction|audio|auto|autos|axa|azure|a[cdefgilmoqrstuwxz])"
+ + "|(?:band|bank|bar|barcelona|barclaycard|barclays|bargains|bauhaus|bayern|bbc|bbva"
+ + "|bcn|beats|beer|bentley|berlin|best|bet|bharti|bible|bid|bike|bing|bingo|bio|biz|black"
+ + "|blackfriday|bloomberg|blue|bms|bmw|bnl|bnpparibas|boats|bom|bond|boo|boots|boutique"
+ + "|bradesco|bridgestone|broadway|broker|brother|brussels|budapest|build|builders|business"
+ + "|buzz|bzh|b[abdefghijmnorstvwyz])"
+ + "|(?:cab|cafe|cal|camera|camp|cancerresearch|canon|capetown|capital|car|caravan|cards"
+ + "|care|career|careers|cars|cartier|casa|cash|casino|cat|catering|cba|cbn|ceb|center|ceo"
+ + "|cern|cfa|cfd|chanel|channel|chat|cheap|chloe|christmas|chrome|church|cipriani|cisco"
+ + "|citic|city|cityeats|claims|cleaning|click|clinic|clothing|cloud|club|clubmed|coach"
+ + "|codes|coffee|college|cologne|com|commbank|community|company|computer|comsec|condos"
+ + "|construction|consulting|contractors|cooking|cool|coop|corsica|country|coupons|courses"
+ + "|credit|creditcard|creditunion|cricket|crown|crs|cruises|csc|cuisinella|cymru|cyou|c[acdfghiklmnoruvwxyz])"
+ + "|(?:dabur|dad|dance|date|dating|datsun|day|dclk|deals|degree|delivery|dell|delta"
+ + "|democrat|dental|dentist|desi|design|dev|diamonds|diet|digital|direct|directory|discount"
+ + "|dnp|docs|dog|doha|domains|doosan|download|drive|durban|dvag|d[ejkmoz])"
+ + "|(?:earth|eat|edu|education|email|emerck|energy|engineer|engineering|enterprises"
+ + "|epson|equipment|erni|esq|estate|eurovision|eus|events|everbank|exchange|expert|exposed"
+ + "|express|e[cegrstu])"
+ + "|(?:fage|fail|fairwinds|faith|family|fan|fans|farm|fashion|feedback|ferrero|film"
+ + "|final|finance|financial|firmdale|fish|fishing|fit|fitness|flights|florist|flowers|flsmidth"
+ + "|fly|foo|football|forex|forsale|forum|foundation|frl|frogans|fund|furniture|futbol|fyi"
+ + "|f[ijkmor])"
+ + "|(?:gal|gallery|game|garden|gbiz|gdn|gea|gent|genting|ggee|gift|gifts|gives|giving"
+ + "|glass|gle|global|globo|gmail|gmo|gmx|gold|goldpoint|golf|goo|goog|google|gop|gov|grainger"
+ + "|graphics|gratis|green|gripe|group|gucci|guge|guide|guitars|guru|g[abdefghilmnpqrstuwy])"
+ + "|(?:hamburg|hangout|haus|healthcare|help|here|hermes|hiphop|hitachi|hiv|hockey|holdings"
+ + "|holiday|homedepot|homes|honda|horse|host|hosting|hoteles|hotmail|house|how|hsbc|hyundai"
+ + "|h[kmnrtu])"
+ + "|(?:ibm|icbc|ice|icu|ifm|iinet|immo|immobilien|industries|infiniti|info|ing|ink|institute"
+ + "|insure|int|international|investments|ipiranga|irish|ist|istanbul|itau|iwc|i[delmnoqrst])"
+ + "|(?:jaguar|java|jcb|jetzt|jewelry|jlc|jll|jobs|joburg|jprs|juegos|j[emop])"
+ + "|(?:kaufen|kddi|kia|kim|kinder|kitchen|kiwi|koeln|komatsu|krd|kred|kyoto|k[eghimnprwyz])"
+ + "|(?:lacaixa|lancaster|land|landrover|lasalle|lat|latrobe|law|lawyer|lds|lease|leclerc"
+ + "|legal|lexus|lgbt|liaison|lidl|life|lifestyle|lighting|limited|limo|linde|link|live"
+ + "|lixil|loan|loans|lol|london|lotte|lotto|love|ltd|ltda|lupin|luxe|luxury|l[abcikrstuvy])"
+ + "|(?:madrid|maif|maison|man|management|mango|market|marketing|markets|marriott|mba"
+ + "|media|meet|melbourne|meme|memorial|men|menu|meo|miami|microsoft|mil|mini|mma|mobi|moda"
+ + "|moe|moi|mom|monash|money|montblanc|mormon|mortgage|moscow|motorcycles|mov|movie|movistar"
+ + "|mtn|mtpc|mtr|museum|mutuelle|m[acdeghklmnopqrstuvwxyz])"
+ + "|(?:nadex|nagoya|name|navy|nec|net|netbank|network|neustar|new|news|nexus|ngo|nhk"
+ + "|nico|ninja|nissan|nokia|nra|nrw|ntt|nyc|n[acefgilopruz])"
+ + "|(?:obi|office|okinawa|omega|one|ong|onl|online|ooo|oracle|orange|org|organic|osaka"
+ + "|otsuka|ovh|om)"
+ + "|(?:page|panerai|paris|partners|parts|party|pet|pharmacy|philips|photo|photography"
+ + "|photos|physio|piaget|pics|pictet|pictures|ping|pink|pizza|place|play|playstation|plumbing"
+ + "|plus|pohl|poker|porn|post|praxi|press|pro|prod|productions|prof|properties|property"
+ + "|protection|pub|p[aefghklmnrstwy])"
+ + "|(?:qpon|quebec|qa)"
+ + "|(?:racing|realtor|realty|recipes|red|redstone|rehab|reise|reisen|reit|ren|rent|rentals"
+ + "|repair|report|republican|rest|restaurant|review|reviews|rich|ricoh|rio|rip|rocher|rocks"
+ + "|rodeo|rsvp|ruhr|run|rwe|ryukyu|r[eosuw])"
+ + "|(?:saarland|sakura|sale|samsung|sandvik|sandvikcoromant|sanofi|sap|sapo|sarl|saxo"
+ + "|sbs|sca|scb|schmidt|scholarships|school|schule|schwarz|science|scor|scot|seat|security"
+ + "|seek|sener|services|seven|sew|sex|sexy|shiksha|shoes|show|shriram|singles|site|ski"
+ + "|sky|skype|sncf|soccer|social|software|sohu|solar|solutions|sony|soy|space|spiegel|spreadbetting"
+ + "|srl|stada|starhub|statoil|stc|stcgroup|stockholm|studio|study|style|sucks|supplies"
+ + "|supply|support|surf|surgery|suzuki|swatch|swiss|sydney|systems|s[abcdeghijklmnortuvxyz])"
+ + "|(?:tab|taipei|tatamotors|tatar|tattoo|tax|taxi|team|tech|technology|tel|telefonica"
+ + "|temasek|tennis|thd|theater|theatre|tickets|tienda|tips|tires|tirol|today|tokyo|tools"
+ + "|top|toray|toshiba|tours|town|toyota|toys|trade|trading|training|travel|trust|tui|t[cdfghjklmnortvwz])"
+ + "|(?:ubs|university|uno|uol|u[agksyz])"
+ + "|(?:vacations|vana|vegas|ventures|versicherung|vet|viajes|video|villas|vin|virgin"
+ + "|vision|vista|vistaprint|viva|vlaanderen|vodka|vote|voting|voto|voyage|v[aceginu])"
+ + "|(?:wales|walter|wang|watch|webcam|website|wed|wedding|weir|whoswho|wien|wiki|williamhill"
+ + "|win|windows|wine|wme|work|works|world|wtc|wtf|w[fs])"
+ + "|(?:\u03b5\u03bb|\u0431\u0435\u043b|\u0434\u0435\u0442\u0438|\u043a\u043e\u043c|\u043c\u043a\u0434"
+ + "|\u043c\u043e\u043d|\u043c\u043e\u0441\u043a\u0432\u0430|\u043e\u043d\u043b\u0430\u0439\u043d"
+ + "|\u043e\u0440\u0433|\u0440\u0443\u0441|\u0440\u0444|\u0441\u0430\u0439\u0442|\u0441\u0440\u0431"
+ + "|\u0443\u043a\u0440|\u049b\u0430\u0437|\u0570\u0561\u0575|\u05e7\u05d5\u05dd|\u0627\u0631\u0627\u0645\u0643\u0648"
+ + "|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629"
+ + "|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0627\u06cc\u0631\u0627\u0646"
+ + "|\u0628\u0627\u0632\u0627\u0631|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633"
+ + "|\u0633\u0648\u062f\u0627\u0646|\u0633\u0648\u0631\u064a\u0629|\u0634\u0628\u0643\u0629"
+ + "|\u0639\u0631\u0627\u0642|\u0639\u0645\u0627\u0646|\u0641\u0644\u0633\u0637\u064a\u0646"
+ + "|\u0642\u0637\u0631|\u0643\u0648\u0645|\u0645\u0635\u0631|\u0645\u0644\u064a\u0633\u064a\u0627"
+ + "|\u0645\u0648\u0642\u0639|\u0915\u0949\u092e|\u0928\u0947\u091f|\u092d\u093e\u0930\u0924"
+ + "|\u0938\u0902\u0917\u0920\u0928|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4"
+ + "|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd"
+ + "|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e04\u0e2d\u0e21|\u0e44\u0e17\u0e22"
+ + "|\u10d2\u10d4|\u307f\u3093\u306a|\u30b0\u30fc\u30b0\u30eb|\u30b3\u30e0|\u4e16\u754c"
+ + "|\u4e2d\u4fe1|\u4e2d\u56fd|\u4e2d\u570b|\u4e2d\u6587\u7f51|\u4f01\u4e1a|\u4f5b\u5c71"
+ + "|\u4fe1\u606f|\u5065\u5eb7|\u516b\u5366|\u516c\u53f8|\u516c\u76ca|\u53f0\u6e7e|\u53f0\u7063"
+ + "|\u5546\u57ce|\u5546\u5e97|\u5546\u6807|\u5728\u7ebf|\u5927\u62ff|\u5a31\u4e50|\u5de5\u884c"
+ + "|\u5e7f\u4e1c|\u6148\u5584|\u6211\u7231\u4f60|\u624b\u673a|\u653f\u52a1|\u653f\u5e9c"
+ + "|\u65b0\u52a0\u5761|\u65b0\u95fb|\u65f6\u5c1a|\u673a\u6784|\u6de1\u9a6c\u9521|\u6e38\u620f"
+ + "|\u70b9\u770b|\u79fb\u52a8|\u7ec4\u7ec7\u673a\u6784|\u7f51\u5740|\u7f51\u5e97|\u7f51\u7edc"
+ + "|\u8c37\u6b4c|\u96c6\u56e2|\u98de\u5229\u6d66|\u9910\u5385|\u9999\u6e2f|\ub2f7\ub137"
+ + "|\ub2f7\ucef4|\uc0bc\uc131|\ud55c\uad6d|xbox"
+ + "|xerox|xin|xn\\-\\-11b4c3d|xn\\-\\-1qqw23a|xn\\-\\-30rr7y|xn\\-\\-3bst00m|xn\\-\\-3ds443g"
+ + "|xn\\-\\-3e0b707e|xn\\-\\-3pxu8k|xn\\-\\-42c2d9a|xn\\-\\-45brj9c|xn\\-\\-45q11c|xn\\-\\-4gbrim"
+ + "|xn\\-\\-55qw42g|xn\\-\\-55qx5d|xn\\-\\-6frz82g|xn\\-\\-6qq986b3xl|xn\\-\\-80adxhks"
+ + "|xn\\-\\-80ao21a|xn\\-\\-80asehdb|xn\\-\\-80aswg|xn\\-\\-90a3ac|xn\\-\\-90ais|xn\\-\\-9dbq2a"
+ + "|xn\\-\\-9et52u|xn\\-\\-b4w605ferd|xn\\-\\-c1avg|xn\\-\\-c2br7g|xn\\-\\-cg4bki|xn\\-\\-clchc0ea0b2g2a9gcd"
+ + "|xn\\-\\-czr694b|xn\\-\\-czrs0t|xn\\-\\-czru2d|xn\\-\\-d1acj3b|xn\\-\\-d1alf|xn\\-\\-efvy88h"
+ + "|xn\\-\\-estv75g|xn\\-\\-fhbei|xn\\-\\-fiq228c5hs|xn\\-\\-fiq64b|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s"
+ + "|xn\\-\\-fjq720a|xn\\-\\-flw351e|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-gecrj9c"
+ + "|xn\\-\\-h2brj9c|xn\\-\\-hxt814e|xn\\-\\-i1b6b1a6a2e|xn\\-\\-imr513n|xn\\-\\-io0a7i"
+ + "|xn\\-\\-j1aef|xn\\-\\-j1amh|xn\\-\\-j6w193g|xn\\-\\-kcrx77d1x4a|xn\\-\\-kprw13d|xn\\-\\-kpry57d"
+ + "|xn\\-\\-kput3i|xn\\-\\-l1acc|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgb9awbf|xn\\-\\-mgba3a3ejt"
+ + "|xn\\-\\-mgba3a4f16a|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbab2bd|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e"
+ + "|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-mgbpl2fh|xn\\-\\-mgbtx2b|xn\\-\\-mgbx4cd0ab"
+ + "|xn\\-\\-mk1bu44c|xn\\-\\-mxtq1m|xn\\-\\-ngbc5azd|xn\\-\\-node|xn\\-\\-nqv7f|xn\\-\\-nqv7fs00ema"
+ + "|xn\\-\\-nyqy26a|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1acf|xn\\-\\-p1ai|xn\\-\\-pgbs0dh"
+ + "|xn\\-\\-pssy2u|xn\\-\\-q9jyb4c|xn\\-\\-qcka1pmc|xn\\-\\-qxam|xn\\-\\-rhqv96g|xn\\-\\-s9brj9c"
+ + "|xn\\-\\-ses554g|xn\\-\\-t60b56a|xn\\-\\-tckwe|xn\\-\\-unup4y|xn\\-\\-vermgensberater\\-ctb"
+ + "|xn\\-\\-vermgensberatung\\-pwb|xn\\-\\-vhquv|xn\\-\\-vuq861b|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a"
+ + "|xn\\-\\-xhq521b|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-y9a3aq|xn\\-\\-yfro4i67o"
+ + "|xn\\-\\-ygbi2ammx|xn\\-\\-zfr164b|xperia|xxx|xyz)"
+ + "|(?:yachts|yamaxun|yandex|yodobashi|yoga|yokohama|youtube|y[et])"
+ + "|(?:zara|zip|zone|zuerich|z[amw]))";
+
+ /**
+ * Kept for backward compatibility reasons.
+ *
+ * @deprecated Deprecated since it does not include all IRI characters defined in RFC 3987
+ */
+ @Deprecated
public static final String GOOD_IRI_CHAR =
"a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
@@ -125,35 +251,148 @@ public class Patterns {
+ "|[1-9][0-9]|[0-9]))");
/**
+ * Valid UCS characters defined in RFC 3987.
+ */
+ private static final String UCS_CHAR =
+ "\u00A0-\uD7FF" +
+ "\uF900-\uFDCF" +
+ "\uFDF0-\uFFEF" +
+ "\uD800\uDC00-\uD83F\uDFFD" +
+ "\uD840\uDC00-\uD87F\uDFFD" +
+ "\uD880\uDC00-\uD8BF\uDFFD" +
+ "\uD8C0\uDC00-\uD8FF\uDFFD" +
+ "\uD900\uDC00-\uD93F\uDFFD" +
+ "\uD940\uDC00-\uD97F\uDFFD" +
+ "\uD980\uDC00-\uD9BF\uDFFD" +
+ "\uD9C0\uDC00-\uD9FF\uDFFD" +
+ "\uDA00\uDC00-\uDA3F\uDFFD" +
+ "\uDA40\uDC00-\uDA7F\uDFFD" +
+ "\uDA80\uDC00-\uDABF\uDFFD" +
+ "\uDAC0\uDC00-\uDAFF\uDFFD" +
+ "\uDB00\uDC00-\uDB3F\uDFFD" +
+ "\uDB44\uDC00-\uDB7F\uDFFD";
+
+ /**
+ * Valid characters for IRI label defined in RFC 3987.
+ */
+ private static final String LABEL_CHAR = "a-zA-Z0-9" + UCS_CHAR;
+
+ /**
+ * Valid characters for IRI TLD defined in RFC 3987.
+ */
+ private static final String TLD_CHAR = "a-zA-Z" + UCS_CHAR;
+
+ /**
* RFC 1035 Section 2.3.4 limits the labels to a maximum 63 octets.
*/
- private static final String IRI
- = "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}";
+ private static final String IRI_LABEL =
+ "[" + LABEL_CHAR + "](?:[" + LABEL_CHAR + "\\-]{0,61}[" + LABEL_CHAR + "]){0,1}";
- private static final String GOOD_GTLD_CHAR =
- "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
- private static final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}";
- private static final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD;
+ /**
+ * RFC 3492 references RFC 1034 and limits Punycode algorithm output to 63 characters.
+ */
+ private static final String PUNYCODE_TLD = "xn\\-\\-[\\w\\-]{0,58}\\w";
+
+ private static final String TLD = "(" + PUNYCODE_TLD + "|" + "[" + TLD_CHAR + "]{2,63}" +")";
+
+ private static final String HOST_NAME = "(" + IRI_LABEL + "\\.)+" + TLD;
public static final Pattern DOMAIN_NAME
= Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")");
+ private static final String PROTOCOL = "(?i:http|https|rtsp):\\/\\/";
+
+ /* A word boundary or end of input. This is to stop foo.sure from matching as foo.su */
+ private static final String WORD_BOUNDARY = "(?:\\b|$|^)";
+
+ private static final String USER_INFO = "(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+ + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+ + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@";
+
+ private static final String PORT_NUMBER = "\\:\\d{1,5}";
+
+ private static final String PATH_AND_QUERY = "\\/(?:(?:[" + LABEL_CHAR
+ + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus optional query params
+ + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*";
+
/**
* Regular expression pattern to match most part of RFC 3987
- * Internationalized URLs, aka IRIs. Commonly used Unicode characters are
- * added.
- */
- public static final Pattern WEB_URL = Pattern.compile(
- "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
- + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
- + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
- + "(?:" + DOMAIN_NAME + ")"
- + "(?:\\:\\d{1,5})?)" // plus option port number
- + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params
- + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
- + "(?:\\b|$)"); // and finally, a word boundary or end of
- // input. This is to stop foo.sure from
- // matching as foo.su
+ * Internationalized URLs, aka IRIs.
+ */
+ public static final Pattern WEB_URL = Pattern.compile("("
+ + "("
+ + "(?:" + PROTOCOL + "(?:" + USER_INFO + ")?" + ")?"
+ + "(?:" + DOMAIN_NAME + ")"
+ + "(?:" + PORT_NUMBER + ")?"
+ + ")"
+ + "(" + PATH_AND_QUERY + ")?"
+ + WORD_BOUNDARY
+ + ")");
+
+ /**
+ * Regular expression that matches known TLDs and punycode TLDs
+ */
+ private static final String STRICT_TLD = "(?:" +
+ IANA_TOP_LEVEL_DOMAINS + "|" + PUNYCODE_TLD + ")";
+
+ /**
+ * Regular expression that matches host names using {@link #STRICT_TLD}
+ */
+ private static final String STRICT_HOST_NAME = "(?:(?:" + IRI_LABEL + "\\.)+"
+ + STRICT_TLD + ")";
+
+ /**
+ * Regular expression that matches domain names using either {@link #STRICT_HOST_NAME} or
+ * {@link #IP_ADDRESS}
+ */
+ private static final Pattern STRICT_DOMAIN_NAME
+ = Pattern.compile("(?:" + STRICT_HOST_NAME + "|" + IP_ADDRESS + ")");
+
+ /**
+ * Regular expression that matches domain names without a TLD
+ */
+ private static final String RELAXED_DOMAIN_NAME =
+ "(?:" + "(?:" + IRI_LABEL + "(?:\\.(?=\\S))" +"?)+" + "|" + IP_ADDRESS + ")";
+
+ /**
+ * Regular expression to match strings that do not start with a supported protocol. The TLDs
+ * are expected to be one of the known TLDs.
+ */
+ private static final String WEB_URL_WITHOUT_PROTOCOL = "("
+ + WORD_BOUNDARY
+ + "(?<!:\\/\\/)"
+ + "("
+ + "(?:" + STRICT_DOMAIN_NAME + ")"
+ + "(?:" + PORT_NUMBER + ")?"
+ + ")"
+ + "(?:" + PATH_AND_QUERY + ")?"
+ + WORD_BOUNDARY
+ + ")";
+
+ /**
+ * Regular expression to match strings that start with a supported protocol. Rules for domain
+ * names and TLDs are more relaxed. TLDs are optional.
+ */
+ private static final String WEB_URL_WITH_PROTOCOL = "("
+ + WORD_BOUNDARY
+ + "(?:"
+ + "(?:" + PROTOCOL + "(?:" + USER_INFO + ")?" + ")"
+ + "(?:" + RELAXED_DOMAIN_NAME + ")?"
+ + "(?:" + PORT_NUMBER + ")?"
+ + ")"
+ + "(?:" + PATH_AND_QUERY + ")?"
+ + WORD_BOUNDARY
+ + ")";
+
+ /**
+ * Regular expression pattern to match IRIs. If a string starts with http(s):// the expression
+ * tries to match the URL structure with a relaxed rule for TLDs. If the string does not start
+ * with http(s):// the TLDs are expected to be one of the known TLDs.
+ *
+ * @hide
+ */
+ public static final Pattern AUTOLINK_WEB_URL = Pattern.compile(
+ "(" + WEB_URL_WITH_PROTOCOL + "|" + WEB_URL_WITHOUT_PROTOCOL + ")");
public static final Pattern EMAIL_ADDRESS
= Pattern.compile(
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 5903d4a7c444..71db0b51b0bf 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -364,20 +364,9 @@ public class DragEvent implements Parcelable {
return mClipDescription;
}
- /**
- * Requests the permissions for the content URIs contained in {@link android.content.ClipData}
- * object associated with this event. Which permissions will be granted is defined by the set of
- * flags passed to {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)}.
- * Returns the {@link DropPermissions} object that can be used by the receiving app to release
- * the permissions for the content URIs when they are no longer needed.
- * This method only returns valid data if the event action is {@link #ACTION_DROP}.
- * @return The DropPermissions object used to control access to the content URIs.
- */
- public DropPermissions requestDropPermissions() {
- if (mDropPermissions == null) {
- return null;
- }
- return new DropPermissions(mDropPermissions);
+ /** @hide */
+ public IDropPermissions getDropPermissions() {
+ return mDropPermissions;
}
/**
diff --git a/core/java/android/view/DropPermissions.java b/core/java/android/view/DropPermissions.java
index 780461fe69a3..8c948a9ab4ae 100644
--- a/core/java/android/view/DropPermissions.java
+++ b/core/java/android/view/DropPermissions.java
@@ -16,11 +16,27 @@
package android.view;
+import android.os.IBinder;
import android.os.RemoteException;
import com.android.internal.view.IDropPermissions;
import dalvik.system.CloseGuard;
+/**
+ * {@link DropPermissions} controls the access permissions for the content URIs associated with a
+ * {@link DragEvent}.
+ * <p>
+ * Permission are granted when this object is created by {@link
+ * android.app.Activity#requestDropPermissions(DragEvent) Activity.requestDropPermissions}.
+ * Which permissions are granted is defined by the set of flags passed to {@link
+ * View#startDragAndDrop(android.content.ClipData, View.DragShadowBuilder, Object, int)
+ * View.startDragAndDrop} by the app that started the drag operation.
+ * <p>
+ * The life cycle of the permissions is bound to the activity used to call {@link
+ * android.app.Activity#requestDropPermissions(DragEvent) requestDropPermissions}. The
+ * permissions are revoked when this activity is destroyed, or when {@link #release()} is called,
+ * whichever occurs first.
+ */
public final class DropPermissions {
private final IDropPermissions mDropPermissions;
@@ -28,21 +44,43 @@ public final class DropPermissions {
private final CloseGuard mCloseGuard = CloseGuard.get();
/**
- * Create a new DropPermissions object to be passed to the client with a DragEvent.
- *
+ * Create a new {@link DropPermissions} object to control the access permissions for content
+ * URIs associated with {@link DragEvent}.
+ * @param dragEvent Drag event
+ * @return {@link DropPermissions} object or null if there are no content URIs associated with
+ * the {@link DragEvent}.
* @hide
*/
- DropPermissions(IDropPermissions dropPermissions) {
+ public static DropPermissions obtain(DragEvent dragEvent) {
+ if (dragEvent.getDropPermissions() == null) {
+ return null;
+ }
+ return new DropPermissions(dragEvent.getDropPermissions());
+ }
+
+ /** @hide */
+ private DropPermissions(IDropPermissions dropPermissions) {
mDropPermissions = dropPermissions;
+ }
+
+ /**
+ * Take the permissions and bind their lifetime to the activity.
+ * @param activityToken Binder pointing to an Activity instance to bind the lifetime to.
+ * @return True if permissions are successfully taken.
+ * @hide
+ */
+ public boolean take(IBinder activityToken) {
try {
- mDropPermissions.take();
+ mDropPermissions.take(activityToken);
} catch (RemoteException e) {
+ return false;
}
mCloseGuard.open("release");
+ return true;
}
/**
- * Revoke permissions taken by {@link DragEvent#requestDropPermissions()}.
+ * Revoke permissions explicitly.
*/
public void release() {
try {
diff --git a/core/java/android/view/IDockDividerVisibilityListener.aidl b/core/java/android/view/IDockedStackListener.aidl
index a7d5cda9b44f..77fa7e25f9df 100644
--- a/core/java/android/view/IDockDividerVisibilityListener.aidl
+++ b/core/java/android/view/IDockedStackListener.aidl
@@ -22,6 +22,15 @@ package android.view;
*
* @hide
*/
-oneway interface IDockDividerVisibilityListener {
- void onDockDividerVisibilityChanged(boolean visible);
+oneway interface IDockedStackListener {
+
+ /**
+ * Will fire when an app is shown in side by side mode and a divider should be shown.
+ */
+ void onDividerVisibilityChanged(boolean visible);
+
+ /**
+ * Called when the docked stack gets created or removed.
+ */
+ void onDockedStackExistsChanged(boolean exists);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7a379d50ba05..84d312d59b64 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -29,7 +29,7 @@ import android.os.Bundle;
import android.os.IRemoteCallback;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
import android.view.IWindowSession;
@@ -101,11 +101,14 @@ interface IWindowManager
* the task doesn't exist yet.
* @param configuration Configuration that is being used with this task.
* @param cropWindowsToStack True if the app windows should be cropped to the stack bounds.
+ * @param alwaysFocusable True if the app windows are always focusable regardless of the stack
+ * they are in.
*/
void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- in Rect taskBounds, in Configuration configuration, boolean cropWindowsToStack);
+ in Rect taskBounds, in Configuration configuration, boolean cropWindowsToStack,
+ boolean alwaysFocusable);
/**
*
* @param token The token we are adding to the input task Id.
@@ -354,7 +357,17 @@ interface IWindowManager
void setDockedStackResizing(boolean resizing);
/**
- * Registers a listener that will be called when the dock divider changes its visibility.
+ * Registers a listener that will be called when the dock divider changes its visibility or when
+ * the docked stack gets added/removed.
*/
- void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener);
+ void registerDockedStackListener(IDockedStackListener listener);
+
+ /**
+ * Updates the dim layer used while resizing.
+ *
+ * @param visible Whether the dim layer should be visible.
+ * @param targetStackId The id of the task stack the dim layer should be placed on.
+ * @param alpha The translucency of the dim layer, between 0 and 1.
+ */
+ void setResizeDimLayer(boolean visible, int targetStackId, float alpha);
}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index aa29636398e4..914bd5684b4a 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -555,6 +555,26 @@ public abstract class LayoutInflater {
}
}
+ private static final ClassLoader BOOT_CLASS_LOADER = LayoutInflater.class.getClassLoader();
+
+ private final boolean verifyClassLoader(Constructor<? extends View> constructor) {
+ final ClassLoader constructorLoader = constructor.getDeclaringClass().getClassLoader();
+ if (constructorLoader == BOOT_CLASS_LOADER) {
+ // fast path for boot class loader (most common case?) - always ok
+ return true;
+ }
+ // in all normal cases (no dynamic code loading), we will exit the following loop on the
+ // first iteration (i.e. when the declaring classloader is the contexts class loader).
+ ClassLoader cl = mContext.getClassLoader();
+ do {
+ if (constructorLoader == cl) {
+ return true;
+ }
+ cl = cl.getParent();
+ } while (cl != null);
+ return false;
+ }
+
/**
* Low-level function for instantiating a view by name. This attempts to
* instantiate a view class of the given <var>name</var> found in this
@@ -575,6 +595,10 @@ public abstract class LayoutInflater {
public final View createView(String name, String prefix, AttributeSet attrs)
throws ClassNotFoundException, InflateException {
Constructor<? extends View> constructor = sConstructorMap.get(name);
+ if (constructor != null && !verifyClassLoader(constructor)) {
+ constructor = null;
+ sConstructorMap.remove(name);
+ }
Class<? extends View> clazz = null;
try {
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 394660fb538b..ef50fdc5eb4f 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -57,6 +57,7 @@ public class Surface implements Parcelable {
private static native int nativeGetHeight(long nativeObject);
private static native long nativeGetNextFrameNumber(long nativeObject);
+ private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
public static final Parcelable.Creator<Surface> CREATOR =
new Parcelable.Creator<Surface>() {
@@ -95,6 +96,21 @@ public class Surface implements Parcelable {
private HwuiContext mHwuiContext;
/** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
+ SCALING_MODE_SCALE_CROP, SCALING_MODE_NO_SCALE_CROP})
+ public @interface ScalingMode {}
+ // From system/window.h
+ /** @hide */
+ static final int SCALING_MODE_FREEZE = 0;
+ /** @hide */
+ static final int SCALING_MODE_SCALE_TO_WINDOW = 1;
+ /** @hide */
+ static final int SCALING_MODE_SCALE_CROP = 2;
+ /** @hide */
+ static final int SCALING_MODE_NO_SCALE_CROP = 3;
+
+ /** @hide */
@IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
@Retention(RetentionPolicy.SOURCE)
public @interface Rotation {}
@@ -500,6 +516,20 @@ public class Surface implements Parcelable {
}
/**
+ * Set the scaling mode to be used for this surfaces buffers
+ * @hide
+ */
+ void setScalingMode(@ScalingMode int scalingMode) {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ int err = nativeSetScalingMode(mNativeObject, scalingMode);
+ if (err != 0) {
+ throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode);
+ }
+ }
+ }
+
+ /**
* Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
* when a SurfaceTexture could not successfully be allocated.
*/
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 589c0dc85b68..f4fa98029be7 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -578,8 +578,19 @@ public class SurfaceView extends View {
}
mSurface.transferFrom(mNewSurface);
-
if (visible && mSurface.isValid()) {
+ // We set SCALING_MODE_NO_SCALE_CROP to allow the WindowManager
+ // to update our Surface crop without requiring a new buffer from
+ // us. In the default mode of SCALING_MODE_FREEZE, surface geometry
+ // state (which includes crop) is only applied when a buffer
+ // with appropriate geometry is available. During drag resize
+ // it is quite frequent that a matching buffer will not be available
+ // (because we are constantly being resized and have fallen behind).
+ // However in such situations the WindowManager still needs to be able
+ // to update our crop to ensure we stay within the bounds of the containing
+ // window.
+ mSurface.setScalingMode(Surface.SCALING_MODE_NO_SCALE_CROP);
+
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
mIsCreating = true;
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 6b60be9c91b5..1be4810779da 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -297,7 +297,7 @@ public class TextureView extends View {
@Override
public void setForeground(Drawable foreground) {
- if (foreground != null) {
+ if (foreground != null && !sTextureViewIgnoresDrawableSetters) {
throw new UnsupportedOperationException(
"TextureView doesn't support displaying a foreground drawable");
}
@@ -305,7 +305,7 @@ public class TextureView extends View {
@Override
public void setBackgroundDrawable(Drawable background) {
- if (background != null) {
+ if (background != null && !sTextureViewIgnoresDrawableSetters) {
throw new UnsupportedOperationException(
"TextureView doesn't support displaying a background drawable");
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 537f887305ee..3a1e9ab2cac3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -812,6 +812,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private static boolean sLayoutParamsAlwaysChanged = false;
/**
+ * Allow setForeground/setBackground to be called (and ignored) on a textureview,
+ * without throwing
+ */
+ static boolean sTextureViewIgnoresDrawableSetters = false;
+
+ /**
* This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
* calling setFlags.
*/
@@ -3984,6 +3990,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// work. Partial layout breaks this assumption.
sLayoutParamsAlwaysChanged = targetSdkVersion <= M;
+ // Prior to N, TextureView would silently ignore calls to setBackground/setForeground.
+ // On N+, we throw, but that breaks compatibility with apps that use these methods.
+ sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M;
+
sCompatibilityDone = true;
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index cd93dab0c48b..1c243929fa49 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1419,8 +1419,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
case DragEvent.ACTION_DRAG_ENDED: {
// Release the bookkeeping now that the drag lifecycle has ended
- if (mChildrenInterestedInDrag != null) {
- for (View child : mChildrenInterestedInDrag) {
+ final HashSet<View> childrenInterestedInDrag = mChildrenInterestedInDrag;
+ if (childrenInterestedInDrag != null) {
+ for (View child : childrenInterestedInDrag) {
// If a child was interested in the ongoing drag, it's told that it's over
if (child.dispatchDragEvent(event)) {
retval = true;
@@ -1428,12 +1429,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
child.mPrivateFlags2 &= ~View.DRAG_MASK;
child.refreshDrawableState();
}
-
- mChildrenInterestedInDrag.clear();
- if (mCurrentDragStartEvent != null) {
- mCurrentDragStartEvent.recycle();
- mCurrentDragStartEvent = null;
- }
+ childrenInterestedInDrag.clear();
+ }
+ if (mCurrentDragStartEvent != null) {
+ mCurrentDragStartEvent.recycle();
+ mCurrentDragStartEvent = null;
}
if (mIsInterestedInDrag) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f2b4fb3a042f..1c9f3b403ef8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3315,6 +3315,7 @@ public final class ViewRootImpl implements ViewParent,
&& mPendingStableInsets.equals(args.arg6)
&& mPendingVisibleInsets.equals(args.arg3)
&& mPendingOutsets.equals(args.arg7)
+ && mPendingBackDropFrame.equals(args.arg8)
&& args.arg4 == null) {
break;
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 19e290b71a97..7e981939034b 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1467,10 +1467,14 @@ public class PopupWindow {
}
if (mClipToScreen) {
+ final int winOffsetX = mScreenLocation[0] - mDrawingLocation[0];
+ final int winOffsetY = mScreenLocation[1] - mDrawingLocation[1];
+ p.x += winOffsetX;
+ p.y += winOffsetY;
final int displayFrameWidth = displayFrame.right - displayFrame.left;
final int right = p.x + p.width;
- if (right > displayFrameWidth) {
- p.x -= right - displayFrameWidth;
+ if (right > displayFrame.right) {
+ p.x -= right - displayFrame.right;
}
if (p.x < displayFrame.left) {
@@ -1479,10 +1483,9 @@ public class PopupWindow {
}
if (mOverlapAnchor) {
- final int displayFrameHeight = displayFrame.bottom - displayFrame.top;
final int bottom = p.y + p.height;
if (bottom > displayFrame.bottom) {
- p.y -= bottom - displayFrameHeight;
+ p.y -= bottom - displayFrame.bottom;
}
} else {
if (onTop) {
@@ -1494,6 +1497,8 @@ public class PopupWindow {
p.y = Math.max(p.y, displayFrame.top);
}
}
+ p.x -= winOffsetX;
+ p.y -= winOffsetY;
}
p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 4efefa943947..6a365e0a6927 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -28,6 +28,7 @@ import android.content.res.Resources;
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.Settings;
+import android.util.LocaleList;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -45,6 +46,7 @@ import java.util.ArrayList;
public class LocalePicker extends ListFragment {
private static final String TAG = "LocalePicker";
private static final boolean DEBUG = false;
+ private static final String[] pseudoLocales = { "en-XA", "ar-XB" };
public static interface LocaleSelectionListener {
// You can add any argument if you really need it...
@@ -57,7 +59,7 @@ public class LocalePicker extends ListFragment {
static final Collator sCollator = Collator.getInstance();
String label;
- Locale locale;
+ final Locale locale;
public LocaleInfo(String label, Locale locale) {
this.label = label;
@@ -83,17 +85,30 @@ public class LocalePicker extends ListFragment {
}
}
+ public static String[] getSystemAssetLocales() {
+ return Resources.getSystem().getAssets().getLocales();
+ }
+
+ public static String[] getSupportedLocales(Context context) {
+ return context.getResources().getStringArray(R.array.supported_locales);
+ }
+
+ public static String[] getPseudoLocales() {
+ return pseudoLocales;
+ }
+
public static List<LocaleInfo> getAllAssetLocales(Context context, boolean isInDeveloperMode) {
final Resources resources = context.getResources();
- final String[] locales = Resources.getSystem().getAssets().getLocales();
+ final String[] locales = getSystemAssetLocales();
List<String> localeList = new ArrayList<String>(locales.length);
Collections.addAll(localeList, locales);
// Don't show the pseudolocales unless we're in developer mode. http://b/17190407.
if (!isInDeveloperMode) {
- localeList.remove("ar-XB");
- localeList.remove("en-XA");
+ for (String locale : pseudoLocales) {
+ localeList.remove(locale);
+ }
}
Collections.sort(localeList);
@@ -240,13 +255,24 @@ public class LocalePicker extends ListFragment {
/**
* Requests the system to update the system locale. Note that the system looks halted
* for a while during the Locale migration, so the caller need to take care of it.
+ *
+ * @see #updateLocales(LocaleList)
*/
public static void updateLocale(Locale locale) {
+ updateLocales(new LocaleList(locale));
+ }
+
+ /**
+ * Requests the system to update the list of system locales.
+ * Note that the system looks halted for a while during the Locale migration,
+ * so the caller need to take care of it.
+ */
+ public static void updateLocales(LocaleList locales) {
try {
- IActivityManager am = ActivityManagerNative.getDefault();
- Configuration config = am.getConfiguration();
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ final Configuration config = am.getConfiguration();
- config.setLocale(locale);
+ config.setLocales(locales);
config.userSetLocale = true;
am.updateConfiguration(config);
@@ -256,4 +282,19 @@ public class LocalePicker extends ListFragment {
// Intentionally left blank
}
}
+
+ /**
+ * Get the locale list.
+ *
+ * @return The locale list.
+ */
+ public static LocaleList getLocales() {
+ try {
+ return ActivityManagerNative.getDefault()
+ .getConfiguration().getLocales();
+ } catch (RemoteException e) {
+ // If something went wrong
+ return LocaleList.getDefault();
+ }
+ }
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ba0912a5536a..aa38de737484 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -718,9 +718,9 @@ public class ResolverActivity extends Activity {
if (ri.handleAllWebDataURI) {
// Set default Browser if needed
- final String packageName = pm.getDefaultBrowserPackageName(userId);
+ final String packageName = pm.getDefaultBrowserPackageNameAsUser(userId);
if (TextUtils.isEmpty(packageName)) {
- pm.setDefaultBrowserPackageName(ri.activityInfo.packageName, userId);
+ pm.setDefaultBrowserPackageNameAsUser(ri.activityInfo.packageName, userId);
}
} else {
// Update Domain Verification status
@@ -737,7 +737,7 @@ public class ResolverActivity extends Activity {
categories.contains(Intent.CATEGORY_BROWSABLE);
if (isHttpOrHttps && isViewAction && hasCategoryBrowsable) {
- pm.updateIntentVerificationStatus(packageName,
+ pm.updateIntentVerificationStatusAsUser(packageName,
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
userId);
}
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 4b6e7e4a03d2..575ef0293361 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -483,6 +483,12 @@ public class ToolbarActionBar extends ActionBar {
return true;
}
+ @Override
+ public void onDestroy() {
+ // Remove any invalidation callbacks
+ mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator);
+ }
+
public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
mMenuVisibilityListeners.add(listener);
}
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index bfc56dbed61a..4b821abec6fb 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -36,6 +36,8 @@ public class MetricsLogger implements MetricsConstants {
public static final int NOTIFICATION_TOPIC_NOTIFICATION = 263;
public static final int ACTION_DEFAULT_SMS_APP_CHANGED = 264;
public static final int QS_COLOR_MATRIX = 265;
+ public static final int QS_CUSTOM = 266;
+ public static final int ACTION_ZEN_ALLOW_SCREEN_ON = 267;
/**
* Logged when the user docks a window from recents by longpressing a task and dragging it to
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 8e318a22750e..4a1f7f490a6d 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -534,7 +534,7 @@ public class ZygoteInit {
String args[] = {
"--setuid=1000",
"--setgid=1000",
- "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009",
+ "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 2d8bfd4e73d9..2f951ccb8bbe 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -146,6 +146,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;
+ // Whether the client has explicitly set the content view. If false and mContentParent is not
+ // null, then the content parent was set due to window preservation.
+ private boolean mContentParentExplicitlySet = false;
Callback2 mTakeSurfaceCallback;
@@ -274,6 +277,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private int mDecorCaptionShade = DECOR_CAPTION_SHADE_AUTO;
+ private boolean mUseDecorContext = false;
+
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
@@ -286,8 +291,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mLayoutInflater = LayoutInflater.from(context);
}
+ /**
+ * Constructor for main window of an activity.
+ */
public PhoneWindow(Context context, Window preservedWindow) {
this(context);
+ // Only main activity windows use decor context, all the other windows depend on whatever
+ // context that was given to them.
+ mUseDecorContext = true;
if (preservedWindow != null) {
mDecor = (DecorView) preservedWindow.getDecorView();
mElevation = preservedWindow.getElevation();
@@ -307,7 +318,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public boolean requestFeature(int featureId) {
- if (mContentParent != null) {
+ if (mContentParentExplicitlySet) {
throw new AndroidRuntimeException("requestFeature() must be called before adding content");
}
final int features = getFeatures();
@@ -391,6 +402,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
+ mContentParentExplicitlySet = true;
}
@Override
@@ -421,6 +433,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
+ mContentParentExplicitlySet = true;
}
@Override
@@ -2259,15 +2272,19 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// System process doesn't have application context and in that case we need to directly use
// the context we have. Otherwise we want the application context, so we don't cling to the
// activity.
- Context applicationContext = getContext().getApplicationContext();
Context context;
- if (applicationContext == null) {
- context = getContext();
- } else {
- context = new DecorContext(applicationContext);
- if (mTheme != -1) {
- context.setTheme(mTheme);
+ if (mUseDecorContext) {
+ Context applicationContext = getContext().getApplicationContext();
+ if (applicationContext == null) {
+ context = getContext();
+ } else {
+ context = new DecorContext(applicationContext);
+ if (mTheme != -1) {
+ context.setTheme(mTheme);
+ }
}
+ } else {
+ context = getContext();
}
return new DecorView(context, featureId, this);
}
diff --git a/core/java/com/android/internal/view/IDropPermissions.aidl b/core/java/com/android/internal/view/IDropPermissions.aidl
index 86d27e7c6f1f..2438bdaed135 100644
--- a/core/java/com/android/internal/view/IDropPermissions.aidl
+++ b/core/java/com/android/internal/view/IDropPermissions.aidl
@@ -16,11 +16,13 @@
package com.android.internal.view;
+import android.os.IBinder;
+
/**
* Interface to allow a drop receiver to request permissions for URIs passed along with ClipData
* contained in DragEvent.
*/
interface IDropPermissions {
- void take();
+ void take(IBinder activityToken);
void release();
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index bc3ac5ff426b..30593f2eb67e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -49,6 +49,7 @@ LOCAL_SRC_FILES:= \
android_database_SQLiteConnection.cpp \
android_database_SQLiteGlobal.cpp \
android_database_SQLiteDebug.cpp \
+ android_graphics_drawable_VectorDrawable.cpp \
android_view_DisplayEventReceiver.cpp \
android_view_DisplayListCanvas.cpp \
android_view_GraphicBuffer.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c44a62c08020..63f193d57419 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -130,6 +130,7 @@ extern int register_android_graphics_Rasterizer(JNIEnv* env);
extern int register_android_graphics_Region(JNIEnv* env);
extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_graphics_Xfermode(JNIEnv* env);
+extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
@@ -1312,6 +1313,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_Typeface),
REG_JNI(register_android_graphics_Xfermode),
REG_JNI(register_android_graphics_YuvImage),
+ REG_JNI(register_android_graphics_drawable_VectorDrawable),
REG_JNI(register_android_graphics_pdf_PdfDocument),
REG_JNI(register_android_graphics_pdf_PdfEditor),
REG_JNI(register_android_graphics_pdf_PdfRenderer),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 4a0f3fc23032..d8ec22a0f697 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -587,10 +587,6 @@ static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
return doDecode(env, stream.release(), NULL, options);
}
-static void nativeRequestCancel(JNIEnv*, jobject joptions) {
- // Deprecated
-}
-
static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
@@ -630,10 +626,6 @@ static const JNINativeMethod gMethods[] = {
},
};
-static const JNINativeMethod gOptionsMethods[] = {
- { "requestCancel", "()V", (void*)nativeRequestCancel }
-};
-
int register_android_graphics_BitmapFactory(JNIEnv* env) {
jclass options_class = FindClassOrDie(env, "android/graphics/BitmapFactory$Options");
gOptions_bitmapFieldID = GetFieldIDOrDie(env, options_class, "inBitmap",
@@ -665,8 +657,6 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) {
gInsetStruct_constructorMethodID = GetMethodIDOrDie(env, gInsetStruct_class, "<init>",
"(IIIIIIIIFIF)V");
- android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory$Options",
- gOptionsMethods, NELEM(gOptionsMethods));
return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory",
gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
new file mode 100644
index 000000000000..53d4c6a1cb78
--- /dev/null
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -0,0 +1,386 @@
+/*
+ * 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 "jni.h"
+#include "GraphicsJNI.h"
+#include "core_jni_helpers.h"
+#include "log/log.h"
+
+#include "Paint.h"
+#include "VectorDrawable.h"
+
+namespace android {
+using namespace uirenderer;
+using namespace uirenderer::VectorDrawable;
+
+static jlong createTree(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* rootGroup = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ VectorDrawable::Tree* tree = new VectorDrawable::Tree(rootGroup);
+ return reinterpret_cast<jlong>(tree);
+}
+
+static void deleteTree(JNIEnv*, jobject, jlong treePtr) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ delete tree;
+}
+
+static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
+ jfloat viewportWidth, jfloat viewportHeight) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ tree->setViewportSize(viewportWidth, viewportHeight);
+}
+
+static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ return tree->setRootAlpha(alpha);
+}
+
+static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ return tree->getRootAlpha();
+}
+
+static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCaching) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ tree->setAllowCaching(allowCaching);
+}
+
+static void draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
+ jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+ SkRect rect;
+ GraphicsJNI::jrect_to_rect(env, jrect, &rect);
+ SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
+ tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
+}
+
+static jlong createEmptyFullPath(JNIEnv*, jobject) {
+ VectorDrawable::FullPath* newPath = new VectorDrawable::FullPath();
+ return reinterpret_cast<jlong>(newPath);
+}
+
+static jlong createFullPath(JNIEnv*, jobject, jlong srcFullPathPtr) {
+ VectorDrawable::FullPath* srcFullPath =
+ reinterpret_cast<VectorDrawable::FullPath*>(srcFullPathPtr);
+ VectorDrawable::FullPath* newPath = new VectorDrawable::FullPath(*srcFullPath);
+ return reinterpret_cast<jlong>(newPath);
+}
+
+static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
+ jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
+ jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
+ jint strokeLineCap, jint strokeLineJoin) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->updateProperties(strokeWidth, strokeColor, strokeAlpha, fillColor, fillAlpha,
+ trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit, strokeLineCap,
+ strokeLineJoin);
+}
+
+static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
+ jbyteArray outProperties, jint length) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ int8_t pathProperties[length];
+ bool success = fullPath->getProperties(pathProperties, length);
+ env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
+ return success;
+}
+
+static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
+ jfloatArray outProperties, jint length) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ float groupProperties[length];
+ bool success = group->getProperties(groupProperties, length);
+ env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
+ return success;
+}
+
+static jlong createEmptyClipPath(JNIEnv*, jobject) {
+ VectorDrawable::ClipPath* newPath = new VectorDrawable::ClipPath();
+ return reinterpret_cast<jlong>(newPath);
+}
+
+static jlong createClipPath(JNIEnv*, jobject, jlong srcClipPathPtr) {
+ VectorDrawable::ClipPath* srcClipPath =
+ reinterpret_cast<VectorDrawable::ClipPath*>(srcClipPathPtr);
+ VectorDrawable::ClipPath* newPath = new VectorDrawable::ClipPath(*srcClipPath);
+ return reinterpret_cast<jlong>(newPath);
+}
+
+static jlong createEmptyGroup(JNIEnv*, jobject) {
+ VectorDrawable::Group* newGroup = new VectorDrawable::Group();
+ return reinterpret_cast<jlong>(newGroup);
+}
+
+static jlong createGroup(JNIEnv*, jobject, jlong srcGroupPtr) {
+ VectorDrawable::Group* srcGroup = reinterpret_cast<VectorDrawable::Group*>(srcGroupPtr);
+ VectorDrawable::Group* newGroup = new VectorDrawable::Group(*srcGroup);
+ return reinterpret_cast<jlong>(newGroup);
+}
+
+static void deleteNode(JNIEnv*, jobject, jlong nodePtr) {
+ VectorDrawable::Node* node = reinterpret_cast<VectorDrawable::Node*>(nodePtr);
+ delete node;
+}
+
+static void setNodeName(JNIEnv* env, jobject, jlong nodePtr, jstring nameStr) {
+ VectorDrawable::Node* node = reinterpret_cast<VectorDrawable::Node*>(nodePtr);
+ const char* nodeName = env->GetStringUTFChars(nameStr, NULL);
+ node->setName(nodeName);
+ env->ReleaseStringUTFChars(nameStr, nodeName);
+}
+
+static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
+ jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->updateLocalMatrix(rotate, pivotX, pivotY, scaleX, scaleY, translateX, translateY);
+}
+
+static void addChild(JNIEnv*, jobject, jlong groupPtr, jlong childPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ VectorDrawable::Node* child = reinterpret_cast<VectorDrawable::Node*>(childPtr);
+ group->addChild(child);
+}
+
+static void setPathString(JNIEnv* env, jobject, jlong pathPtr, jstring inputStr,
+ jint stringLength) {
+ VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
+ const char* pathString = env->GetStringUTFChars(inputStr, NULL);
+ path->setPath(pathString, stringLength);
+ env->ReleaseStringUTFChars(inputStr, pathString);
+}
+
+static jfloat getRotation(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getRotation();
+}
+
+static void setRotation(JNIEnv*, jobject, jlong groupPtr, jfloat rotation) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setRotation(rotation);
+}
+
+static jfloat getPivotX(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getPivotX();
+}
+
+static void setPivotX(JNIEnv*, jobject, jlong groupPtr, jfloat pivotX) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setPivotX(pivotX);
+}
+
+static jfloat getPivotY(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getPivotY();
+}
+
+static void setPivotY(JNIEnv*, jobject, jlong groupPtr, jfloat pivotY) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setPivotY(pivotY);
+}
+
+static jfloat getScaleX(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getScaleX();
+}
+
+static void setScaleX(JNIEnv*, jobject, jlong groupPtr, jfloat scaleX) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setScaleX(scaleX);
+}
+
+static jfloat getScaleY(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getScaleY();
+}
+
+static void setScaleY(JNIEnv*, jobject, jlong groupPtr, jfloat scaleY) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setScaleY(scaleY);
+}
+
+static jfloat getTranslateX(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getTranslateX();
+}
+
+static void setTranslateX(JNIEnv*, jobject, jlong groupPtr, jfloat translateX) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setTranslateX(translateX);
+}
+
+static jfloat getTranslateY(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getTranslateY();
+}
+
+static void setTranslateY(JNIEnv*, jobject, jlong groupPtr, jfloat translateY) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setTranslateY(translateY);
+}
+
+static void setPathData(JNIEnv*, jobject, jlong pathPtr, jlong pathDataPtr) {
+ VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
+ PathData* pathData = reinterpret_cast<PathData*>(pathDataPtr);
+ path->setPathData(*pathData);
+}
+
+static jfloat getStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getStrokeWidth();
+}
+
+static void setStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeWidth) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setStrokeWidth(strokeWidth);
+}
+
+static jint getStrokeColor(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getStrokeColor();
+}
+
+static void setStrokeColor(JNIEnv*, jobject, jlong fullPathPtr, jint strokeColor) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setStrokeColor(strokeColor);
+}
+
+static jfloat getStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getStrokeAlpha();
+}
+
+static void setStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeAlpha) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setStrokeAlpha(strokeAlpha);
+}
+
+static jint getFillColor(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getFillColor();
+}
+
+static void setFillColor(JNIEnv*, jobject, jlong fullPathPtr, jint fillColor) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setFillColor(fillColor);
+}
+
+static jfloat getFillAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getFillAlpha();
+}
+
+static void setFillAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat fillAlpha) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setFillAlpha(fillAlpha);
+}
+
+static jfloat getTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getTrimPathStart();
+}
+
+static void setTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathStart) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setTrimPathStart(trimPathStart);
+}
+
+static jfloat getTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getTrimPathEnd();
+}
+
+static void setTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathEnd) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setTrimPathEnd(trimPathEnd);
+}
+
+static jfloat getTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getTrimPathOffset();
+}
+
+static void setTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathOffset) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setTrimPathOffset(trimPathOffset);
+}
+
+static const JNINativeMethod gMethods[] = {
+ {"nCreateRenderer", "!(J)J", (void*)createTree},
+ {"nDestroyRenderer", "!(J)V", (void*)deleteTree},
+ {"nSetRendererViewportSize", "!(JFF)V", (void*)setTreeViewportSize},
+ {"nSetRootAlpha", "!(JF)Z", (void*)setRootAlpha},
+ {"nGetRootAlpha", "!(J)F", (void*)getRootAlpha},
+ {"nSetAllowCaching", "!(JZ)V", (void*)setAllowCaching},
+
+ {"nDraw", "(JJJLandroid/graphics/Rect;ZZ)V", (void*)draw},
+ {"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
+ {"nCreateFullPath", "!(J)J", (void*)createFullPath},
+ {"nUpdateFullPathProperties", "!(JFIFIFFFFFII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
+ {"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
+ {"nGetGroupProperties", "(J[FI)Z", (void*)getGroupProperties},
+
+ {"nCreateClipPath", "!()J", (void*)createEmptyClipPath},
+ {"nCreateClipPath", "!(J)J", (void*)createClipPath},
+ {"nCreateGroup", "!()J", (void*)createEmptyGroup},
+ {"nCreateGroup", "!(J)J", (void*)createGroup},
+ {"nDestroy", "!(J)V", (void*)deleteNode},
+ {"nSetName", "(JLjava/lang/String;)V", (void*)setNodeName},
+ {"nUpdateGroupProperties", "!(JFFFFFFF)V", (void*)updateGroupProperties},
+
+ {"nAddChild", "!(JJ)V", (void*)addChild},
+ {"nSetPathString", "(JLjava/lang/String;I)V", (void*)setPathString},
+
+ {"nGetRotation", "!(J)F", (void*)getRotation},
+ {"nSetRotation", "!(JF)V", (void*)setRotation},
+ {"nGetPivotX", "!(J)F", (void*)getPivotX},
+ {"nSetPivotX", "!(JF)V", (void*)setPivotX},
+ {"nGetPivotY", "!(J)F", (void*)getPivotY},
+ {"nSetPivotY", "!(JF)V", (void*)setPivotY},
+ {"nGetScaleX", "!(J)F", (void*)getScaleX},
+ {"nSetScaleX", "!(JF)V", (void*)setScaleX},
+ {"nGetScaleY", "!(J)F", (void*)getScaleY},
+ {"nSetScaleY", "!(JF)V", (void*)setScaleY},
+ {"nGetTranslateX", "!(J)F", (void*)getTranslateX},
+ {"nSetTranslateX", "!(JF)V", (void*)setTranslateX},
+ {"nGetTranslateY", "!(J)F", (void*)getTranslateY},
+ {"nSetTranslateY", "!(JF)V", (void*)setTranslateY},
+
+ {"nSetPathData", "!(JJ)V", (void*)setPathData},
+ {"nGetStrokeWidth", "!(J)F", (void*)getStrokeWidth},
+ {"nSetStrokeWidth", "!(JF)V", (void*)setStrokeWidth},
+ {"nGetStrokeColor", "!(J)I", (void*)getStrokeColor},
+ {"nSetStrokeColor", "!(JI)V", (void*)setStrokeColor},
+ {"nGetStrokeAlpha", "!(J)F", (void*)getStrokeAlpha},
+ {"nSetStrokeAlpha", "!(JF)V", (void*)setStrokeAlpha},
+ {"nGetFillColor", "!(J)I", (void*)getFillColor},
+ {"nSetFillColor", "!(JI)V", (void*)setFillColor},
+ {"nGetFillAlpha", "!(J)F", (void*)getFillAlpha},
+ {"nSetFillAlpha", "!(JF)V", (void*)setFillAlpha},
+ {"nGetTrimPathStart", "!(J)F", (void*)getTrimPathStart},
+ {"nSetTrimPathStart", "!(JF)V", (void*)setTrimPathStart},
+ {"nGetTrimPathEnd", "!(J)F", (void*)getTrimPathEnd},
+ {"nSetTrimPathEnd", "!(JF)V", (void*)setTrimPathEnd},
+ {"nGetTrimPathOffset", "!(J)F", (void*)getTrimPathOffset},
+ {"nSetTrimPathOffset", "!(JF)V", (void*)setTrimPathOffset},
+};
+
+int register_android_graphics_drawable_VectorDrawable(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/graphics/drawable/VectorDrawable", gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 90606a35b5a2..3473d9dab732 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -578,7 +578,7 @@ static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject cla
return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
}
-static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
{
Vector<String8> locales;
@@ -587,7 +587,7 @@ static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject
return NULL;
}
- am->getLocales(&locales);
+ am->getLocales(&locales, includeSystemLocales);
const int N = locales.size();
@@ -608,6 +608,16 @@ static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject
return result;
}
+static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+{
+ return getLocales(env, clazz, true /* include system locales */);
+}
+
+static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
+{
+ return getLocales(env, clazz, false /* don't include system locales */);
+}
+
static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
jobject result = env->NewObject(gConfigurationOffsets.classObject,
gConfigurationOffsets.constructor);
@@ -2154,6 +2164,8 @@ static const JNINativeMethod gAssetManagerMethods[] = {
// Resources.
{ "getLocales", "()[Ljava/lang/String;",
(void*) android_content_AssetManager_getLocales },
+ { "getNonSystemLocales", "()[Ljava/lang/String;",
+ (void*) android_content_AssetManager_getNonSystemLocales },
{ "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
(void*) android_content_AssetManager_getSizeConfigurations },
{ "setConfiguration", "!(IILjava/lang/String;IIIIIIIIIIIIII)V",
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index f6e68c48e881..cf68449096a6 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -465,11 +465,17 @@ static jint nativeGetHeight(JNIEnv* env, jclass clazz, jlong nativeObject) {
anw->query(anw, NATIVE_WINDOW_HEIGHT, &value);
return value;
}
+
static jlong nativeGetNextFrameNumber(JNIEnv *env, jclass clazz, jlong nativeObject) {
Surface* surface = reinterpret_cast<Surface*>(nativeObject);
return surface->getNextFrameNumber();
}
+static jint nativeSetScalingMode(JNIEnv *env, jclass clazz, jlong nativeObject, jint scalingMode) {
+ Surface* surface = reinterpret_cast<Surface*>(nativeObject);
+ return surface->setScalingMode(scalingMode);
+}
+
namespace uirenderer {
using namespace android::uirenderer::renderthread;
@@ -546,6 +552,7 @@ static const JNINativeMethod gSurfaceMethods[] = {
{"nativeGetWidth", "(J)I", (void*)nativeGetWidth },
{"nativeGetHeight", "(J)I", (void*)nativeGetHeight },
{"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber },
+ {"nativeSetScalingMode", "(JI)I", (void*)nativeSetScalingMode },
// HWUI context
{"nHwuiCreate", "(JJ)J", (void*) hwui::create },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 96d150be0234..041e693089de 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -605,10 +605,32 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
jint debug_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
- // Grant CAP_WAKE_ALARM to the Bluetooth process.
jlong capabilities = 0;
+
+ // Grant CAP_WAKE_ALARM to the Bluetooth process.
if (uid == AID_BLUETOOTH) {
- capabilities |= (1LL << CAP_WAKE_ALARM);
+ capabilities |= (1LL << CAP_WAKE_ALARM);
+ }
+
+ // Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
+ bool gid_wakelock_found = false;
+ if (gid == AID_WAKELOCK) {
+ gid_wakelock_found = true;
+ } else if (gids != NULL) {
+ jsize gids_num = env->GetArrayLength(gids);
+ ScopedIntArrayRO ar(env, gids);
+ if (ar.get() == NULL) {
+ RuntimeAbort(env, __LINE__, "Bad gids array");
+ }
+ for (int i = 0; i < gids_num; i++) {
+ if (ar[i] == AID_WAKELOCK) {
+ gid_wakelock_found = true;
+ break;
+ }
+ }
+ }
+ if (gid_wakelock_found) {
+ capabilities |= (1LL << CAP_BLOCK_SUSPEND);
}
return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1090f90fbbef..c154e91bb559 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -107,6 +107,7 @@
<protected-broadcast android:name="android.backup.intent.CLEAR" />
<protected-broadcast android:name="android.backup.intent.INIT" />
+ <protected-broadcast android:name="android.bluetooth.intent.DISCOVERABLE_TIMEOUT" />
<protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
@@ -888,6 +889,11 @@
android:protectionLevel="normal"
android:permissionFlags="hidden"/>
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.FLASHLIGHT"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
<!-- ====================================================================== -->
<!-- INSTALL PERMISSIONS -->
<!-- ====================================================================== -->
@@ -1193,14 +1199,6 @@
android:description="@string/permdesc_vibrate"
android:protectionLevel="normal" />
- <!-- Allows access to the flashlight.
- <p>Protection level: normal
- -->
- <permission android:name="android.permission.FLASHLIGHT"
- android:label="@string/permlab_flashlight"
- android:description="@string/permdesc_flashlight"
- android:protectionLevel="normal" />
-
<!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
from dimming.
<p>Protection level: normal
@@ -1901,7 +1899,7 @@
<!-- Allows an application to bind to third party quick settings tiles.
<p>Should only be requested by the System, should be required by
- QSTileService declarations.-->
+ TileService declarations.-->
<permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
android:protectionLevel="signature" />
diff --git a/core/res/res/layout/notification_material_reply_text.xml b/core/res/res/layout/notification_material_reply_text.xml
new file mode 100644
index 000000000000..bc22eb49cf57
--- /dev/null
+++ b/core/res/res/layout/notification_material_reply_text.xml
@@ -0,0 +1,61 @@
+<?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
+ -->
+
+<!-- Note: this layout is included from a view stub; layout attributes will be overridden. -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingStart="@dimen/notification_content_margin_start">
+
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:id="@+id/action_divider"
+ android:layout_marginBottom="15dp"
+ android:background="@drawable/notification_template_divider" />
+
+ <TextView
+ android:id="@+id/notification_material_reply_text_3"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:visibility="gone"
+ android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+ android:singleLine="true" />
+
+ <TextView
+ android:id="@+id/notification_material_reply_text_2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:visibility="gone"
+ android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+ android:singleLine="true" />
+
+ <TextView
+ android:id="@+id/notification_material_reply_text_1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="15dp"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+ android:singleLine="true" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index 91a5cebe1994..dfd72c08a8c6 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -55,6 +55,11 @@
</FrameLayout>
<include layout="@layout/notification_template_right_icon" />
</FrameLayout>
+ <ViewStub android:layout="@layout/notification_material_reply_text"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
<include
layout="@layout/notification_material_action_list"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_template_material_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml
index 58e3d1b2612e..5c07b9bf5a0c 100644
--- a/core/res/res/layout/notification_template_material_big_picture.xml
+++ b/core/res/res/layout/notification_template_material_big_picture.xml
@@ -52,6 +52,13 @@
android:layout_marginBottom="16dp"
android:scaleType="centerCrop"
/>
+ <ViewStub android:layout="@layout/notification_material_reply_text"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="-16dp"
+ android:layout_marginEnd="-16dp"
+ />
<include layout="@layout/notification_material_action_list" />
</LinearLayout>
</FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index de9f5721f4e6..ebaffc30e28a 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -63,6 +63,13 @@
android:contentDescription="@string/notification_work_profile_content_description"
/>
</LinearLayout>
+ <ViewStub android:layout="@layout/notification_material_reply_text"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="-16dp"
+ android:layout_marginEnd="-16dp"
+ />
<include layout="@layout/notification_material_action_list" />
</LinearLayout>
<include layout="@layout/notification_template_right_icon" />
diff --git a/core/res/res/layout/text_drag_thumbnail.xml b/core/res/res/layout/text_drag_thumbnail.xml
index 63d2c05b539e..b1a58cdbec61 100644
--- a/core/res/res/layout/text_drag_thumbnail.xml
+++ b/core/res/res/layout/text_drag_thumbnail.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2010, The Android Open Source Project
**
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 04466e511bb8..36c167ea8056 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Laat die program toe om foto\'s en video\'s met die kamera te neem. Hierdie toestemming laat die program toe om die kamera te eniger tyd sonder jou bevestiging te gebruik."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"beheer vibrasie"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Laat die program toe om die vibrator te beheer."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"beheer flitslig"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Laat die program toe om die flitslig te beheer."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"skakel foonnommers direk"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Laat die program toe om telefoonnommers sonder jou tussentrede te bel. Dit kan tot onverwagte heffings of oproepe lei. Let daarop dat dit nie die program toelaat om noodnommers te bel nie. Kwaadwillige programme kan jou geld kos deur oproepe sonder jou bevestiging te maak."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"toegang tot kitsboodskapoproepdiens"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index b26232572be7..ec16add34a26 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"መተግበሪያው በካሜራው ፎቶዎችንና ቪዲዮዎችን እንዲያነሳ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ካሜራውን በማንኛውም ጊዜ ያላንተ ማረጋገጫ እንዲጠቀም ይፈቅድለታል።"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ነዛሪ ተቆጣጠር"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ነዛሪውን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"የብርሃንብልጭታ ተቆጣጠር"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"የብልጭታ ብርሃኑን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"በቀጥታ ስልክ ቁጥሮች ደውል"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"መተግበሪያው ያላንተ ጣልቃ ገብነት የስልክ ቁጥሮች ላይ እንዲደውል ይፈቅድለታል። ይህ ያልተጠበቁ ክፍያዎችን ወይም ጥሪዎችን ሊያስከትል ይችላል። ይህ መተግበሪያው የድንገተኛ ስልክ ቁጥሮችን እንዲደውል እንደማይፈቅድለት ልብ በል። ተንኮል አዘል መተግበሪያዎች ያላንተ ማረጋገጫ ጥሪዎችን በማድረግ ገንዘብ ሊያስወጡህ ይችላሉ።"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"የአይኤምኤስ ጥሪ አገልግሎትን ይደርሳል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 6eb005c0aae4..12ef759d60ad 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -358,8 +358,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"للسماح للتطبيق بالتقاط صور ومقاطع فيديو من خلال الكاميرا. ويتيح هذا الإذن للتطبيق استخدام الكاميرا في أي وقت وبدون موافقة منك."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"التحكم في الاهتزاز"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"للسماح للتطبيق بالتحكم في الهزّاز."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"التحكم في الضوء الوامض"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"للسماح للتطبيق بالتحكم في الضوء الوامض."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"اتصال مباشر بأرقام الهواتف"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"للسماح للتطبيق بطلب أرقام هاتفية بدون تدخل منك. وقد يؤدي ذلك إلى تحمل رسوم غير متوقعة أو إجراء مكالمات غير متوقعة. ومن الجدير بالذكر أن ذلك لا يتيح للتطبيق الاتصال بأرقام الطوارئ. وقد تؤدي التطبيقات الضارة إلى تحملك تكاليف مالية من خلال إجراء مكالمات بدون موافقة منك."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"الوصول إلى خدمة الاتصال عبر الرسائل الفورية"</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 30b6e77d59f5..7f0e6d7a3cf7 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Tətbiqə kamera ilə şəkil və video çəkməyə imkan yaradır. Bu icazə tətbiqə sizin təsdiqiniz olmadan kameradan istifadə icazəsi verir."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"vibrasiyaya nəzarət edir"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Tətbiqə vibratoru idarə etmə icazəsi verir."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"Flash işığını idarə edir"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Tətbiqə siqnal işığı na nəzarət etməyə imkan verir."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefon nömrələrinə birbaşa zəng edir"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Tətbiqə Sizin müdaxiləniz olmadan telefon zəngləri etməyə imkan verir. Zərərli tətbiqlər Sizdən xəbərsiz şəkildə müxtəlif zənglər edərək, Sizə maddi ziyan vura bilər. Qeyd: Bu, tətbiqlərə təcili nömrələrə zəng etməyə icazə vermir."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS zəng xidmətinə giriş"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 0f51f0d9d976..ac5ce6629593 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -355,8 +355,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Dozvoljava aplikaciji da snima slike i video snimke kamerom. Ova dozvola omogućava aplikaciji da u bilo kom trenutku koristi kameru bez vaše potvrde."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrola vibracije"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Dozvoljava aplikaciji da kontroliše vibraciju."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrola osvetljenja"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Dozvoljava aplikaciji da kontroliše blic."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"direktno pozivanje brojeva telefona"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Dozvoljava aplikaciji da poziva brojeve telefona bez vaše dozvole. Ovo može da dovede do neočekivanih troškova ili poziva. Imajte na umu da ovo ne dozvoljava aplikaciji da poziva brojeve za hitne slučajeve. Zlonamerne aplikacije mogu da pozivaju bez vaše potvrde, što može da dovede do troškova."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristup usluzi poziva pomoću razmene trenutnih poruka"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d70f95fcd45b..301e1e33b221 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Разрешава на приложението да прави снимки и видеоклипове с камерата. Това разрешение му позволява да я използва по всяко време без потвърждение от ваша страна."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"контролиране на вибрирането"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Разрешава на приложението да контролира устройството за вибрация."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"контролиране на фенерчето"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Разрешава на приложението да контролира фенерчето."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"директно обаждане до телефонни номера"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Разрешава на приложението да се обажда без ваша намеса до телефонни номера, което може да доведе до неочаквано таксуване или обаждания. Обърнете внимание, че това не му позволява да извършва обаждания до спешните служби. Злонамерените приложения могат да ви въвлекат в разходи, като извършват обаждания без потвърждение от ваша страна."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"достъп до услугата за незабавни съобщения за обаждания"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 683e2ecc437a..9c88d44349c5 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ক্যামেরার সাহায্যে ছবি তুলতে ও ভিডিও তৈরি করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ এই অনুমতিটি অ্যাপ্লিকেশানটিকে আপনার নিশ্চয়তা ছাড়াই যেকোনো সময় ক্যামেরা ব্যবহার করতে মঞ্জুর করে৷"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"কম্পন নিয়ন্ত্রণ করুন"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"অ্যাপ্লিকেশানকে কম্পক নিয়ন্ত্রণ করতে দেয়৷"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ফ্ল্যাশলাইট নিয়ন্ত্রণ করে"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"অ্যাপ্লিকেশানকে টর্চলাইট নিয়ন্ত্রণ করতে দেয়৷"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"সরাসরি ফোন নম্বরগুলিতে কল করে"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"অ্যাপ্লিকেশানটিকে আপনার হস্তক্ষেপ ছাড়াই ফোন নম্বরগুলিতে কল করতে মঞ্জুর করে৷ এটি অপ্রত্যাশিত পরিমাণ খরচা বা কলের কারণ হতে পারে৷ মনে রাখবেন, এটি অ্যাপ্লিকেশানটির দ্বারা জরুরি নম্বরগুলিতে কল করাকে অনুমতি দেয় না৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার সম্মতি ছাড়াই কল করার ফলে আপনাকে অহেতুক অর্থ প্রদান করতে হতে পারে৷"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS পরিষেবাতে অ্যাক্সেস"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 786fea1b7b0e..8554b84394a5 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permet que l\'aplicació faci fotos i vídeos amb la càmera. Aquest permís permet que l\'aplicació utilitzi la càmera en qualsevol moment sense la teva confirmació."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibració"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permet que l\'aplicació controli el vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controla la llanterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet que l\'aplicació controli la llanterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"trucar directament a números de telèfon"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permet que l\'aplicació truqui a números de telèfon sense la teva intervenció. Aquesta acció pot produir càrrecs o trucades inesperades. Tingues en compte que això no permet que l\'aplicació truqui a números d\'emergència. Les aplicacions malicioses poden fer trucades sense la teva confirmació, cosa que et pot fer gastar diners."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"accés al servei de trucades IMS"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a2e12a39e93a..2eca49a6f7bf 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -356,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikaci pořizovat fotografie a videa pomocí fotoaparátu. Toto oprávnění umožňuje aplikaci používat fotoaparát kdykoliv i bez vašeho svolení."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ovládání vibrací"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikaci ovládat vibrace."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ovládání kontrolky"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikaci ovládat svítilnu."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"přímé volání na telefonní čísla"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikaci volat na telefonní čísla bez vašeho přičinění. Může mít za následek neočekávané poplatky nebo hovory. Toto oprávnění neumožňuje aplikaci volat na tísňová čísla. Škodlivé aplikace vás mohou připravit o peníze uskutečňováním hovorů bez vašeho svolení."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"přístup ke službě zasílání rychlých zpráv pro účely hovorů"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 67b8ee9195c0..2a719b011c0e 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Tillader, at appen kan tage billeder og videoer med kameraet. Med denne tilladelse kan appen til enhver tid bruge kameraet uden din bekræftelse."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrollere vibration"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Tillader, at appen kan kontrollere vibratoren."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontroller lommelygte"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Tillader, at appen kan kontrollere lommelygten."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ringe direkte op til telefonnumre"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Tillader, at appen kan ringe til telefonnumre uden din indgriben. Dette kan resultere i uventede opkrævninger eller opkald. Bemærk, at appen med denne tilladelse ikke kan ringe til nødopkaldsnumre. Skadelige apps kan koste dig penge ved at foretage opkald uden din bekræftelse."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"få adgang til chat-opkaldstjeneste"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 2d64aee2e5e9..d116a24ee817 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ermöglicht der App, Bilder und Videos mit der Kamera aufzunehmen. Die Berechtigung erlaubt der App, die Kamera jederzeit und ohne Ihre Bestätigung zu nutzen."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"Vibrationsalarm steuern"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Ermöglicht der App, den Vibrationsalarm zu steuern"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"Lichtanzeige steuern"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Ermöglicht der App, die Lichtanzeige zu steuern"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"Telefonnummern direkt anrufen"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Ermöglicht der App, ohne Ihr Eingreifen Telefonnummern zu wählen. Dies kann zu unerwarteten Kosten und Anrufen führen. Beachten Sie, dass die App keine Notrufnummern wählen kann. Schädliche Apps verursachen möglicherweise Kosten, indem sie Anrufe ohne Ihre Bestätigung tätigen."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"Zugriff auf IMS-Anrufdienst"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index a1a6ced4debb..8116b16ea4fa 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Επιτρέπει στην εφαρμογή τη λήψη φωτογραφιών και βίντεο με τη φωτογραφική μηχανή. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να χρησιμοποιεί τη φωτογραφική μηχανή ανά πάσα στιγμή χωρίς την έγκρισή σας."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"έλεγχος δόνησης"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Επιτρέπει στην εφαρμογή τον έλεγχο της δόνησης."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"έλεγχος φακού"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Επιτρέπει στην εφαρμογή τον έλεγχο του φακού."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"απευθείας κλήση τηλεφωνικών αριθμών"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Επιτρέπει στην εφαρμογή την κλήση αριθμών τηλεφώνου χωρίς δική σας παρέμβαση. Αυτό μπορεί να προκαλέσει μη αναμενόμενες χρεώσεις ή κλήσεις. Έχετε υπόψη ότι δεν επιτρέπεται στην εφαρμογή η κλήση αριθμών έκτακτης ανάγκης. Οι κακόβουλες εφαρμογές ενδέχεται να σας κοστίσουν χρήματα, πραγματοποιώντας κλήσεις χωρίς την έγκρισή σας."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"πρόσβαση στην υπηρεσία κλήσεων της IMS"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index cd2dc23c3715..930c310b9267 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index cd2dc23c3715..930c310b9267 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index cd2dc23c3715..930c310b9267 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index a6f76ace6b18..258ef33fe993 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación saque fotos o grabe videos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibración"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que la aplicación controle la vibración."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que la aplicación controle la función de linterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que la aplicación haga llamadas a números de teléfono sin intervención del usuario, lo que puede dar lugar a llamadas o cargos inesperados. Ten en cuenta que las aplicaciones no pueden usar este servicio para realizar llamadas a números de emergencia, pero las aplicaciones malintencionadas pueden causarte gastos imprevistos al realizar llamadas sin tu confirmación."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceder al servicio IMS para realizar llamadas"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 594fa5065603..9848bb624c26 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación haga fotos o grabe vídeos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibración"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que la aplicación controle la función de vibración."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que la aplicación controle la función de linterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que la aplicación haga llamadas sin intervención del usuario, lo que puede dar lugar a llamadas o cargos inesperados. Ten en cuenta que las aplicaciones no pueden usar este servicio para realizar llamadas a números de emergencia, pero las aplicaciones malintencionadas pueden causarte gastos imprevistos al realizar llamadas sin tu confirmación."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceder al servicio de llamadas IMS"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 8ee89048d4d2..466bd5dddfe7 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Võimaldab rakendusel teha kaameraga pilte ja videoid. See luba võimaldab rakendusel kasutada kaamerat mis tahes ajal teie kinnituseta."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"juhtige vibreerimist"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Võimaldab rakendusel juhtida vibreerimist."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"juhi taskulampi"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Võimaldab rakendusel juhtida taskulampi."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"helista otse telefoninumbritele"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Võimaldab rakendusel teie sekkumiseta telefoninumbritele helistada. See võib põhjustada ootamatuid tasusid või telefonikõnesid. Pange tähele, et see ei luba rakendusel helistada hädaabinumbritele. Pahatahtlikud rakendused võivad teile kulusid tekitada, tehes telefonikõnesid teie kinnituseta."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"juurdepääs IMS-kõneteenusele"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 7072957c852a..cdb8622e9a01 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Kamerarekin argazkiak ateratzeko eta bideoak grabatzeko baimena ematen die aplikazioei. Baimen horrekin, aplikazioak kamera edonoiz erabil dezake zure baimenik gabe."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"bibrazioa kontrolatzea"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Bibragailua kontrolatzea baimentzen die aplikazioei."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolatu linterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Linterna kontrolatzea baimentzen die aplikazioei."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"deitu zuzenean telefono-zenbakietara"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Telefono-zenbakietara zuk esku hartu gabe deitzeko baimena ematen die aplikazioei. Horrela, ustekabeko gastuak edo deiak eragin daitezke. Aplikazio gaiztoek erabil dezakete zuk berretsi gabeko deiak eginda gastuak eragiteko."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"Atzitu IMS dei-zerbitzua"</string>
@@ -384,8 +382,8 @@
<string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Tabletak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dituzun aplikazioek sortutako kontuak har daitezke barne."</string>
<string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Telebistak ezagutzen dituen kontuen zerrenda lortzea baimentzen die aplikazioei. Instalatuta dituzun aplikazioek sortutako kontuak sar daitezke."</string>
<string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Telefonoak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dituzun aplikazioek sortutako kontuak har daitezke barne."</string>
- <string name="permlab_accessNetworkState" msgid="4951027964348974773">"sare-konexioak ikustea"</string>
- <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Sare-konexioei buruzko informazioa ikusteko baimena ematen die aplikazioei; adibidez, zer sare dauden eta zeintzuk dauden konektatuta."</string>
+ <string name="permlab_accessNetworkState" msgid="4951027964348974773">"sareko konexioak ikustea"</string>
+ <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Sareko konexioei buruzko informazioa ikusteko baimena ematen die aplikazioei; adibidez, zer sare dauden eta zeintzuk dauden konektatuta."</string>
<string name="permlab_createNetworkSockets" msgid="7934516631384168107">"Izan sarerako sarbide osoa"</string>
<string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Sare-socketak sortzeko eta sare-protokolo pertsonalizatuak erabiltzeko baimena ematen die aplikazioei. Arakatzaileak eta beste aplikazio batzuek Internetera konektatzeko moduak eskaintzen dituzte, beraz, baimen hori ez da beharrezkoa datuak Internetera bidaltzeko."</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"aldatu sarearen konektagarritasuna"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6c1f98ae8bd4..b0da5fe89d48 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"به برنامه اجازه می‌دهد با دوربین به عکسبرداری و فیلمبرداری بپردازد. این مجوز به برنامه اجازه می‌‌دهد از دوربین در هر زمانی بدون تأیید شما استفاده کند."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"کنترل لرزش"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"‏به برنامه اجازه می‎دهد تا لرزاننده را کنترل کند."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"کنترل چراغ قوه"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"‏به برنامه اجازه می‎دهد تا چراغ قوه را کنترل کند."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"تماس مستقیم با شماره تلفن‌ها"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"به برنامه اجازه می‌دهد بدون دخالت شما با شماره‌های تلفن تماس بگیرد. این ممکن است باعث ایجاد هزینه یا تماس‌های پیش‌بینی نشده شود. توجه داشته باشید که این به برنامه اجازه نمی‌دهد به برقراری تماس‌های اضطراری بپردازد. برنامه‌های مخرب ممکن است با برقراری تماس بدون تأیید شما هزینه‌هایی را برای شما ایجاد کنند."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"‏دسترسی به سرویس تماس IMS"</string>
@@ -931,7 +929,7 @@
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> در حال اجرا"</string>
<string name="heavy_weight_notification_detail" msgid="1721681741617898865">"لمس کردن برای بازکردن برنامه"</string>
<string name="heavy_weight_switcher_title" msgid="7153167085403298169">"برنامه عوض شود؟"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"برنامه دیگری از قبل در حال اجرا است که باید قبل از اینکه برنامه جدیدی را شروع کنید متوقف شود."</string>
+ <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"برنامه دیگری از قبل در حال اجراست که باید متوقف شود تا بتوانید برنامه جدید را شروع کنید."</string>
<string name="old_app_action" msgid="493129172238566282">"بازگشت به <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
<string name="old_app_description" msgid="2082094275580358049">"برنامه جدید شروع نشود."</string>
<string name="new_app_action" msgid="5472756926945440706">"شروع <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index b0efd9638889..f7db67853a4a 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Antaa sovelluksen ottaa kuvia ja kuvata videoita kameralla. Sovellus voi käyttää kameraa milloin tahansa ilman lupaasi."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"hallitse värinää"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Antaa sovelluksen hallita värinää."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"hallitse taskulamppua"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Antaa sovelluksen hallita taskulamppua."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"soittaa puhelinnumeroihin suoraan"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Antaa sovelluksen soittaa puhelinnumeroihin kysymättä sinulta. Tämä voi aiheuttaa odottamattomia kuluja tai puheluita. Huomaa, että tämä ei anna sovellukselle lupaa soittaa hätänumeroihin. Haitalliset sovellukset voivat aiheuttaa sinulle kuluja soittamalla puheluita ilman lupaa."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"pikaviestipalvelun puhelukäyttöoikeus"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 52a47587aa2f..50aed95e9594 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"gérer le vibreur"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permet à l\'application de gérer le vibreur de l\'appareil."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"gérer la lampe de poche"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet à l\'application de gérer la lampe de poche."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement des numéros de téléphone"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Des applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"accéder au service d\'appel IMS"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index e90f35fac568..33d20169adfc 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -189,7 +189,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Sonnerie activée"</string>
<string name="reboot_to_update_title" msgid="6212636802536823850">"Mise à jour du système Android"</string>
<string name="reboot_to_update_prepare" msgid="6305853831955310890">"Préparation de la mise à jour en cours…"</string>
- <string name="reboot_to_update_package" msgid="3871302324500927291">"Traitement du package de mises à jour en cours…"</string>
+ <string name="reboot_to_update_package" msgid="3871302324500927291">"Traitement du package de mise à jour…"</string>
<string name="reboot_to_update_reboot" msgid="6428441000951565185">"Redémarrage en cours…"</string>
<string name="reboot_to_reset_title" msgid="4142355915340627490">"Rétablir la configuration d\'usine"</string>
<string name="reboot_to_reset_message" msgid="2432077491101416345">"Redémarrage en cours…"</string>
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"contrôler le vibreur"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permet à l\'application de contrôler le vibreur."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"contrôler la lampe de poche"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet à l\'application de contrôler la lampe de poche."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement les numéros de téléphone"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Les applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"accéder au service d\'appel IMS"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 71ce6e9bffb6..7947825f75bf 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite á aplicación tomar imaxes e vídeos coa cámara. Con este permiso a aplicación pode utilizar a cámara en calquera momento sen a túa confirmación."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar a vibración"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite á aplicación controlar o vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar a lanterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite á aplicación controlar a luz do flash."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"chamar directamente aos números de teléfono"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite á aplicación chamar a números de teléfono sen a túa intervención. Esta acción pode implicar chamadas ou custos inesperados. Ten en conta que isto non permite á aplicación chamar a números de emerxencia. É posible que aplicacións maliciosas che custen diñeiro debido á realización de chamadas sen a túa confirmación."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceso ao servizo de chamadas de IMS"</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 8258dc2b4e0d..aa9478bd6158 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"એપ્લિકેશનને કૅમેરા વડે ચિત્રો અને વિડિઓઝ લેવાની મંજૂરી આપે છે. આ પરવાનગી એપ્લિકેશનને તમારી પુષ્ટિ વિના કોઈપણ સમયે કૅમેરાના ઉપયોગની મંજૂરી આપે છે."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"વાઇબ્રેશન નિયંત્રિત કરો"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"એપ્લિકેશનને વાઇબ્રેટરને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ફ્લેશલાઇટ નિયંત્રિત કરો"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"એપ્લિકેશનને ફ્લેશલાઇટને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"સીધા જ ફોન નંબર્સ પર કૉલ કરો"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"એપ્લિકેશનને તમારા હસ્તક્ષેપ વિના ફોન નંબર્સ પર કૉલ કરવાની મંજૂરી આપે છે. આ અનપેક્ષિત શુલ્ક અથવા કૉલ્સમાં પરિણમી શકે છે. નોંધો કે આ એપ્લિકેશનને કટોકટીના નંબર્સ પર કૉલ કરવાની મંજૂરી આપતું નથી. દુર્ભાવનાપૂર્ણ એપ્લિકેશનો તમારી પુષ્ટિ વિના કૉલ્સ કરીને તમારા પૈસા ખર્ચ કરી શકે છે."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS કૉલ સેવા ઍક્સેસ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 3f374ac6dc2c..d3d1e2c2aa10 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ऐप्स को कैमरे से चित्र और वीडियो लेने देता है. यह अनुमति ऐप्स को किसी भी समय आपकी पुष्टि के बिना कैमरे का उपयोग करने देती है."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करें"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ऐप्स को कंपनकर्ता नियंत्रित करने देता है."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"फ़्लैशलाइट नियंत्रित करें"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ऐप्स को फ़्लैशलाइट नियंत्रित करने देता है."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"फ़ोन नंबर पर सीधे कॉल करें"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ऐप्स को आपके हस्‍तक्षेप के बिना फ़ोन नंबर पर कॉल करने देता है. इसके परिणाम अप्रत्‍याशित शुल्‍क या कॉल हो सकते हैं. ध्यान दें कि यह ऐप्स को आपातकालीन नंबर पर कॉल नहीं करने देता. दुर्भावनापूर्ण ऐप्स आपकी पुष्टि के बिना कॉल करके आपका धन व्‍यय कर सकते हैं."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवा ऐक्‍सेस करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index bf89366b5f24..dc55c57b5001 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -355,8 +355,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogućuje snimanje slika i videozapisa fotoaparatom. Ta dozvola aplikaciji omogućuje upotrebu fotoaparata u bilo kojem trenutku bez vašeg odobrenja."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"upravljanje vibracijom"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Aplikaciji omogućuje nadzor nad vibratorom."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"upravljanje svjetiljkom"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Aplikaciji omogućuje upravljanje svjetiljkom."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"izravno pozivanje telefonskog broja"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Aplikaciji omogućuje pozivanje telefonskih brojeva bez vašeg sudjelovanja. To može dovesti do neočekivanih troškova ili poziva. Uzmite u obzir da se aplikaciji time ne omogućuje pozivanje brojeva u nuždi. Zlonamjerne aplikacije mogu vam uzrokovati dodatne troškove postavljanjem poziva bez vašeg odobrenja."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristupiti usluzi poziva izravnih poruka"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 64e222958266..3176c6579399 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Lehetővé teszi az alkalmazás számára, hogy a fényképezőgéppel fotókat és videókat készítsen. Az engedéllyel rendelkező alkalmazás bármikor, az Ön jóváhagyása nélkül használhatja a fényképezőgépet."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"rezgés szabályozása"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Lehetővé teszi az alkalmazás számára a rezgés vezérlését."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"vaku vezérlése"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Lehetővé teszi az alkalmazás számára a vaku vezérlését."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefonszámok közvetlen hívása"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Lehetővé teszi az alkalmazás számára, hogy az Ön jóváhagyása nélkül hívjon fel telefonszámokat. Ennek eredményeként váratlan terhelésekkel vagy telefonhívásokkal találkozhat. Vegye figyelembe, hogy ez nem teszi lehetővé segélyhívó számok hívását az alkalmazás számára. A rosszindulatú alkalmazások az Ön jóváhagyása nélkül kezdeményezhetnek hívásokat, így költségek merülhetnek fel."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"hozzáférés az IMS-hívásszolgáltatáshoz"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 6fdccd30568b..d72ee8dcfb12 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Թույլ է տալիս հավելվածին ֆոտոխցիկով լուսանկարել և տեսանկարել: Այս թույլտվությունը հնարավորություն է տալիս հավելվածին օգտագործել ֆոտոխցիկը ցանկացած ժամանակ` առանց ձեր հաստատման:"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"կառավարել թրթռումը"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Թույլ է տալիս հավելվածին կառավարել թրթռոցը:"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"կառավարել լապտերը"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Թույլ է տալիս հավելվածին կառավարել լապտերը:"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ուղղակիորեն զանգել հեռախոսահամարներին"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Թույլ է տալիս հավելվածին զանգել հեռախոսահամարներին առանց ձեր միջամտության: Սա կարող է հանգեցնել անկանխատեսելի գանձումների կամ զանգերի: Նկատի ունեցեք, որ սա թույլ չի տալիս հավելվածին զանգել արտակարգ իրավիճակների համարներին: Վնասարար հավելվածները կարող են ձեր հաշվից զանգեր կատարել` առանց ձեր հաստատման:"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"օգտվել IMS զանգերի ծառայությունից"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 4960267078b0..024eea4c2ca1 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Memungkinkan aplikasi mengambil gambar dan video dengan kamera. Izin ini memungkinkan aplikasi menggunakan kamera kapan saja tanpa konfirmasi Anda."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrol getaran"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Mengizinkan aplikasi untuk mengendalikan vibrator."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"mengontrol lampu senter"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Mengizinkan apl mengontrol lampu kilat."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"panggil nomor telepon secara langsung"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Memungkinkan aplikasi menghubungi nomor telepon tanpa campur tangan Anda. Izin ini dapat mengakibatkan biaya atau panggilan tak terduga. Perhatikan bahwa izin ini tidak memungkinkan aplikasi menghubungi nomor darurat. Aplikasi berbahaya dapat menyebabkan Anda dikenakan biaya dengan melakukan panggilan tanpa konfirmasi Anda."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"akses layanan panggilan IMS"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 35ae53da0f6e..240c71558b66 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Leyfir forriti að taka myndir og myndskeið með myndavélinni. Þessi heimild leyfir forritinu að nota myndavélina hvenær sem er án þinnar heimildar."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"stjórna titringi"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Leyfir forriti að stjórna titraranum."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"stjórna vasaljósi"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Leyfir forriti að stjórna vasaljósinu."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"hringja beint í símanúmer"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Leyfir forriti að hringja í símanúmer án íhlutunar notanda. Þetta getur haft í för með sér óumbeðin gjöld og símtöl. Athugaðu að þetta leyfir forritinu ekki að hringja í neyðarnúmer. Spilliforrit geta stofnað til kostnaðar fyrir þig með því að hringja símtöl án þinnar heimildar."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"fá aðgang að IMS-símtalsþjónustu"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 1ed6dce3304f..ece503d74a38 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Consente all\'applicazione di scattare foto e riprendere video con la fotocamera. Questa autorizzazione consente all\'applicazione di utilizzare la fotocamera in qualsiasi momento senza la tua conferma."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controllo vibrazione"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Consente all\'applicazione di controllare la vibrazione."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controllo flash"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Consente all\'applicazione di controllare il flash."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"chiamata diretta n. telefono"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Consente all\'applicazione di chiamare numeri di telefono senza il tuo intervento. Ciò può comportare chiamate o addebiti imprevisti. Tieni presente che ciò non consente all\'applicazione di chiamare numeri di emergenza. Applicazioni dannose potrebbero generare dei costi effettuando chiamate senza la tua conferma."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"Accesso al servizio di chiamata IMS"</string>
@@ -1477,8 +1475,8 @@
<item quantity="other">Per %d ore</item>
<item quantity="one">Per 1 ora</item>
</plurals>
- <string name="zen_mode_until" msgid="7336308492289875088">"Fino alle ore <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
- <string name="zen_mode_alarm" msgid="9128205721301330797">"Fino alle ore <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (prossima sveglia)"</string>
+ <string name="zen_mode_until" msgid="7336308492289875088">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+ <string name="zen_mode_alarm" msgid="9128205721301330797">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (prossima sveglia)"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Fino alla disattivazione"</string>
<string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Fino alla disattivazione di Non disturbare"</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>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index df0471eadbfb..144afc09bb50 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -356,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"מאפשר לאפליקציה לצלם תמונות וסרטונים באמצעות המצלמה. אישור זה מאפשר לאפליקציה להשתמש במצלמה בכל עת ללא אישורך."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"שליטה ברטט"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"מאפשר לאפליקציה לשלוט ברטט."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"שליטה בפנס"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"מאפשר לאפליקציה לשלוט בפנס."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"התקשר ישירות למספרי טלפון"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"מאפשר לאפליקציה להתקשר למספרי טלפון ללא התערבותך. פעולה זו עשויה לגרום לשיחות או לחיובים לא צפויים. שים לב שהדבר לא מאפשר לאפליקציה להתקשר למספרי חירום. אפליקציות זדוניות עשויות לגרום לעלויות על ידי ביצוע שיחות ללא התערבותך."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"‏גישה אל שירות שיחות IMS"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 764e0cfe60cc..edfab2281b72 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"カメラでの写真と動画の撮影をアプリに許可します。これにより、アプリが確認なしでいつでもカメラを使用できるようになります。"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"バイブレーションの制御"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"バイブレーションの制御をアプリに許可します。"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ライトのコントロール"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ライトの制御をアプリに許可します。"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"電話番号発信"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"電話番号への自動発信をアプリに許可します。これにより、予期せぬ発信や料金が発生する可能性があります。なお、緊急通報番号への発信は許可されません。悪意のあるアプリが確認なしで発信し、料金が発生する恐れがあります。"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS通話サービスへのアクセス"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 0fa786cd04fb..ffdd31c14b5d 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"აპს შეეძლება კამერით სურათისა და ვიდეოს გადაღება. ეს ნებართვა აპს უფლებას აძლევს, ნებისმიერ დროს გამოიყენოს კამერა თქვენი დადასტურების გარეშე."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ვიბრაციის კონტროლი"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"აპს შეეძლება, მართოს ვიბრირება."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ფანრის მართვა"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"აპს შეეძლება, მართოს განათება."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"პირდაპირი დარეკვა ტელეფონის ნომრებზე"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"აპს შეეძლება დარეკოს ტელეფონის ნომრებზე თქვენი ჩარევის გარეშე. ამან შესაძლოა გამოიწვიოს თქვენს სატელეფონი ქვითარზე მოულოდნელი ხარჯებისა და ზარების გაჩენა. გაითვალისწინეთ, რომ აპს გადაუდებელი დახმარების ნომრებზე დარეკვა არ შეუძლია. მავნე აპებს შეეძლება თქვენი დადასტურების გარეშე ზარების განხორციელება და შესაბამისი საფასურის გადახდაც მოგიწევთ."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ზარების სერვისზე წვდომა"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 275e5bcbab3a..ff58eaadc82d 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Қолданбаға камераны қолданып, фотосурет немесе бейне жазу мүмкіндігін береді. Бұл рұқсат камераны кез келген уақытта сіздің құптауыңызды қажет етпей қолдану мүмкіндігін береді."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"тербелісті басқару"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Қолданбаға вибраторды басқаруға рұқсат береді."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"сигналдық шамды басқару"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Қолданбаға қалта шамын басқаруға рұқсат береді."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"нөмірлерге тікелей телефон шалу"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Қолданбаға сіздің қатысуыңызсыз қоңырау шалу мүмкіндігін береді. Нәтижесінде қосымша төлем немесе күтпеген қоңырау алуыңыз мүмкін. Есіңізде болсын, қолданба төтенше байланыстарға қоңырау шала алмайды. Залалды қолданбалар сіздің рұқсатыңызсыз қоңыраулар шалып, күтпеген төлемдерге себеп болуы мүмкін."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS қоңырау қызметін пайдалану"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 96abf450cdad..261212fa79bf 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ឲ្យ​កម្មវិធី​ថត​រូប និង​វីដេអូ​ដោយ​ប្រើ​ម៉ាស៊ីន​ថត។ វា​ឲ្យ​កម្មវិធី​​ប្រើ​ម៉ាស៊ីន​ថត​នៅ​ពេល​​ណាមួយ​ដោយ​គ្មាន​ការ​បញ្ជាក់​របស់​អ្នក។"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ពិនិត្យ​ការ​ញ័រ"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ឲ្យ​កម្មវិធី​គ្រប់គ្រង​កម្មវិធី​ញ័រ។"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ត្រួតពិនិត្យ​ពិល"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ឲ្យ​កម្មវិធី​ពិនិត្យ​ពិល។"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ហៅ​លេខ​ទូរស័ព្ទ​ដោយ​ផ្ទាល់"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ឲ្យ​កម្មវិធី​ហៅ​លេខ​ទូរស័ព្ទ​ដោយ​គ្មាន​សកម្មភាព​របស់​អ្នក។​ វា​អាច​កាត់​លុយ​ ឬ​ហៅ​ដោយ​មិន​រំពឹង​ទុក។ ចំណាំ​ថា​ វា​មិន​អនុញ្ញាត​ឲ្យ​កម្មវិធី​ហៅ​លេខ​ពេល​អាសន្ន​ទេ។ កម្មវិធី​ព្យាបាទ​អាច​កាត់​លុយ​របស់​អ្នក​ ដោយ​ធ្វើការ​ហៅ​ដោយ​គ្មាន​ការ​បញ្ជាក់​របស់​អ្នក។"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"ចូលដំណើរការសេវាកម្មការហៅតាម IMS"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index d0dac23cb538..f083702d66ae 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ಕ್ಯಾಮರಾ ಮೂಲಕ ಚಿತ್ರಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಸೆರೆಹಿಡಿಯಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಈ ಅನುಮತಿಯು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ವೈಬ್ರೇಷನ್‌‌ ನಿಯಂತ್ರಿಸಿ"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ವೈಬ್ರೇಟರ್‌ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ನಿಯಂತ್ರಿಸಿ"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ಫೋನ್ ಸಂಖ್ಯೆಗಳಿಗೆ ನೇರವಾಗಿ ಕರೆ ಮಾಡಿ"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ನಿಮ್ಮ ಹಸ್ತಕ್ಷೇಪ ಇಲ್ಲದೆಯೇ ಫೋನ್‍ ಸಂಖ್ಯೆಗಳಿಗೆ ಕರೆ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಇದು ಅನಿರೀಕ್ಷಿತ ಶುಲ್ಕಗಳು ಅಥವಾ ಕರೆಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು. ತುರ್ತು ಸಂಖ್ಯೆಗಳಿಗೆ ಕರೆಮಾಡಲು ಈ ಅಪ್ಲಿಕೇಶನ್‍ ಅನುಮತಿಸುವುದಿಲ್ಲ ಎಂಬುದು ಗಮನದಲ್ಲಿರಲಿ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್‍‍ಗಳು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಕರೆಗಳನ್ನು ಮಾಡುವುದರ ಮೂಲಕ ನಿಮ್ಮ ಹಣ ಖರ್ಚಾಗಬಹುದು."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ಕರೆ ಸೇವೆಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index b1b45883e977..c8f08c77cf8b 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"앱이 카메라로 사진과 동영상을 찍을 수 있도록 허용합니다. 이 권한을 사용하면 앱이 언제든지 사용자의 확인 없이 카메라를 사용할 수 있습니다."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"진동 제어"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"앱이 진동을 제어할 수 있도록 허용합니다."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"카메라 플래시 제어"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"앱이 카메라 플래시를 제어할 수 있도록 허용합니다."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"전화번호 자동 연결"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"앱이 사용자의 조작 없이 전화번호로 전화를 걸 수 있도록 허용합니다. 이 경우 예상치 못한 통화 요금이 부과될 수 있습니다. 앱이 비상 전화를 걸도록 하는 권한은 주어지지 않습니다. 악성 앱이 사용자의 확인 없이 전화를 걸어 요금이 부과될 수 있습니다."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS 통화 서비스에 액세스"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 7644a9b32381..4d8493395b07 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Колдонмого камера аркылуу видео жана сүрөт тартуу уруксатын берет. Бул уруксат, камераны каалаган убакта, сиздин ырастооңузсуз колдонуу уруксатын берет."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"титирөөнү башкаруу"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Колдонмого дирилдегичти көзөмөлдөө мүмкүнчүлүгүн берет."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"кол чыракты көзөмөлдөө"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Колдонмого колчыракты көзөмөлдөө мүмкүнчүлүгүн берет."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"телефон номерлерине түз чалуу"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Колдонмого сиздин катышууңузсуз телефон номурларга чалуу уруксатын берет. Бул сиз күтпөгөн чыгымдарга же чалууларга алып келиши мүмкүн. Бул куткаруучулардын номурларына чалууга уруксат бербей тургандыгын эске алыңыз. Зыяндуу колдонмолор, сиздин ырастооңузсуз чалууларды аткарып, көп чыгымдарга себепкер болушу мүмкүн."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS чалуу кызматына мүмкүнчүлүк алуу"</string>
diff --git a/core/res/res/values-land/config.xml b/core/res/res/values-land/config.xml
new file mode 100644
index 000000000000..7308dc5882c1
--- /dev/null
+++ b/core/res/res/values-land/config.xml
@@ -0,0 +1,19 @@
+<?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>
+ <integer name="config_dockedStackDividerSnapMode">2</integer>
+</resources> \ No newline at end of file
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index a5ff8d18dfa7..12d67bb2d2bf 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ອະນຸຍາດໃຫ້ແອັບຯຖ່າຍຮູບ ແລະວິດີໂອດ້ວຍກ້ອງຖ່າຍຮູບ. ການອະນຸຍາດນີ້ຈະອານຸຍາດໃຫ້ແອັບຯ ສາມາດໃຊ້ກ້ອງຖ່າຍຮູບໄດ້ຕະຫລອດເວລາ ໂດຍບໍ່ຕ້ອງຖ້າການຢືນຢັນຈາກທ່ານ."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ຄວບຄຸມການສັ່ນ"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມໂຕສັ່ນ."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ຄວບຄຸມໄຟແຟລດ"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ອະນຸຍາດໃຫ້ແອັບຯ ຄວບຄຸມໄຟແຟລດ."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ໂທຫາເບີໂທລະສັບໂດຍກົງ"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ອະນຸຍາດໃຫ້ແອັບຯໂທຫາເບີໂທລະສັບໄດ້ ໂດຍບໍ່ຕ້ອງຖ້າການດຳເນີນການໃດໆຈາກທ່ານ. ຄຸນສົມບັດນີ້ອາດກໍ່ໃຫ້ເກີດຄ່າໃຊ້ຈ່າຍໃນການໂທທີ່ບໍ່ຄາດຄິດໄດ້. ໝາຍເຫດ: ຄຸນສົມບັດນີ້ບໍ່ໄດ້ເປັນການອະນຸຍາດໃຫ້ແອັບຯ ສາມາດໂທຫາເບີສຸກເສີນ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດເຮັດໃຫ້ທ່ານ ຕ້ອງເສຍຄ່າໂທໂດຍທີ່ບໍ່ໄດ້ຄາດຄິດ."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"ເຂົ້າ​ຫາ​ການ​ບໍ​ລິ​ການ​ໂທ IMS"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index f59e7542f2dd..e35edd6aa539 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -356,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Leidžiama programai fotografuoti ir filmuoti kamera. Šis leidimas suteikia teisę programai naudoti kamerą bet kada be jūsų patvirtinimo."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"valdyti vibraciją"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Leidžiama programai valdyti vibravimą."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"valdyti šviesos signalą"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Leidžiama programai valdyti šviesos signalą."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"skambinti tiesiogiai telefono numeriais"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Leidžiama programai skambinti telefonų numeriais be jūsų įsikišimo. Dėl to gali atsirasti nenumatytų apmokestinimų ar skambučių. Atminkite, kad programai neleidžiama skambinti pagalbos telefonų numeriais. Kenkėjiškos programos gali skambinti be jūsų patvirtinimo, o dėl to jums gali būti taikomi mokesčiai."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"pasiekti IMS skambučių paslaugą"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d1993edff0b9..de02a4f86796 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -355,8 +355,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ļauj lietotnei uzņemt attēlus un videoklipus ar kameru. Ar šo atļauju lietotne var jebkurā brīdī izmantot kameru bez jūsu apstiprinājuma."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrolēt vibrosignālu"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Ļauj lietotnei kontrolēt vibrosignālu."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolēt uzliesmojumu"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Ļauj lietotnei kontrolēt zibspuldzi."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"tieši zvanīt uz tālruņa numuriem"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Ļauj lietotnei zvanīt uz tālruņa numuriem bez jūsu iejaukšanās. Tas var radīt neparedzētas izmaksas vai zvanus. Ņemiet vērā, ka lietotnei nav atļauts zvanīt uz tālruņa numuriem ārkārtas situācijām. Ļaunprātīgas lietotnes var radīt jums izmaksas, veicot zvanus bez jūsu apstiprinājuma."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"piekļūt tūlītējās ziņojumapmaiņas pakalpojumam, lai veiktu zvanus"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index a3d64ddb937a..96a29a59bf08 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Овозможува апликацијата да прави фотографии и да снима видеа со камерата. Оваа дозвола овозможува апликацијата да ја користи камерата во кое било време без ваша потврда."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"контролирај вибрации"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Дозволува апликацијата да ги контролира вибрациите."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"контролирај сијаличка"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозволува апликацијата да ја контролира батериската ламба."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"директно избирај телефонски броеви"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Овозможува апликацијата да повикува телефонски броеви без ваша интервенција. Ова може да предизвика неочекувани трошоци или повици. Имајте на ум дека ова не дозволува апликацијата да повикува броеви на служби за итна помош. Злонамерните апликации може да ве чинат пари поради повици без ваша потврда."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"пристапи до услугата за повици IMS"</string>
@@ -859,7 +857,7 @@
<string name="cut" msgid="3092569408438626261">"Исечи"</string>
<string name="copy" msgid="2681946229533511987">"Копирај"</string>
<string name="paste" msgid="5629880836805036433">"Залепи"</string>
- <string name="paste_as_plain_text" msgid="5427792741908010675">"Залепете како обичен текст"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Залепи како обичен текст"</string>
<string name="replace" msgid="5781686059063148930">"Замени..."</string>
<string name="delete" msgid="6098684844021697789">"Избриши"</string>
<string name="copyUrl" msgid="2538211579596067402">"Копирај УРЛ"</string>
@@ -1255,7 +1253,7 @@
<string name="media_route_chooser_title" msgid="1751618554539087622">"Поврзи се со уред"</string>
<string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Префрли екран на уред"</string>
<string name="media_route_chooser_searching" msgid="4776236202610828706">"Пребарување за уреди..."</string>
- <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Подесувања"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Поставки"</string>
<string name="media_route_controller_disconnect" msgid="8966120286374158649">"Исклучи"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Скенирање..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Се поврзува..."</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index c6f6698bbe1d..f6869e38a169 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ക്യാമറ ഉപയോഗിച്ച് ചിത്രങ്ങളും വീഡിയോകളും എടുക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ ഏതുസമയത്തും ക്യാമറ ഉപയോഗിക്കാൻ ഈ അനുമതി അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"വൈബ്രേറ്റുചെയ്യൽ നിയന്ത്രിക്കുക"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"വൈബ്രേറ്റർ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ടോർച്ച് നിയന്ത്രിക്കുക"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ഫ്ലാഷ്ലൈറ്റിനെ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ഫോൺ നമ്പറുകളിലേക്ക് നേരിട്ട് വിളിക്കുക"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"നിങ്ങളുടെ ഇടപെടൽ ഇല്ലാതെ ഫോൺ നമ്പറുകളിലേക്ക് കോൾ ചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് അപ്രതീക്ഷിത നിരക്കുകൾക്കോ കോളുകൾക്കോ ഇടയാക്കാം. ഇത് അടിയന്തര നമ്പറുകളിലേക്ക് വിളിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കില്ലെന്ന കാര്യം ശ്രദ്ധിക്കുക. ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ കോളുകൾ ചെയ്യുന്നത് പണച്ചെലവിനിടയാക്കാം."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS കോൾ സേവനം ആക്സസ് ചെയ്യുക"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index c42beca3e221..d982eceb6aac 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Апп нь камераар зураг авах болон видео бичих боломжтой. Энэ зөвшөөрөл нь апп-д ямар ч үед таны зөвшөөрөлгүйгээр камер ашиглах боломжийг олгоно."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"чичиргээг удирдах"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Апп нь чичиргээг удирдах боломжтой."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"гар чийдэн удирдах"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Апп нь гар чийдэнг удирдах боломжтой."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"утасны дугаарт шууд дуудлага хийх"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Апп нь таны оролцоогүйгээр дуудлага хийх боломжтой. Энэ нь төлөвлөгдөөгүй төлбөрт оруулах эсвэл дуудлага хийнэ. Энэ нь апп-г яаралтай дугаарт дуудлага хийхйг зөвшөөрөхгүй. Хортой апп нь таны зөвшөөрөлгүйгээр дуудлага хийж таныг төлбөрт оруулж болзошгүй"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS дуудлагын үйлчилгээнд хандах"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 8bc86e63d0d0..408719926ba9 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"कॅमेर्‍यासह चित्रे आणि व्हिडिओ घेण्यासाठी अॅप ला अनुमती देते. ही परवानगी आपल्या पुष्टीकरणाशिवाय कोणत्याही वेळी कॅमेरा वापरण्यासाठी अॅप ला परवानगी देते."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करा"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"अॅप ला व्हायब्रेटर नियंत्रित करण्यासाठी अनुमती देते."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"फ्लॅशलाइट नियंत्रित करा"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"फ्लॅशलाइट नियंत्रित करण्यासाठी अॅप ला अनुमती देते."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"फोन नंबरवर प्रत्यक्ष कॉल करा"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"आपल्या हस्तक्षेपाशिवाय फोन नंबरवर कॉल करण्यासाठी अॅप ला अनुमती देते. यामुळे अनपेक्षित शुल्क किंवा कॉल लागू शकतात. लक्षात ठेवा की हे आणीबाणीच्या नंबरवर कॉल करण्यासाठी अॅप ला अनुमती देत नाही. दुर्भावनापूर्ण अॅप्स नी आपल्या पुष्टिकरणाशिवाय कॉल केल्यामुळे आपले पैसे खर्च होऊ शकतात."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवेमध्‍ये प्रवेश करा"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index f1249d6201af..0923e912b215 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Membenarkan apl mengambil gambar dan video menggunakan kamera. Kebenaran ini membenarkan apl untuk menggunakan kamera pada bila-bila masa tanpa pengesahan anda."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kawal getaran"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Membenarkan apl mengawal penggetar."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"mengawal lampu suluh"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Membenarkan apl mengawal lampu suluh."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"panggil terus nombor telefon"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Membenarkan apl memanggil nombor telefon tanpa campur tangan anda. Ini mungkin menyebabkan caj atau panggilan yang di luar jangkaan. Apl hasad boleh menyebabkan anda kerugian wang dengan membuat panggilan tanpa pengesahan anda."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"akses perkhidmatan panggilan IMS"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 3393e1289448..3ef7e6cb8d8c 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"အပလီကေးရှင်းအား အလိုအလျောက် ဓာတ်ပုံရိုက်ခွင့်၊ ဗီဒီယို ရိုက်ကူးခွင့် ပြုပါ။ ဒီခွင့်ပြုချက်က အပလီကေးရှင်းကို အချိန်မရွေး ကင်မရာအား ခွင့်ပြုချက် မလိုအပ်ပဲ သုံးခွင့်ပြုပါသည်။"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"တုန်ခုန်မှုအား ထိန်းချုပ်ခြင်း"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"appအား တုန်ခါစက်ကို ထိန်းချုပ်ခွင့် ပြုသည်။"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ဓါတ်မီးအား ထိန်းသိမ်းရန်"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"appအား ကား ဖလက်ရှမီးကို ထိန်းချုပ်ခွင့် ပြုသည်။"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ဖုန်းနံပါတ်များကိုတိုက်ရိုက်ခေါ်ဆိုခြင်း"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"အပလီကေးရှင်းအား အလိုအလျောက် ဖုန်းခေါ်ခွင့် ပြုပါ။ မလိုအပ်သော ဖုန်းခ များ ဖြစ်ပေါ်နိုင်ပါသည်။ ဒီခွင့်ပြုခြင်းမှာ အရေးပေါ်ဖုန်းခေါ်ခြင်း မပါဝင်ပါ။ သံသယဖြစ်စရာ အပလီကေးရှင်းများက သင့်မသိပဲ ဖုန်းခေါ်ခြင်းဖြင့် ဖုန်းခ ပိုမိုကျနိုင်ပါသည်။"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ဖုန်းခေါ်ဆိုမှု ဝန်ဆောင်ဌာန ဝင်ကြည့်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e1ad565bd343..cd65d85255e9 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Appen tillates å ta bilder og filme med kameraet. Det betyr at appen kan bruke kameraet når som helst uten bekreftelse fra deg."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrollere vibreringen"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Lar appen kontrollere vibreringsfunksjonen."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollere lommelykten"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Lar appen kontrollere lommelykten."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ringe telefonnummer direkte"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Lar appen ringe telefonnumre uten at du gjør noe. Dette kan resultere i uventede oppringninger og kostnader. Appen kan imidlertid ikke ringe nødnumre. Merk at skadelige apper kan påføre deg kostnader ved å ringe uten bekreftelse fra deg."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"få tilgang til nettprattjenesten for ringing"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index f94222b16ce1..301094b75d03 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"अनुप्रयोगलाई क्यामेरासँग तस्बिर र भिडियोहरू लिन अनुमति दिन्छ। यस अनुमतिले अनुप्रयोगलाई तपाईंको पुष्टिकरण बिना कुनै पनि समयमा क्यामेरा प्रयोग गर्न स्वीकृति दिन्छ।"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"कम्पन नियन्त्रण गर्नुहोस्"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"अनुप्रयोगलाई भाइब्रेटर नियन्त्रण गर्न अनुमति दिन्छ।"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"फ्ल्यासलाईट नियन्त्रण गर्नुहोस्"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"फ्ल्यास प्रकाशलाई नियन्त्रण गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"फोन नम्बरहरूमा सिधै कल गर्नुहोस्"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"तपाईँको हस्तक्षेप बेगरै फोन नम्बर कल गर्न अनुप्रयोगलाई अनुमति दिन्छ। यसले अनपेक्षित शुल्क वा कलहरू गराउन सक्छ। यसले अनुप्रयोगलाई आपतकालीन नम्बरहरू कल गर्न अनुमति दिँदैन विचार गर्नुहोस्। खराब अनुप्रयोगहरूले तपाईँको स्वीकार बिना कलहरू गरेर तपाईँलाई बढी पैसा तिराउन सक्छ।"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कल सेवा पहुँच गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 1bef95d92ba4..1407991d68bf 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Hiermee kan de app foto\'s en video\'s maken met de camera. Met deze toestemming kan de app de camera altijd gebruiken, zonder je bevestiging."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"trilling beheren"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Hiermee kan de app de trilstand beheren."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"zaklamp bedienen"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Hiermee kan de app de zaklamp bedienen."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefoonnummers rechtstreeks bellen"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Hiermee kan de app zonder je tussenkomst telefoonnummers bellen. Dit kan tot onverwachte kosten of oproepen leiden. De app kan hiermee geen noodnummers bellen. Schadelijke apps kunnen u geld kosten door nummers te bellen zonder om je bevestiging te vragen."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"toegang tot IMS-service voor bellen"</string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 168c66f31570..39f20f5fba52 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ਐਪ ਨੂੰ ਕੈਮਰੇ ਨਾਲ ਤਸਵੀਰਾਂ ਅਤੇ ਵੀਡੀਓ ਲੈਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਕੈਮਰਾ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ਵਾਈਬ੍ਰੇਸ਼ਨ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ਐਪ ਨੂੰ ਵਾਈਬ੍ਰੇਟਰ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ਫਲੈਸ਼ਲਾਈਟ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ਐਪ ਨੂੰ ਫਲੈਸ਼ਲਾਈਟ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ਫੋਨ ਨੰਬਰਾਂ ਤੇ ਸਿੱਧੇ ਕਾਲ ਕਰੋ"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਫੋਨ ਨੰਬਰਾਂ ਤੇ ਕਾਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਸਦੇ ਸਿੱਟੇ ਵਜੋਂ ਅਕਲਪਿਤ ਖ਼ਰਚੇ ਜਾਂ ਕਾਲਾਂ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਧਿਆਨ ਦਿਓ ਕਿ ਇਹ ਐਪ ਨੂੰ ਐਮਰਜੈਂਸੀ ਨੰਬਰਾਂ ਤੇ ਕਾਲ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦਾ। ਖ਼ਰਾਬ ਐਪਸ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਾਲਾਂ ਕਰਕੇ ਤੁਹਾਨੂੰ ਖ਼ਰਚੇ ਪਾ ਸਕਦੇ ਹਨ।"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ਕਾਲ ਸੇਵਾ ਤੱਕ ਪਹੁੰਚ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 80ef7df29f74..f3e50b56815f 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -356,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Pozwala aplikacji na robienie zdjęć i nagrywanie filmów przy użyciu aparatu. Aplikacja z tym uprawnieniem może użyć aparatu w dowolnym momencie bez Twojego potwierdzenia."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"sterowanie wibracjami"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Pozwala aplikacji na sterowanie wibracjami."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolowanie latarki"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Pozwala aplikacji na sterowanie latarką."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"bezpośrednie wybieranie numerów telefonów"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Pozwala aplikacji na dzwonienie pod numery telefonów bez Twojej wiedzy. Może to skutkować nieoczekiwanymi opłatami lub połączeniami. Aplikacja nie może dzwonić pod numery alarmowe. Złośliwe aplikacje mogą generować koszty, wykonując połączenia bez Twojego potwierdzenia."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"usługa telefoniczna z dostępem do komunikatora"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 11e060a0baf5..89bbbe82d714 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que o app controle a vibração."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que o app controle a lanterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ligar diretamente para números de telefone"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que o app ligue para números de telefone sem sua intervenção. Isso pode resultar em cobranças ou chamadas inesperadas. Esta opção não permite que o app ligue para números de emergência. Apps maliciosos podem gerar custos com chamadas feitas sem sua confirmação."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"acessar serviço de mensagens instantâneas para chamadas"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index d76133ab1808..f559dbb3ef1e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que a aplicação tire fotografias e grave vídeos com a câmara. Esta autorização permite que a aplicação utilize a câmara sem a sua confirmação em qualquer altura."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite à aplicação controlar o vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite à aplicação controlar a lanterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone diretamente"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que a aplicação ligue para números de telefone sem a intervenção do utilizador. Esta ação pode resultar em cobranças ou chamadas inesperadas. Tenha em atenção que isto não permite que a aplicação ligue para números de emergência. As aplicações maliciosas podem fazer com que incorra em custos, fazendo chamadas sem a sua confirmação."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"aceder ao serviço de chamadas IMS"</string>
@@ -1478,7 +1476,7 @@
<item quantity="one">Durante 1 h</item>
</plurals>
<string name="zen_mode_until" msgid="7336308492289875088">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
- <string name="zen_mode_alarm" msgid="9128205721301330797">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
+ <string name="zen_mode_alarm" msgid="9128205721301330797">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Até que o utilizador desative"</string>
<string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Até desativar Não incomodar"</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>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 11e060a0baf5..89bbbe82d714 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que o app controle a vibração."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que o app controle a lanterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ligar diretamente para números de telefone"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que o app ligue para números de telefone sem sua intervenção. Isso pode resultar em cobranças ou chamadas inesperadas. Esta opção não permite que o app ligue para números de emergência. Apps maliciosos podem gerar custos com chamadas feitas sem sua confirmação."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"acessar serviço de mensagens instantâneas para chamadas"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 8a78f17c380f..4086e69e2e2f 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -355,8 +355,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite aplicației să realizeze fotografii și videoclipuri cu camera foto. Cu această permisiune aplicația utilizează camera foto oricând și fără confirmare."</string>
<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_flashlight" msgid="2155920810121984215">"control lanternă"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite aplicației să controleze lanterna."</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="permlab_accessImsCallService" msgid="3574943847181793918">"accesează serviciul de apelare IMS"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 0753e93c8307..ee39b83a7166 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -356,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Приложение сможет снимать фотографии и видеоролики с помощью камеры в любое время без вашего разрешения."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"Управление функцией вибросигнала"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Приложение сможет контролировать вибросигналы."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"Управление вспышкой"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Приложение сможет контролировать вспышку."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"Осуществление телефонных вызовов"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Приложение сможет без вашего участия звонить на любой номер телефона. Это не относится к номерам экстренных служб. Вредоносные программы смогут совершать вызовы без вашего разрешения, что может привести к непредвиденным расходам."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"совершение звонков с помощью службы IMS"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index d66b2453d1d4..5364c98dfd7e 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"කැමරාවෙන් පින්තූර ගැනීමට සහ වීඩියෝ කිරීමට යෙදුමට අවසර දෙන්න. මෙම අවසරය මඟින් ඔබගේ අනුදැනුමකින් තොරව ඕනෑම වේලාවකදී කැමරාව භාවිතා කිරීමට යෙදුමට අවසර දෙන්න."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"කම්පනය පාලනය කිරීම"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"කම්පකය පාලනයට යෙදුමට අවසර දෙන්න."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"සැණෙළි ආලෝකය පාලනය කරන්න"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"සැණෙළිය පාලනයට යෙදුමට අවසර දෙන්න."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"දුරකථන අංක වෙත ඍජුවම අමතන්න"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ඔබගේ මැදිහත් වීමක් නොමැතිව දුරකථන අංක ඇමතීමට යෙදුමට අවසර දෙන්න. මෙහි ප්‍රතිඑලය වන්නේ අනපේක්ෂිත අයකිරීම් හෝ ඇමතුම් ඇතිවීමයි. මෙයන් හදිසි අංක වලට ඇමතුම් ගැනීමට යෙදුමට අවසර නොදෙන බවට සටහන් කරගන්න. ඔබගේ අනුදැනුමක් නොමැතිව ඇමතුම් ගැනීමෙන් අනිෂ්ට යෙදුම් ඔබගේ මුදල් නිකරුණේ වැය කරයි."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ඇමතුම් සේවාවට පිවිසෙන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 05c846705bd2..90ccd543a99c 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -356,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikácii fotografovať a nahrávať videá pomocou fotoaparátu. Toto povolenie umožňuje aplikácii používať fotoaparát kedykoľvek a bez vášho potvrdenia."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ovládať vibrovanie"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikácii ovládať vibrácie."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ovládať kontrolku"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikácii ovládať svetlo."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"priamo volať na telefónne čísla"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikácii volať telefónne čísla bez vášho zásahu. V dôsledku toho sa môžu účtovať neočakávané poplatky alebo sa môžu uskutočniť neočakávané hovory. Toto povolenie neumožňuje aplikácii volať na čísla tiesňového volania."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"prístup k službe volania IMS"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index ea5f4c43e192..4e9b1c55c03f 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -356,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogoča fotografiranje in snemanje videoposnetkov s kamero. S tem dovoljenjem lahko aplikacija kadar koli uporablja kamero brez vaše potrditve."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"nadzor vibriranja"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Aplikaciji omogoča nadzor vibriranja."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"nadzor svetilke"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Aplikaciji omogoča nadzor svetilke."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"neposredno klicanje telefonskih številk"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Aplikaciji omogoča klicanje telefonskih številk brez vašega posredovanja. Zaradi tega lahko pride do nepričakovanih stroškov ali klicev. Aplikaciji to ne dovoljuje opravljanja klicev v sili. Zlonamerne aplikacije lahko kličejo brez vaše potrditve, kar vas lahko drago stane."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"dostop do storitve za klicanje IMS"</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 77e0e62b9229..be9c709cd398 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Lejon aplikacion të krijojë fotografi dhe video me kamerën. Kjo leje mundëson përdorimin e kamerës në çdo kohë pa konfirmimin tënd."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrollo dridhjen"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Lejon aplikacionin të kontrollojë dridhësin."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollo elektrikun"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Lejon aplikacionin të kontrollojë elektrikun."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefono drejtpërdrejt numrat e telefonit"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Lejon aplikacionin të telefonojë numra pa ndërhyrjen tënde. Kjo mund të rezultojë në tarifa ose telefonata të papritura. Ki parasysh se kjo nuk e lejon aplikacionin të telefonojë numra urgjence. Aplikacione keqdashëse mund të të kushtojnë para duke kryer telefonata pa konfirmimin tënd."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"qasje në shërbimin e telefonatave IMS"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 242341843b0c..a3618ab5e2f2 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -355,8 +355,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Дозвољава апликацији да снима слике и видео снимке камером. Ова дозвола омогућава апликацији да у било ком тренутку користи камеру без ваше потврде."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"контрола вибрације"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Дозвољава апликацији да контролише вибрацију."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"контрола осветљења"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозвољава апликацији да контролише блиц."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"директно позивање бројева телефона"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Дозвољава апликацији да позива бројеве телефона без ваше дозволе. Ово може да доведе до неочекиваних трошкова или позива. Имајте на уму да ово не дозвољава апликацији да позива бројеве за хитне случајеве. Злонамерне апликације могу да позивају без ваше потврде, што може да доведе до трошкова."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"приступ услузи позива помоћу размене тренутних порука"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index cdf252e7f359..b07dc285e128 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Tillåter att appen tar bilder och spelar in videor med kameran. Med den här behörigheten tillåts appen att använda kameran när som helst utan ditt godkännande."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"styra vibration"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Tillåter att appen styr vibrationen."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"styra lampa"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Tillåter att appen styr lampan."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ringa telefonnummer direkt"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Tillåter att appen ringer telefonnummer utan någon aktiv åtgärd från dig. Detta kan leda till oväntade avgifter och samtal. Observera att appen inte tillåts ringa nödsamtal. Skadliga appar kan ringa utan ditt godkännande och detta kan kosta pengar."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"tillgång till tjänsten för snabbmeddelanden vid samtal"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 5e618bfd0a2c..cf0063c7254a 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -356,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Inaruhusu programu kupiga picha na video kwa kamera. Kibali hiki kinaruhusu programu kutumia kamera kwa wakati wowote bila uthibitisho wako."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"Kudhibiti mtetemo"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Inaruhusu programu kudhibiti kitingishi."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"dhibiti tochi"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Inaruhusu programu kudhibiti tochi."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"piga simu moja kwa moja kwa nambari za simu"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Inaruhusu programu kupiga nambari za simu bila ya wewe kuingilia kati. Hii inaweza kusababisha gharama zisizotarajiwa au simu. Kumbuka kuwa hii hairuhusu programu kupiga nambari za dharura. Programu hasidi zinaweza kukugharimu pesa kwa kupiga simu bila uthibitisho wako."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"fikia huduma ya simu ya IMS"</string>
@@ -795,7 +793,7 @@
<string name="save_password_remember" msgid="6491879678996749466">"Kumbuka"</string>
<string name="save_password_never" msgid="8274330296785855105">"Katu"</string>
<string name="open_permission_deny" msgid="7374036708316629800">"Hauna idhini ya kufungua ukurasa huu."</string>
- <string name="text_copied" msgid="4985729524670131385">"Maandishi yamenakiliwa kwenye ubao klipu."</string>
+ <string name="text_copied" msgid="4985729524670131385">"Maandishi yamenakiliwa kwenye ubao wa kunakili."</string>
<string name="more_item_label" msgid="4650918923083320495">"Zaidi"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"Menyu+"</string>
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"mwanya"</string>
diff --git a/core/res/res/values-sw600dp/config.xml b/core/res/res/values-sw600dp/config.xml
index 5a007ce97483..7f57ded0521e 100644
--- a/core/res/res/values-sw600dp/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -40,5 +40,6 @@
<!-- Use a larger scaling span for larger screen devices. -->
<dimen name="config_minScalingSpan">32mm</dimen>
+ <integer name="config_dockedStackDividerSnapMode">1</integer>
</resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 7e0ab5eb88dc..ecefb7755f4e 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"கேமரா மூலமாகப் படங்களையும், வீடியோக்களையும் எடுக்க பயன்பாட்டை அனுமதிக்கிறது. உங்கள் உறுதிப்படுத்தல் இன்றி கேமராவை எந்நேரத்திலும் பயன்படுத்தப் பயன்பாட்டை இது அனுமதிக்கிறது."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"அதிர்வைக் கட்டுப்படுத்துதல்"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"அதிர்வைக் கட்டுப்படுத்தப் பயன்பாட்டை அனுமதிக்கிறது."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ஃப்லாஷ்லைட்டை இயக்குதல்"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ஃப்ளாஷ் லைட்டைக் கட்டுப்படுத்த, பயன்பாட்டை அனுமதிக்கிறது."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"தொலைபேசி எண்களை நேரடியாக அழைத்தல்"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"உங்கள் தலையீட்டின்றி மொபைல் எண்களை அழைக்கப் பயன்பாட்டை அனுமதிக்கிறது. இதன் விளைவாக எதிர்பாராத கட்டணங்களோ அழைப்புகளோ ஏற்படலாம். அவசரகால எண்களை அழைக்க இது பயன்பாட்டை அனுமதிக்காது என்பதை நினைவில்கொள்ளவும். தீங்கிழைக்கும் பயன்பாடுகள், உங்கள் உறுதிப்படுத்தல் இன்றி அழைப்புகளைச் செய்வதால் உங்களுக்குச் செலவு ஏற்படக்கூடும்."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS அழைப்புச் சேவையை அணுகுதல்"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 87b782fff2b9..b1bccd2987d7 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"కెమెరాతో చిత్రాలు మరియు వీడియోలను తీయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఈ అనుమతి మీ నిర్ధారణ లేకుండానే ఎప్పుడైనా కెమెరాను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"వైబ్రేషన్‌ను నియంత్రించడం"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"వైబ్రేటర్‌ను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ఫ్లాష్‌కాంతిని నియంత్రించడం"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ఫ్లాష్‌లైట్‌ను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ఫోన్ నంబర్‌లకు నేరుగా కాల్ చేయడం"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్‌లకు కాల్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్‌లు రావచ్చు. ఇది అత్యవసర నంబర్‌లకు కాల్ చేయడానికి అనువర్తనాన్ని అనుమతించదని గుర్తుంచుకోండి. హానికరమైన అనువర్తనాలు మీ నిర్ధారణ లేకుండానే కాల్‌లు చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS కాల్ సేవ ప్రాప్యత అనుమతి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 2ec0f4c51ced..0b8e60d68987 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"อนุญาตให้แอปพลิเคชันถ่ายภาพและวิดีโอด้วยกล้องถ่ายรูปนี้ การอนุญาตนี้จะทำให้แอปพลิเคชันสามารถใช้กล้องถ่ายรูปได้ทุกเมื่อโดยไม่ต้องรอการยืนยันจากคุณ"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ควบคุมการสั่นเตือน"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"อนุญาตให้แอปพลิเคชันควบคุมการสั่นเตือน"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ควบคุมไฟฉาย"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"อนุญาตให้แอปพลิเคชันควบคุมไฟฉาย"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"โทรติดต่อหมายเลขโทรศัพท์โดยตรง"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"อนุญาตให้แอปพลิเคชันโทรเข้าโทรศัพท์โดยไม่ต้องให้คุณจัดการ ซึ่งอาจทำให้มีการเรียกเก็บเงินหรือการโทรที่ไม่คาดคิด โปรดทราบว่าการทำงานนี้ไม่ได้อนุญาตให้แอปพลิเคชันโทรไปหมายเลขฉุกเฉิน แอปพลิเคชันที่เป็นอันตรายอาจทำให้คุณต้องเสียค่าบริการด้วยการโทรโดยไม่ขอการยืนยันจากคุณ"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"เข้าถึงบริการโทร IMS"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 36aa9d95dee9..02a3587759d9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Pinapayagan ang app na kumuha ng mga larawan at video gamit ang camera. Pinapayagan ng pahintulot na ito ang app na gamitin ang camera anumang oras nang wala ng iyong kumpirmasyon."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrolin ang pag-vibrate"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Pinapayagan ang app na kontrolin ang vibrator."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolin ang flashlight"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Pinapayagan ang app na kontrolin ang flashlight."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"direktang tawagan ang mga numero ng telepono"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Pinapayagan ang app na tumawag sa mga numero ng telepono nang wala ng iyong panghihimasok. Maaari itong magresulta sa mga hindi inaasahang pagsingil o tawag. Tandaan na hindi nito pinapayagan ang app na tumawag sa mga numerong pang-emergency. Maaaring magpagastos sa iyo ng pera ang nakakahamak na apps sa pamamagitan ng pagtawag nang wala ng iyong kumpirmasyon."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"i-access ang serbisyo sa tawag ng IMS"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 7b0bdc681135..283bcebb887d 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Uygulamaya kamerayla fotoğraf ve video çekme izni verir. Bu izin, uygulamanın sizin onayınız olmadan istediği zaman kamerayı kullanmasına olanak sağlar."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"titreşimi denetleme"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Uygulamaya, titreşimi denetleme izni verir."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"el fenerini denetle"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Uygulamaya, el fenerini denetleme izni verir."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefon numaralarına doğrudan çağrı yap"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Uygulamaya sizin müdahaleniz olmadan telefon numaralarına çağrı yapma izni verir. Bu durum beklenmeyen ödemelere veya çağrılara neden olabilir. Ancak bu iznin, uygulamanın acil numaralara çağrı yapmasına olanak sağlamadığını unutmayın. Kötü amaçlı uygulamalar onayınız olmadan çağrılar yaparak sizi zarara sokabilir."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS çağrı hizmetine erişme"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 308e50cba07c..fce4cc3909b0 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -356,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Дозволяє програмі фотографувати та знімати відео за допомогою камери. Такий дозвіл дає програмі змогу будь-коли використовувати камеру без вашого підтвердження."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"контролювати вібросигнал"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Дозволяє програмі контролювати вібросигнал."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"контр. блим. світло"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозволяє програмі контролювати світловий сигнал."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"прямо набирати номери тел."</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Дозволяє програмі набирати номери телефону без вашого відома. Це може спричинити неочікуване стягнення плати чи здійснення дзвінків. Зауважте, що це не дозволяє програмі набирати екстрені номери. Шкідливі програми можуть здійснювати дзвінки без вашого підтвердження, за що з вас стягуватимуться кошти."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"отримувати доступ до телефонної служби IMS"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index ca26e9b3bd6a..519f42b67272 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ایپ کو کیمرے سے تصویریں لینے اور ویڈیوز بنانے کی اجازت دیتا ہے۔ یہ اجازت ایپ کو آپ کی تصدیق کے بغیر کسی بھی وقت کیمرا استعمال کرنے کی اجازت دیتی ہے۔"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ارتعاش کو کنٹرول کریں"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ایپ کو وائبریٹر کنٹرول کرنے کی اجازت دیتا ہے۔"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"فلیش لائٹ کنٹرول"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ایپ کو فلیش لائٹ کنٹرول کرنے کی اجازت دیتا ہے۔"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"براہ راست فون نمبرز پر کال کریں"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ایپ کو آپ کی مداخلت کے بغیر فون نمبروں پر کال کرنے کی اجازت دیتا ہے۔ اس کے نتیجے میں غیر متوقع چارجز یا کالیں ہوسکتی ہیں۔ نوٹ کرلیں کہ یہ ایپ کو ہنگامی نمبروں پر کال کرنے کی اجازت نہیں دیتا ہے۔ نقصان دہ ایپس آپ کی تصدیق کے بغیر کالیں کرکے آپ کی رقم صرف کروا سکتے ہیں۔"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"‏IMS کال سروس تک رسائی حاصل کریں"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 3f3d151c039b..e90d921dc40b 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ilovaga kameradan foydalanib rasm va videoga olishga ruxsat beradi. Bu ruxsat ilovaga sizdan tasdiqlashni so‘ramasdan kameradan foydalanishga imkon beradi."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"tebranishni boshqarish"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Ilova tebranishli signallarni boshqarishi mumkin."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"chiroq chaqnashini boshqarish"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Ilova chaqnoqni boshqarishi mumkin."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefon raqamlariga tog‘ridan to‘g‘ri qo‘ng‘iroq qilish"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Ilovaga sizning yordamingizsiz telefonga qo‘ng‘iroq qilish imkonini beradi. Bu kutilmagan qo‘ng‘iroqlarni amalga oshirishi yoki ortiqcha to‘lovlarni yuzaga keltirishi mumkin. Shunga e’tibor qilinki, u favqulodda telefon raqamlariga qo‘ng‘iroqlar qilishga ruxsat bermaydi. Zararli ilovalar sizdan so‘ramasdan qo‘ng‘iroqlarni amalga oshirib, pulingizni sarflashi mumkin."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS qo‘ng‘iroq xizmatiga kirish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index c538684e06c8..31e090bc6c99 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Cho phép ứng dụng chụp ảnh và quay video bằng máy ảnh. Quyền này cho phép ứng dụng sử dụng máy ảnh bất kỳ lúc nào mà không cần sự xác nhận của bạn."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kiểm soát rung"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Cho phép ứng dụng kiểm soát bộ rung."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kiểm soát đèn nháy"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Cho phép ứng dụng kiểm soát đèn nháy."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"gọi trực tiếp số điện thoại"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Cho phép ứng dụng gọi các số điện thoại mà không cần sự can thiệp của bạn. Việc này có thể dẫn đến các khoản phí hoặc cuộc gọi không mong muốn. Lưu ý rằng quyền này không cho phép ứng dụng gọi các số khẩn cấp. Các ứng dụng độc hại có thể khiến bạn tốn tiền do thực hiện cuộc gọi mà không cần sự xác nhận của bạn."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"truy cập dịch vụ gọi điện qua IMS"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index cef00973a30a..c5cd59af735e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"允许该应用使用相机拍摄照片和视频。此权限可让该应用随时使用相机,而无需您的确认。"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"控制振动"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"允许应用控制振动器。"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"控制闪光灯"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"允许应用控制闪光灯。"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"直接拨打电话号码"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"允许该应用在您未执行操作的情况下拨打电话号码。此权限可能会导致意外收费或呼叫。请注意,此权限不允许该应用拨打紧急电话号码。恶意应用可通过拨打电话产生相关费用,而无需您的确认。"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"使用即时通讯通话服务"</string>
@@ -859,15 +857,13 @@
<string name="cut" msgid="3092569408438626261">"剪切"</string>
<string name="copy" msgid="2681946229533511987">"复制"</string>
<string name="paste" msgid="5629880836805036433">"粘贴"</string>
- <!-- no translation found for paste_as_plain_text (5427792741908010675) -->
- <skip />
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"以纯文本形式粘贴"</string>
<string name="replace" msgid="5781686059063148930">"替换..."</string>
<string name="delete" msgid="6098684844021697789">"删除"</string>
<string name="copyUrl" msgid="2538211579596067402">"复制网址"</string>
<string name="selectTextMode" msgid="1018691815143165326">"选择文字"</string>
<string name="undo" msgid="7905788502491742328">"撤消"</string>
- <!-- no translation found for redo (7759464876566803888) -->
- <skip />
+ <string name="redo" msgid="7759464876566803888">"重做"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"文字选择"</string>
<string name="addToDictionary" msgid="4352161534510057874">"添加到字典"</string>
<string name="deleteText" msgid="6979668428458199034">"删除"</string>
@@ -1113,8 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知侦听器"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"条件提供程序"</string>
- <!-- no translation found for notification_assistant_binding_label (909456055569102952) -->
- <skip />
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知助手"</string>
<string name="vpn_title" msgid="19615213552042827">"已激活VPN"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g>已激活VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 612efe4a0248..36ba2ad610f2 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限允許應用程式隨時使用相機,而不需經您確認。"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"控制震動"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"允許應用程式控制震動。"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"允許應用程式控制閃光燈。"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"允許應用程式繞過您自行撥打電話號碼,但可能會產生未預期的費用或撥打未預期的電話。注意:這項權限不允許應用程式撥打緊急電話。惡意應用程式可能未經您確認擅自撥打電話,增加您的支出。"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"使用 IMS 通話服務"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 201cc1e365c2..72ea52395ed2 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限可讓應用程式隨時使用相機,而不需請求您進行確認。"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"控制震動"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"允許應用程式控制震動。"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"允許應用程式控制閃光燈。"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"允許應用程式自行撥打電話,但可能產生非預期的費用或撥打非預期的電話。注意:這項權限不允許應用程式撥打緊急電話。惡意應用程式可能利用此功能擅自撥打電話,增加您不必要的額外支出。"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"存取 IMS 撥號服務"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 5e835e39df1b..bee7eeaa55c9 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -354,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ivumela uhlelo lokusebenza ukuthatha izithombe namavidiyo ngekhamera. Le mvume ivumela uhlelo lokusebenza ukusebenzisa ikhamera nganoma isiphi isikhathi ngaphandle kwemvume yakho."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"lawula ukudlidliza"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Ivumela uhlelo lokusebenza ukulawula isidlidlizi."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"lawula ukukhanya kwefulashi"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Ivumela uhlelo lokusebenza ukulawula ukukhanya kwefuleshi."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ngokuqondile shayela izinombolo zocingo"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Ivumela uhlelo lokusebenza ukushayela izinombolo zefoni ngaphandle kokuhlanganyela kwakho. Lokhu kungaholela emashajini noma amakholi angalindelekile. Qaphela ukuthi lokhu akuvumeli uhlelo lokusebenza ukushayela izinombolo zesimo esiphuthumayo. Izinhlelo zokusebenza ezingalungile zingabiza imali ngokwenze amakholi ngaphandle kokuqinisekisa kwakho."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"finyelela kusevisi yekholi ye-IMS"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 2a1108155f17..58a77e809235 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1857,6 +1857,11 @@
<attr name="lockTaskMode" />
<attr name="showForAllUsers" />
<attr name="encryptionAware" />
+ <!-- @hide This activity is always focusable regardless of if it is in a task/stack whose
+ activities are normally not focusable.
+ For example, {@link android.R.attr#supportsPictureInPicture} activities are placed
+ in a task/stack that isn't focusable. This flag allows them to be focusable.-->
+ <attr name="alwaysFocusable" format="boolean" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c03d4711120e..d13a6227c04f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2410,4 +2410,11 @@
<!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
<string translatable="false" name="config_defaultPictureInPictureBounds">"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)
+ 2 - 1 snap target: 1:1
+ -->
+ <integer name="config_dockedStackDividerSnapMode">0</integer>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index ec24af51ac05..37b2c1288d91 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -47,7 +47,7 @@
<!-- How much the content in the divider is inset from the window bounds when resting. Used to
calculate the bounds of the stacks-->
- <dimen name="docked_stack_divider_insets">18dp</dimen>
+ <dimen name="docked_stack_divider_insets">19dp</dimen>
<!-- Min width for a tablet device -->
<dimen name="min_xlarge_screen_width">800dp</dimen>
@@ -429,4 +429,6 @@
<item type="dimen" format="integer" name="time_picker_column_start_material">0</item>
<item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
+
+ <item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
</resources>
diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml
index dae7a2eb3d89..3cfd9f4be0ce 100644
--- a/core/res/res/values/locale_config.xml
+++ b/core/res/res/values/locale_config.xml
@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* //device/apps/common/assets/res/any/colors.xml
-**
-** Copyright 2006, The Android Open Source Project
+** 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.
@@ -51,6 +49,7 @@
<item>ar-SY</item> <!-- Arabic (Syria) -->
<item>ar-TD</item> <!-- Arabic (Chad) -->
<item>ar-TN</item> <!-- Arabic (Tunisia) -->
+ <item>ar-XB</item> <!-- Right-to-left pseudolocale -->
<item>ar-YE</item> <!-- Arabic (Yemen) -->
<item>as-IN</item> <!-- Assamese (India) -->
<item>asa-TZ</item> <!-- Asu (Tanzania) -->
@@ -197,6 +196,7 @@
<item>en-VI</item> <!-- English (U.S. Virgin Islands) -->
<item>en-VU</item> <!-- English (Vanuatu) -->
<item>en-WS</item> <!-- English (Samoa) -->
+ <item>en-XA</item> <!-- Left-to-right pseudolocale -->
<item>en-ZA</item> <!-- English (South Africa) -->
<item>en-ZM</item> <!-- English (Zambia) -->
<item>en-ZW</item> <!-- English (Zimbabwe) -->
@@ -332,7 +332,6 @@
<item>ko-KP</item> <!-- Korean (North Korea) -->
<item>ko-KR</item> <!-- Korean (South Korea) -->
<item>kok-IN</item> <!-- Konkani (India) -->
- <item>ks-IN</item> <!-- Kashmiri (India) -->
<item>ksb-TZ</item> <!-- Shambala (Tanzania) -->
<item>ksf-CM</item> <!-- Bafia (Cameroon) -->
<item>ksh-DE</item> <!-- Colognian (Germany) -->
@@ -347,8 +346,6 @@
<item>ln-CF</item> <!-- Lingala (Central African Republic) -->
<item>ln-CG</item> <!-- Lingala (Congo (Republic)) -->
<item>lo-LA</item> <!-- Lao (Laos) -->
- <item>lrc-IQ</item> <!-- Northern Luri (Iraq) -->
- <item>lrc-IR</item> <!-- Northern Luri (Iran) -->
<item>lt-LT</item> <!-- Lithuanian (Lithuania) -->
<item>lu-CD</item> <!-- Luba-Katanga (Congo (DRC)) -->
<item>luo-KE</item> <!-- Luo (Kenya) -->
@@ -369,7 +366,6 @@
<item>ms-MY</item> <!-- Malay (Malaysia) -->
<item>ms-SG</item> <!-- Malay (Singapore) -->
<item>mt-MT</item> <!-- Maltese (Malta) -->
- <item>mua-CM</item> <!-- Mundang (Cameroon) -->
<item>my-MM</item> <!-- Burmese (Myanmar (Burma)) -->
<item>mzn-IR</item> <!-- Mazanderani (Iran) -->
<item>naq-NA</item> <!-- Nama (Namibia) -->
@@ -433,8 +429,6 @@
<item>seh-MZ</item> <!-- Sena (Mozambique) -->
<item>ses-ML</item> <!-- Koyraboro Senni (Mali) -->
<item>sg-CF</item> <!-- Sango (Central African Republic) -->
- <item>shi-Latn-MA</item> <!-- Tachelhit (Latin,Morocco) -->
- <item>shi-Tfng-MA</item> <!-- Tachelhit (Tifinagh,Morocco) -->
<item>si-LK</item> <!-- Sinhala (Sri Lanka) -->
<item>sk-SK</item> <!-- Slovak (Slovakia) -->
<item>sl-SI</item> <!-- Slovenian (Slovenia) -->
@@ -484,8 +478,6 @@
<item>uz-Arab-AF</item> <!-- Uzbek (Arabic,Afghanistan) -->
<item>uz-Cyrl-UZ</item> <!-- Uzbek (Cyrillic,Uzbekistan) -->
<item>uz-Latn-UZ</item> <!-- Uzbek (Latin,Uzbekistan) -->
- <item>vai-Latn-LR</item> <!-- Vai (Latin,Liberia) -->
- <item>vai-Vaii-LR</item> <!-- Vai (Vai,Liberia) -->
<item>vi-VN</item> <!-- Vietnamese (Vietnam) -->
<item>vun-TZ</item> <!-- Vunjo (Tanzania) -->
<item>wae-CH</item> <!-- Walser (Switzerland) -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 347f2f912e41..be9ba62baa3a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1026,11 +1026,6 @@
<string name="permdesc_vibrate">Allows the app to control the vibrator.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_flashlight">control flashlight</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_flashlight">Allows the app to control the flashlight.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_callPhone">directly call phone numbers</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_callPhone">Allows the app to call phone numbers
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 74ebf266910a..8485e59be5a9 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -432,6 +432,8 @@ please see styles_device_defaults.xml.
<item name="textSize">@dimen/notification_text_size</item>
</style>
+ <style name="TextAppearance.Material.Notification.Reply" />
+
<style name="TextAppearance.Material.Notification.Title">
<item name="textColor">@color/primary_text_default_material_light</item>
<item name="textSize">@dimen/notification_title_text_size</item>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index 05835e7b41ab..7dde5f8fc96a 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -26,6 +26,10 @@
<item name="taskOpenExitAnimation">@null</item>
<item name="taskCloseEnterAnimation">@null</item>
<item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
+ <item name="taskToFrontEnterAnimation">@anim/slide_in_micro</item>
+ <item name="taskToFrontExitAnimation">@null</item>
+ <item name="taskToBackEnterAnimation">@null</item>
+ <item name="taskToBackExitAnimation">@anim/slide_out_micro</item>
<item name="wallpaperOpenEnterAnimation">@null</item>
<item name="wallpaperOpenExitAnimation">@anim/slide_out_micro</item>
<item name="wallpaperCloseEnterAnimation">@anim/slide_in_micro</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b40fc3b87cb9..845c8c935ab9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1492,6 +1492,8 @@
<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="integer" name="config_dockedStackDividerSnapMode" />
+ <java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
<java-symbol type="dimen" name="navigation_bar_height" />
<java-symbol type="dimen" name="navigation_bar_height_landscape" />
<java-symbol type="dimen" name="navigation_bar_width" />
@@ -2366,6 +2368,11 @@
<java-symbol type="id" name="addToDictionaryButton" />
<java-symbol type="id" name="deleteButton" />
+ <java-symbol type="id" name="notification_material_reply_container" />
+ <java-symbol type="id" name="notification_material_reply_text_1" />
+ <java-symbol type="id" name="notification_material_reply_text_2" />
+ <java-symbol type="id" name="notification_material_reply_text_3" />
+
<java-symbol type="string" name="notification_children_count_bracketed" />
<java-symbol type="string" name="notification_hidden_text" />
<java-symbol type="id" name="app_name_text" />
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 7cd25afe5bcd..ee8921ef8228 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -22,7 +22,7 @@ LOCAL_SRC_FILES := \
$(call all-java-files-under, EnabledTestApp/src)
LOCAL_DX_FLAGS := --core-library
-LOCAL_AAPT_FLAGS = -0 dat -0 gld
+LOCAL_AAPT_FLAGS = -0 dat -0 gld -c fa
LOCAL_STATIC_JAVA_LIBRARIES := \
core-tests-support \
android-common \
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 51778361291d..c0453f8ac991 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -146,6 +146,16 @@
</intent-filter>
</activity>
+ <activity android:name="android.widget.DatePickerActivity"
+ android:label="DatePickerActivity"
+ android:screenOrientation="portrait"
+ android:theme="@android:style/Theme.Material.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.widget.focus.DescendantFocusability" android:label="DescendantFocusability">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/res/layout/datepicker_layout.xml b/core/tests/coretests/res/layout/datepicker_layout.xml
new file mode 100644
index 000000000000..a79f87d97aa9
--- /dev/null
+++ b/core/tests/coretests/res/layout/datepicker_layout.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <DatePicker
+ android:id="@+id/datePicker"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"/>
+ <EditText
+ android:id="@+id/belowPicker"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Some Text"
+ android:textAlignment="center"
+ android:layout_below="@id/datePicker"/>
+</RelativeLayout>
diff --git a/core/tests/coretests/res/values-fa/strings.xml b/core/tests/coretests/res/values-fa/strings.xml
new file mode 100644
index 000000000000..c83f5f1bebf4
--- /dev/null
+++ b/core/tests/coretests/res/values-fa/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="dummy_string">رشتهٔ الکی</string>
+</resources>
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index 04b0478c96d1..ef915bba1013 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -139,4 +139,7 @@
<!-- RestrictionsManagerTest -->
<string name="restrictionManager_title">Title</string>
<string name="restrictionManager_desc">Description</string>
+
+ <!-- ResourcesLocaleResolutionTest -->
+ <string name="dummy_string">dummy string</string>
</resources>
diff --git a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java b/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
deleted file mode 100644
index 37495e135725..000000000000
--- a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
+++ /dev/null
@@ -1,77 +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.content.pm;
-
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.MessageDigest;
-
-public class ManifestDigestTest extends AndroidTestCase {
- private static final byte[] MESSAGE_1 = {
- (byte) 0x00, (byte) 0xAA, (byte) 0x55, (byte) 0xFF
- };
-
- public void testManifestDigest_FromInputStream_Null() {
- assertNull("Attributes were null, so ManifestDigest.fromAttributes should return null",
- ManifestDigest.fromInputStream(null));
- }
-
- public void testManifestDigest_FromInputStream_ThrowsIoException() {
- InputStream is = new InputStream() {
- @Override
- public int read() throws IOException {
- throw new IOException();
- }
- };
-
- assertNull("InputStream threw exception, so ManifestDigest should be null",
- ManifestDigest.fromInputStream(is));
- }
-
- public void testManifestDigest_Equals() throws Exception {
- InputStream is = new ByteArrayInputStream(MESSAGE_1);
-
- ManifestDigest expected =
- new ManifestDigest(MessageDigest.getInstance("SHA-256").digest(MESSAGE_1));
-
- ManifestDigest actual = ManifestDigest.fromInputStream(is);
- assertEquals(expected, actual);
-
- ManifestDigest unexpected = new ManifestDigest(new byte[0]);
- assertFalse(unexpected.equals(actual));
- }
-
- public void testManifestDigest_Parcel() throws Exception {
- InputStream is = new ByteArrayInputStream(MESSAGE_1);
-
- ManifestDigest digest = ManifestDigest.fromInputStream(is);
-
- Parcel p = Parcel.obtain();
- digest.writeToParcel(p, 0);
- p.setDataPosition(0);
-
- ManifestDigest fromParcel = ManifestDigest.CREATOR.createFromParcel(p);
-
- assertEquals("ManifestDigest going through parceling should be the same as before: "
- + digest.toString() + " and " + fromParcel.toString(), digest,
- fromParcel);
- }
-}
diff --git a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
index 9b216cba0bd5..d963812db622 100644
--- a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
+++ b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
@@ -16,7 +16,6 @@
package android.content.pm;
-import android.content.pm.ManifestDigest;
import android.content.pm.VerificationParams;
import android.net.Uri;
import android.os.Parcel;
@@ -33,7 +32,6 @@ public class VerificationParamsTest extends AndroidTestCase {
private final static String VERIFICATION_URI_STRING = "http://verification.uri/path";
private final static String ORIGINATING_URI_STRING = "http://originating.uri/path";
private final static String REFERRER_STRING = "http://referrer.uri/path";
- private final static byte[] DIGEST_BYTES = "fake digest".getBytes();
private final static int INSTALLER_UID = 42;
private final static Uri VERIFICATION_URI = Uri.parse(VERIFICATION_URI_STRING);
@@ -42,11 +40,9 @@ public class VerificationParamsTest extends AndroidTestCase {
private final static int ORIGINATING_UID = 10042;
- private final static ManifestDigest MANIFEST_DIGEST = new ManifestDigest(DIGEST_BYTES);
-
public void testParcel() throws Exception {
VerificationParams expected = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
Parcel parcel = Parcel.obtain();
expected.writeToParcel(parcel, 0);
@@ -61,85 +57,70 @@ public class VerificationParamsTest extends AndroidTestCase {
assertEquals(REFERRER, actual.getReferrer());
assertEquals(ORIGINATING_UID, actual.getOriginatingUid());
-
- assertEquals(MANIFEST_DIGEST, actual.getManifestDigest());
}
public void testEquals_Success() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertEquals(params1, params2);
}
public void testEquals_VerificationUri_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse("http://a.different.uri/"), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertFalse(params1.equals(params2));
}
public void testEquals_OriginatingUri_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertFalse(params1.equals(params2));
}
public void testEquals_Referrer_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse("http://a.different.uri/"), ORIGINATING_UID,
- new ManifestDigest(DIGEST_BYTES));
+ Uri.parse("http://a.different.uri/"), ORIGINATING_UID);
assertFalse(params1.equals(params2));
}
public void testEquals_Originating_Uid_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
-
- VerificationParams params2 = new VerificationParams(
- Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), 12345, new ManifestDigest(DIGEST_BYTES));
-
- assertFalse(params1.equals(params2));
- }
-
- public void testEquals_ManifestDigest_Failure() throws Exception {
- VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID,
- new ManifestDigest("a different digest".getBytes()));
+ Uri.parse(REFERRER_STRING), 12345);
assertFalse(params1.equals(params2));
}
public void testEquals_InstallerUid_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
params2.setInstallerUid(INSTALLER_UID);
assertFalse(params1.equals(params2));
@@ -147,78 +128,65 @@ public class VerificationParamsTest extends AndroidTestCase {
public void testHashCode_Success() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertEquals(params1.hashCode(), params2.hashCode());
}
public void testHashCode_VerificationUri_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(null, Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertFalse(params1.hashCode() == params2.hashCode());
}
public void testHashCode_OriginatingUri_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertFalse(params1.hashCode() == params2.hashCode());
}
public void testHashCode_Referrer_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING), null,
- ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ ORIGINATING_UID);
assertFalse(params1.hashCode() == params2.hashCode());
}
public void testHashCode_Originating_Uid_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
-
- VerificationParams params2 = new VerificationParams(
- Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), 12345, new ManifestDigest(DIGEST_BYTES));
-
- assertFalse(params1.hashCode() == params2.hashCode());
- }
-
- public void testHashCode_ManifestDigest_Failure() throws Exception {
- VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID,
- new ManifestDigest("a different digest".getBytes()));
+ Uri.parse(REFERRER_STRING), 12345);
assertFalse(params1.hashCode() == params2.hashCode());
}
public void testHashCode_InstallerUid_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID,
- new ManifestDigest("a different digest".getBytes()));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
params2.setInstallerUid(INSTALLER_UID);
assertFalse(params1.hashCode() == params2.hashCode());
diff --git a/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java b/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java
new file mode 100644
index 000000000000..55c00314ee63
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java
@@ -0,0 +1,53 @@
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.content.res;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.DisplayMetrics;
+import android.util.LocaleList;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+public class ResourcesLocaleResolutionTest extends AndroidTestCase {
+ @SmallTest
+ public void testGetResolvedLocale_englishIsAlwaysConsideredSupported() {
+ // First make sure English has no explicit assets other than the default assets
+ final AssetManager assets = getContext().getAssets();
+ final String supportedLocales[] = assets.getNonSystemLocales();
+ for (String languageTag : supportedLocales) {
+ if ("en-XA".equals(languageTag)) {
+ continue;
+ }
+ assertFalse(
+ "supported locales: " + Arrays.toString(supportedLocales),
+ "en".equals(Locale.forLanguageTag(languageTag).getLanguage()));
+ }
+
+ final DisplayMetrics dm = new DisplayMetrics();
+ dm.setToDefaults();
+ final Configuration cfg = new Configuration();
+ cfg.setToDefaults();
+ // Avestan and English have no assets, but Persian does.
+ cfg.setLocales(LocaleList.forLanguageTags("ae,en,fa"));
+ Resources res = new Resources(assets, dm, cfg);
+ // We should get English, because it is always considered supported.
+ assertEquals("en", res.getResolvedLocale().toLanguageTag());
+ }
+}
+
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index 253eb2585377..d3837756e495 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -17,14 +17,16 @@ package android.util;
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.Suppress;
-import android.util.Patterns;
import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import junit.framework.TestCase;
public class PatternsTest extends TestCase {
+ //Tests for Patterns.TOP_LEVEL_DOMAIN
+
@SmallTest
public void testTldPattern() throws Exception {
boolean t;
@@ -40,7 +42,7 @@ public class PatternsTest extends TestCase {
t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn--0zwm56d").matches();
assertTrue("Missed valid TLD", t);
- // One of the new top level internationalized domain.
+ // One of the new top level unicode domain.
t = Patterns.TOP_LEVEL_DOMAIN.matcher("\uD55C\uAD6D").matches();
assertTrue("Missed valid TLD", t);
@@ -54,60 +56,372 @@ public class PatternsTest extends TestCase {
assertFalse("Matched invalid TLD!", t);
}
+ //Tests for Patterns.IANA_TOP_LEVEL_DOMAINS
+
@SmallTest
- @Suppress // Failing.
- public void testUrlPattern() throws Exception {
- boolean t;
+ public void testIanaTopLevelDomains_matchesValidTld() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertTrue("Should match 'com'", pattern.matcher("com").matches());
+ }
- t = Patterns.WEB_URL.matcher("http://www.google.com").matches();
- assertTrue("Valid URL", t);
+ @SmallTest
+ public void testIanaTopLevelDomains_matchesValidNewTld() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertTrue("Should match 'me'", pattern.matcher("me").matches());
+ }
- // Google in one of the new top level domain.
- t = Patterns.WEB_URL.matcher("http://www.google.me").matches();
- assertTrue("Valid URL", t);
- t = Patterns.WEB_URL.matcher("google.me").matches();
- assertTrue("Valid URL", t);
+ @SmallTest
+ public void testIanaTopLevelDomains_matchesPunycodeTld() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertTrue("Should match Punycode TLD", pattern.matcher("xn--qxam").matches());
+ }
- // Test url in Chinese: http://xn--fsqu00a.xn--0zwm56d
- t = Patterns.WEB_URL.matcher("http://xn--fsqu00a.xn--0zwm56d").matches();
- assertTrue("Valid URL", t);
- t = Patterns.WEB_URL.matcher("xn--fsqu00a.xn--0zwm56d").matches();
- assertTrue("Valid URL", t);
+ @SmallTest
+ public void testIanaTopLevelDomains_matchesIriTLD() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertTrue("Should match IRI TLD", pattern.matcher("\uD55C\uAD6D").matches());
+ }
- // Url for testing top level Arabic country code domain in Punycode:
- // http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx
- t = Patterns.WEB_URL.matcher("http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches();
- assertTrue("Valid URL", t);
- t = Patterns.WEB_URL.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches();
- assertTrue("Valid URL", t);
+ @SmallTest
+ public void testIanaTopLevelDomains_doesNotMatchWrongTld() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertFalse("Should not match 'mem'", pattern.matcher("mem").matches());
+ }
- // Internationalized URL.
- t = Patterns.WEB_URL.matcher("http://\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
- assertTrue("Valid URL", t);
- t = Patterns.WEB_URL.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
- assertTrue("Valid URL", t);
- // URL with international TLD.
- t = Patterns.WEB_URL.matcher("\uB3C4\uBA54\uC778.\uD55C\uAD6D").matches();
- assertTrue("Valid URL", t);
+ @SmallTest
+ public void testIanaTopLevelDomains_doesNotMatchWrongPunycodeTld() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertFalse("Should not match invalid Punycode TLD", pattern.matcher("xn").matches());
+ }
- t = Patterns.WEB_URL.matcher("http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" +
- "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/").matches();
- assertTrue("Valid URL", t);
+ //Tests for Patterns.WEB_URL
- t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches();
- assertFalse("Matched invalid protocol", t);
+ @SmallTest
+ public void testWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
+ String url = "http://www.android.com";
+ assertTrue("Should match URL with scheme and hostname",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
- t = Patterns.WEB_URL.matcher("http://www.example.com:8080").matches();
- assertTrue("Didn't match valid URL with port", t);
+ @SmallTest
+ public void testWebUrl_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception {
+ String url = "http://www.android.me";
+ assertTrue("Should match URL with scheme, hostname and new TLD",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
- t = Patterns.WEB_URL.matcher("http://www.example.com:8080/?foo=bar").matches();
- assertTrue("Didn't match valid URL with port and query args", t);
+ @SmallTest
+ public void testWebUrl_matchesValidUrlWithHostnameAndNewTld() throws Exception {
+ String url = "android.me";
+ assertTrue("Should match URL with hostname and new TLD",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
- t = Patterns.WEB_URL.matcher("http://www.example.com:8080/~user/?foo=bar").matches();
- assertTrue("Didn't match valid URL with ~", t);
+ @SmallTest
+ public void testWebUrl_matchesChinesePunycodeUrlWithProtocol() throws Exception {
+ String url = "http://xn--fsqu00a.xn--0zwm56d";
+ assertTrue("Should match Chinese Punycode URL with protocol",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesChinesePunycodeUrlWithoutProtocol() throws Exception {
+ String url = "xn--fsqu00a.xn--0zwm56d";
+ assertTrue("Should match Chinese Punycode URL without protocol",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+
+ @SmallTest
+ public void testWebUrl_matchesArabicPunycodeUrlWithProtocol() throws Exception {
+ String url = "http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+ assertTrue("Should match arabic Punycode URL with protocol",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesArabicPunycodeUrlWithoutProtocol() throws Exception {
+ String url = "xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+ assertTrue("Should match Arabic Punycode URL without protocol",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithUnicodeDomainNameWithProtocol() throws Exception {
+ String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("Should match URL with Unicode domain name",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithUnicodeDomainNameWithoutProtocol() throws Exception {
+ String url = "\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("Should match URL without protocol and with Unicode domain name",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithUnicodeTld() throws Exception {
+ String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
+ assertTrue("Should match URL with Unicode TLD",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithUnicodePath() throws Exception {
+ String url = "http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" +
+ "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/";
+ assertTrue("Should match URL with Unicode path",
+ Patterns.WEB_URL.matcher(url).matches());
}
@SmallTest
+ public void testWebUrl_doesNotMatchValidUrlWithInvalidProtocol() throws Exception {
+ String url = "ftp://www.example.com";
+ assertFalse("Should not match URL with invalid protocol",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesValidUrlWithPort() throws Exception {
+ String url = "http://www.example.com:8080";
+ assertTrue("Should match URL with port", Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithPortAndQuery() throws Exception {
+ String url = "http://www.example.com:8080/?foo=bar";
+ assertTrue("Should match URL with port and query",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithTilde() throws Exception {
+ String url = "http://www.example.com:8080/~user/?foo=bar";
+ assertTrue("Should match URL with tilde", Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesProtocolCaseInsensitive() throws Exception {
+ String url = "hTtP://android.com";
+ assertTrue("Protocol matching should be case insensitive",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ //Tests for Patterns.AUTOLINK_WEB_URL
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
+ String url = "http://www.android.com";
+ assertTrue("Should match URL with scheme and hostname",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception {
+ String url = "http://www.android.me";
+ assertTrue("Should match URL with scheme, hostname and new TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesValidUrlWithHostnameAndNewTld() throws Exception {
+ String url = "android.me";
+ assertTrue("Should match URL with hostname and new TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+
+ url = "android.camera";
+ assertTrue("Should match URL with hostname and new TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesChinesePunycodeUrlWithProtocol() throws Exception {
+ String url = "http://xn--fsqu00a.xn--0zwm56d";
+ assertTrue("Should match Chinese Punycode URL with protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesChinesePunycodeUrlWithoutProtocol() throws Exception {
+ String url = "xn--fsqu00a.xn--0zwm56d";
+ assertTrue("Should match Chinese Punycode URL without protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesArabicPunycodeUrlWithProtocol() throws Exception {
+ String url = "http://xn--4gbrim.xn--rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+ assertTrue("Should match Arabic Punycode URL with protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesArabicPunycodeUrlWithoutProtocol() throws Exception {
+ String url = "xn--4gbrim.xn--rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+ assertTrue("Should match Arabic Punycode URL without protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchPunycodeTldThatStartsWithDash() throws Exception {
+ String url = "http://xn--fsqu00a.-xn--0zwm56d";
+ assertFalse("Should not match Punycode TLD that starts with dash",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchPunycodeTldThatEndsWithDash() throws Exception {
+ String url = "http://xn--fsqu00a.xn--0zwm56d-";
+ assertFalse("Should not match Punycode TLD that ends with dash",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlWithUnicodeDomainName() throws Exception {
+ String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("Should match URL with Unicode domain name",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+
+ url = "\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("hould match URL without protocol and with Unicode domain name",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlWithUnicodeTld() throws Exception {
+ String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
+ assertTrue("Should match URL with Unicode TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlWithUnicodePath() throws Exception {
+ String url = "http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" +
+ "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/";
+ assertTrue("Should match URL with Unicode path",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchValidUrlWithInvalidProtocol() throws Exception {
+ String url = "ftp://www.example.com";
+ assertFalse("Should not match URL with invalid protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesValidUrlWithPort() throws Exception {
+ String url = "http://www.example.com:8080";
+ assertTrue("Should match URL with port",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlWithPortAndQuery() throws Exception {
+ String url = "http://www.example.com:8080/?foo=bar";
+ assertTrue("Should match URL with port and query",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlWithTilde() throws Exception {
+ String url = "http://www.example.com:8080/~user/?foo=bar";
+ assertTrue("Should match URL with tilde",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesProtocolCaseInsensitive() throws Exception {
+ String url = "hTtP://android.com";
+ assertTrue("Protocol matching should be case insensitive",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlStartingWithHttpAndDoesNotHaveTld() throws Exception {
+ String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
+ assertTrue("Should match URL without a TLD and starting with http ",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld()
+ throws Exception {
+ String url = "thank.you";
+ assertFalse("Should not match URL that does not start with a protocol and " +
+ "does not contain a known TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchUrlWithInvalidRequestParameter() throws Exception {
+ String url = "http://android.com?p=value";
+ assertFalse("Should not match URL with invalid request parameter",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotPartiallyMatchUnknownProtocol() throws Exception {
+ String url = "ftp://foo.bar/baz";
+ assertFalse("Should not partially match URL with unknown protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).find());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesValidUrlWithEmoji() throws Exception {
+ String url = "Thank\u263A.com";
+ assertTrue("Should match URL with emoji",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld()
+ throws Exception {
+ String url = "Thank\u263A.you";
+ assertFalse("Should not match URLs containing emoji and with unknown TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchEmailAddress()
+ throws Exception {
+ String url = "android@android.com";
+ assertFalse("Should not match email address",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesDomainNameWithSurrogatePairs() throws Exception {
+ String url = "android\uD83C\uDF38.com";
+ assertTrue("Should match domain name with Unicode surrogate pairs",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesTldWithSurrogatePairs() throws Exception {
+ String url = "http://android.\uD83C\uDF38com";
+ assertTrue("Should match TLD with Unicode surrogate pairs",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesPathWithSurrogatePairs() throws Exception {
+ String url = "http://android.com/path-with-\uD83C\uDF38?v=\uD83C\uDF38";
+ assertTrue("Should match path and query with Unicode surrogate pairs",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchUrlWithExcludedSurrogate() throws Exception {
+ String url = "http://android\uD83F\uDFFE.com";
+ assertFalse("Should not match URL with excluded Unicode surrogate pair",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ //Tests for Patterns.IP_ADDRESS
+
+ @SmallTest
public void testIpPattern() throws Exception {
boolean t;
@@ -118,34 +432,85 @@ public class PatternsTest extends TestCase {
assertFalse("Invalid IP", t);
}
+ //Tests for Patterns.DOMAIN_NAME
+
@SmallTest
- @Suppress // Failing.
- public void testDomainPattern() throws Exception {
- boolean t;
+ public void testDomain_matchesPunycodeTld() throws Exception {
+ String domain = "xn--fsqu00a.xn--0zwm56d";
+ assertTrue("Should match domain name in Punycode",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ @SmallTest
+ public void testDomain_doesNotMatchPunycodeThatStartsWithDash() throws Exception {
+ String domain = "xn--fsqu00a.-xn--0zwm56d";
+ assertFalse("Should not match Punycode TLD that starts with a dash",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
- t = Patterns.DOMAIN_NAME.matcher("mail.example.com").matches();
- assertTrue("Valid domain", t);
+ @SmallTest
+ public void testDomain_doesNotMatchPunycodeThatEndsWithDash() throws Exception {
+ String domain = "xn--fsqu00a.xn--0zwm56d-";
+ assertFalse("Should not match Punycode TLD that ends with a dash",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
- t = Patterns.DOMAIN_NAME.matcher("google.me").matches();
- assertTrue("Valid domain", t);
+ @SmallTest
+ public void testDomain_doesNotMatchPunycodeLongerThanAllowed() throws Exception {
+ String tld = "xn--";
+ for(int i=0; i<=6; i++) {
+ tld += "0123456789";
+ }
+ String domain = "xn--fsqu00a." + tld;
+ assertFalse("Should not match Punycode TLD that is longer than 63 chars",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
- // Internationalized domains.
- t = Patterns.DOMAIN_NAME.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
- assertTrue("Valid domain", t);
+ @SmallTest
+ public void testDomain_matchesObsoleteTld() throws Exception {
+ String domain = "test.yu";
+ assertTrue("Should match domain names with obsolete TLD",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
- t = Patterns.DOMAIN_NAME.matcher("__+&42.xer").matches();
- assertFalse("Invalid domain", t);
+ @SmallTest
+ public void testDomain_matchesWithSubDomain() throws Exception {
+ String domain = "mail.example.com";
+ assertTrue("Should match domain names with subdomains",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
- // Obsolete domain .yu
- t = Patterns.DOMAIN_NAME.matcher("test.yu").matches();
- assertFalse("Obsolete country code top level domain", t);
+ @SmallTest
+ public void testDomain_matchesWithoutSubDomain() throws Exception {
+ String domain = "android.me";
+ assertTrue("Should match domain names without subdomains",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ @SmallTest
+ public void testDomain_matchesUnicodeDomainNames() throws Exception {
+ String domain = "\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("Should match unicodedomain names",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
- // Testing top level Arabic country code domain in Punycode:
- t = Patterns.DOMAIN_NAME.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c").matches();
- assertTrue("Valid domain", t);
+ @SmallTest
+ public void testDomain_doesNotMatchInvalidDomain() throws Exception {
+ String domain = "__+&42.xer";
+ assertFalse("Should not match invalid domain name",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
}
@SmallTest
+ public void testDomain_matchesPunycodeArabicDomainName() throws Exception {
+ String domain = "xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c";
+ assertTrue("Should match Punycode Arabic domain name",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ //Tests for Patterns.PHONE
+
+ @SmallTest
public void testPhonePattern() throws Exception {
boolean t;
diff --git a/core/tests/coretests/src/android/widget/DatePickerActivity.java b/core/tests/coretests/src/android/widget/DatePickerActivity.java
new file mode 100644
index 000000000000..c3b25a1a5a8c
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/DatePickerActivity.java
@@ -0,0 +1,32 @@
+/*
+ * 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.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
+/**
+ * A minimal application for DatePickerFocusTest.
+ */
+public class DatePickerActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.datepicker_layout);
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/DatePickerFocusTest.java b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
new file mode 100644
index 000000000000..513e40f4bcc3
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
@@ -0,0 +1,250 @@
+/*
+ * 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.widget;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.android.frameworks.coretests.R;
+
+/**
+ * Test {@link DatePicker} focus changes.
+ */
+public class DatePickerFocusTest extends ActivityInstrumentationTestCase2<DatePickerActivity> {
+
+ private Activity mActivity;
+ private Instrumentation mInstrumentation;
+ private DatePicker mDatePicker;
+
+ public DatePickerFocusTest() {
+ super(DatePickerActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mInstrumentation = getInstrumentation();
+
+ mDatePicker = (DatePicker) mActivity.findViewById(R.id.datePicker);
+ }
+
+ /**
+ * Tabs (forward and backward) through the DatePicker to ensure the correct
+ * Views gain focus.
+ */
+ public void testFocusTravel() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(mDatePicker.requestFocus());
+ }
+ });
+ assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
+ sendKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.prev);
+ sendKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.next);
+ sendKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+ sendKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(R.id.belowPicker);
+ sendShiftKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+ sendShiftKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.next);
+ sendShiftKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.prev);
+ sendShiftKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
+ }
+
+ private void sendKey(int keycode) {
+ mInstrumentation.sendKeyDownUpSync(keycode);
+ mInstrumentation.waitForIdleSync();
+ }
+
+ private void assertViewHasFocus(final int id) throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View view = mActivity.findViewById(id);
+ assertTrue(view.hasFocus());
+ }
+ });
+ }
+
+ private void sendShiftKey(int keycode) {
+ final KeyEvent shiftDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT);
+ mInstrumentation.sendKeySync(shiftDown);
+
+ final KeyEvent keyDown = new KeyEvent(SystemClock.uptimeMillis(),
+ SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, keycode, 0,
+ KeyEvent.META_SHIFT_ON);
+ mInstrumentation.sendKeySync(keyDown);
+
+ final KeyEvent keyUp = new KeyEvent(SystemClock.uptimeMillis(),
+ SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, keycode, 0,
+ KeyEvent.META_SHIFT_ON);
+ mInstrumentation.sendKeySync(keyUp);
+
+ final KeyEvent shiftUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT);
+ mInstrumentation.sendKeySync(shiftUp);
+
+ mInstrumentation.waitForIdleSync();
+ }
+
+ /**
+ * Tests to ensure the keyboard can select the current year.
+ */
+ public void testYearChoice() throws Throwable {
+ setKnownDate();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View year = mDatePicker.
+ findViewById(com.android.internal.R.id.date_picker_header_year);
+ assertTrue(year.requestFocus());
+ }
+ });
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View yearSelect = mDatePicker.
+ findViewById(com.android.internal.R.id.date_picker_year_picker);
+ assertEquals(yearSelect, mDatePicker.findFocus());
+ }
+ });
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View yearSelect = mDatePicker.
+ findViewById(com.android.internal.R.id.date_picker_year_picker);
+ assertNotSame(View.VISIBLE, yearSelect.getVisibility());
+ View year = mDatePicker.
+ findViewById(com.android.internal.R.id.date_picker_header_year);
+ assertTrue(year.hasFocus());
+ assertEquals(2014, mDatePicker.getYear());
+ }
+ });
+ }
+
+ public void testArrowThroughDays() throws Throwable {
+ setKnownDate();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View prev = mDatePicker.findViewById(com.android.internal.R.id.next);
+ prev.requestFocus();
+ }
+ });
+ sendKey(KeyEvent.KEYCODE_TAB);
+ // Should select the current date and the date shouldn't change
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(12, 31, 2015);
+ // Move right to January 24, 2016
+ sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(1, 24, 2016);
+ // Move down to January 31, 2016
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(1, 31, 2016);
+ // Move up to January 5, 2016
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(1, 5, 2016);
+ // Move up to prev arrow key
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ assertViewHasFocus(com.android.internal.R.id.prev);
+ // tab back into the day-selection pager
+ sendKey(KeyEvent.KEYCODE_TAB);
+ sendKey(KeyEvent.KEYCODE_TAB);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+ assertDateIs(1, 5, 2016);
+
+ // Move up out again, then down back into the day-selection pager.
+ // It should land right below the prev button (1/3/2016)
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+ assertDateIs(1, 3, 2016);
+
+ // Move left to previous month (12/12/2015)
+ sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(12, 12, 2015);
+ // Now make sure the start of the month works
+ // Move up to 12/5/2015 and right to 1/1/2016
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(1, 1, 2016);
+ // Now make sure the left key goes back to previous month (12/5/2015)
+ sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(12, 5, 2015);
+ // Now go to a mismatched row (no such row on previous month)
+ // This moves over to 1/31/2016 and then left to 12/31/2015
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(12, 31, 2015);
+ }
+
+ private void assertDateIs(int month, final int day, final int year) throws Throwable {
+ final int monthInt = month - 1; // months are 0-based
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertEquals(day, mDatePicker.getDayOfMonth());
+ assertEquals(year, mDatePicker.getYear());
+ assertEquals(monthInt, mDatePicker.getMonth());
+ }
+ });
+ }
+
+ private void setKnownDate() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mDatePicker.updateDate(2015, 11, 31); // December 31, 2015
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index b4f88c332314..999d47bea696 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -44,6 +44,7 @@
<permission name="android.permission.BLUETOOTH_STACK" >
<group gid="net_bt_stack" />
+ <group gid="wakelock" />
</permission>
<permission name="android.permission.NET_TUNNELING" >
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 554b6f1ba6c0..731bf42b01e2 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -344,7 +344,7 @@
<family>
<font weight="400" style="normal">NanumGothic.ttf</font>
</family>
- <family lang="und-Qaae">
+ <family lang="und-Zsye">
<font weight="400" style="normal">NotoColorEmoji.ttf</font>
</family>
<family>
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index c05ea2e1a1e5..704f0ce7624b 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -38,13 +38,14 @@ import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* The main programming interface for the DRM framework. An application must instantiate this class
* to access DRM agents through the DRM framework.
*
*/
-public class DrmManagerClient {
+public class DrmManagerClient implements AutoCloseable {
/**
* Indicates that a request was successful or that no error occurred.
*/
@@ -61,6 +62,7 @@ public class DrmManagerClient {
HandlerThread mEventThread;
private static final String TAG = "DrmManagerClient";
+ private final AtomicBoolean mClosed = new AtomicBoolean();
private final CloseGuard mCloseGuard = CloseGuard.get();
static {
@@ -117,7 +119,6 @@ public class DrmManagerClient {
private int mUniqueId;
private long mNativeContext;
- private volatile boolean mReleased;
private Context mContext;
private InfoHandler mInfoHandler;
private EventHandler mEventHandler;
@@ -261,41 +262,47 @@ public class DrmManagerClient {
@Override
protected void finalize() throws Throwable {
try {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
- release();
+ mCloseGuard.warnIfOpen();
+ close();
} finally {
super.finalize();
}
}
/**
- * Releases resources associated with the current session of DrmManagerClient.
- *
- * It is considered good practice to call this method when the {@link DrmManagerClient} object
- * is no longer needed in your application. After release() is called,
- * {@link DrmManagerClient} is no longer usable since it has lost all of its required resource.
+ * Releases resources associated with the current session of
+ * DrmManagerClient. It is considered good practice to call this method when
+ * the {@link DrmManagerClient} object is no longer needed in your
+ * application. After this method is called, {@link DrmManagerClient} is no
+ * longer usable since it has lost all of its required resource.
*/
- public void release() {
- if (mReleased) return;
- mReleased = true;
-
- if (mEventHandler != null) {
- mEventThread.quit();
- mEventThread = null;
- }
- if (mInfoHandler != null) {
- mInfoThread.quit();
- mInfoThread = null;
- }
- mEventHandler = null;
- mInfoHandler = null;
- mOnEventListener = null;
- mOnInfoListener = null;
- mOnErrorListener = null;
- _release(mUniqueId);
+ @Override
+ public void close() {
mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
+ if (mEventHandler != null) {
+ mEventThread.quit();
+ mEventThread = null;
+ }
+ if (mInfoHandler != null) {
+ mInfoThread.quit();
+ mInfoThread = null;
+ }
+ mEventHandler = null;
+ mInfoHandler = null;
+ mOnEventListener = null;
+ mOnInfoListener = null;
+ mOnErrorListener = null;
+ _release(mUniqueId);
+ }
+ }
+
+ /**
+ * @deprecated replaced by {@link #close()}.
+ */
+ @Deprecated
+ public void release() {
+ close();
}
/**
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index da58884e3833..175c726072cc 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -163,8 +163,11 @@ public class BitmapFactory {
public boolean inPremultiplied;
/**
- * If dither is true, the decoder will attempt to dither the decoded
- * image.
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this is
+ * ignored.
+ *
+ * In {@link android.os.Build.VERSION_CODES#M} and below, if dither is
+ * true, the decoder will attempt to dither the decoded image.
*/
public boolean inDither;
@@ -308,7 +311,11 @@ public class BitmapFactory {
public boolean inInputShareable;
/**
- * If inPreferQualityOverSpeed is set to true, the decoder will try to
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this is
+ * ignored. The output will always be high quality.
+ *
+ * In {@link android.os.Build.VERSION_CODES#M} and below, if
+ * inPreferQualityOverSpeed is set to true, the decoder will try to
* decode the reconstructed image to a higher quality even at the
* expense of the decoding speed. Currently the field only affects JPEG
* decode, in the case of which a more accurate, but slightly slower,
@@ -347,8 +354,6 @@ public class BitmapFactory {
*/
public byte[] inTempStorage;
- private native void requestCancel();
-
/**
* Flag to indicate that cancel has been called on this object. This
* is useful if there's an intermediary that wants to first decode the
@@ -359,16 +364,19 @@ public class BitmapFactory {
public boolean mCancel;
/**
- * This can be called from another thread while this options object is
- * inside a decode... call. Calling this will notify the decoder that
- * it should cancel its operation. This is not guaranteed to cancel
- * the decode, but if it does, the decoder... operation will return
- * null, or if inJustDecodeBounds is true, will set outWidth/outHeight
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this
+ * will not affect the decode, though it will still set mCancel.
+ *
+ * In {@link android.os.Build.VERSION_CODES#M} and below, if this can
+ * be called from another thread while this options object is inside
+ * a decode... call. Calling this will notify the decoder that it
+ * should cancel its operation. This is not guaranteed to cancel the
+ * decode, but if it does, the decoder... operation will return null,
+ * or if inJustDecodeBounds is true, will set outWidth/outHeight
* to -1
*/
public void requestCancelDecode() {
mCancel = true;
- requestCancel();
}
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index d5166ab92179..1cc53469a2f7 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -654,6 +654,12 @@ public class Canvas {
/**
* Return, in ctm, the current transformation matrix. This does not alter
* the matrix in the canvas, but just returns a copy of it.
+ *
+ * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any
+ * matrix when passed to a View or Drawable, as it is implementation defined where in the
+ * hierarchy such canvases are created. It is recommended in such cases to either draw contents
+ * irrespective of the current matrix, or to track relevant transform state outside of the
+ * canvas.
*/
@Deprecated
public void getMatrix(@NonNull Matrix ctm) {
@@ -663,6 +669,12 @@ public class Canvas {
/**
* Return a new matrix with a copy of the canvas' current transformation
* matrix.
+ *
+ * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any
+ * matrix when passed to a View or Drawable, as it is implementation defined where in the
+ * hierarchy such canvases are created. It is recommended in such cases to either draw contents
+ * irrespective of the current matrix, or to track relevant transform state outside of the
+ * canvas.
*/
@Deprecated
public final @NonNull Matrix getMatrix() {
@@ -812,6 +824,7 @@ public class Canvas {
* @deprecated Unlike all other clip calls this API does not respect the
* current matrix. Use {@link #clipRect(Rect)} as an alternative.
*/
+ @Deprecated
public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) {
return native_clipRegion(mNativeCanvasWrapper, region.ni(), op.nativeInt);
}
@@ -829,6 +842,7 @@ public class Canvas {
* @deprecated Unlike all other clip calls this API does not respect the
* current matrix. Use {@link #clipRect(Rect)} as an alternative.
*/
+ @Deprecated
public boolean clipRegion(@NonNull Region region) {
return clipRegion(region, Region.Op.INTERSECT);
}
@@ -1830,16 +1844,16 @@ public class Canvas {
* Draw the text in the array, with each character's origin specified by
* the pos array.
*
- * This method does not support glyph composition and decomposition and
- * should therefore not be used to render complex scripts. It also doesn't
- * handle supplementary characters (eg emoji).
- *
* @param text The text to be drawn
* @param index The index of the first character to draw
* @param count The number of characters to draw, starting from index.
* @param pos Array of [x,y] positions, used to position each
* character
* @param paint The paint used for the text (e.g. color, size, style)
+ *
+ * @deprecated This method does not support glyph composition and decomposition and
+ * should therefore not be used to render complex scripts. It also doesn't
+ * handle supplementary characters (eg emoji).
*/
@Deprecated
public void drawPosText(@NonNull char[] text, int index, int count,
@@ -1857,13 +1871,13 @@ public class Canvas {
* Draw the text in the array, with each character's origin specified by
* the pos array.
*
- * This method does not support glyph composition and decomposition and
- * should therefore not be used to render complex scripts. It also doesn't
- * handle supplementary characters (eg emoji).
- *
* @param text The text to be drawn
* @param pos Array of [x,y] positions, used to position each character
* @param paint The paint used for the text (e.g. color, size, style)
+ *
+ * @deprecated This method does not support glyph composition and decomposition and
+ * should therefore not be used to render complex scripts. It also doesn't
+ * handle supplementary characters (eg emoji).
*/
@Deprecated
public void drawPosText(@NonNull String text, @NonNull @Size(multiple=2) float[] pos,
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 1857345968fd..84ca5464f5cb 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -19,6 +19,7 @@ import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.Animator.AnimatorListener;
+import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.ColorStateList;
@@ -140,6 +141,15 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
/** Local, mutable animator set. */
private final AnimatorSet mAnimatorSet = new AnimatorSet();
+
+ private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ invalidateSelf();
+ }
+ };
+
/**
* The resources against which this drawable was created. Used to attempt
* to inflate animators if applyTheme() doesn't get called.
@@ -201,9 +211,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
@Override
public void draw(Canvas canvas) {
mAnimatedVectorState.mVectorDrawable.draw(canvas);
- if (isStarted()) {
- invalidateSelf();
- }
}
@Override
@@ -486,6 +493,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
* animators, or {@code null} if not available
*/
public void prepareLocalAnimators(@NonNull AnimatorSet animatorSet,
+ @NonNull ValueAnimator.AnimatorUpdateListener updateListener,
@Nullable Resources res) {
// Check for uninflated animators. We can remove this after we add
// support for Animator.applyTheme(). See comments in inflate().
@@ -511,6 +519,17 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
final Animator nextAnim = prepareLocalAnimator(i);
builder.with(nextAnim);
}
+
+ // Setup a value animator to get animation update callbacks.
+ long totalDuration = animatorSet.getTotalDuration();
+ ValueAnimator updateAnim = ValueAnimator.ofFloat(0f, 1f);
+ if (totalDuration == ValueAnimator.DURATION_INFINITE) {
+ updateAnim.setRepeatCount(ValueAnimator.INFINITE);
+ } else {
+ updateAnim.setDuration(totalDuration);
+ }
+ updateAnim.addUpdateListener(updateListener);
+ builder.with(updateAnim);
}
}
@@ -603,7 +622,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
@NonNull
private void ensureAnimatorSet() {
if (!mHasAnimatorSet) {
- mAnimatedVectorState.prepareLocalAnimators(mAnimatorSet, mRes);
+ mAnimatedVectorState.prepareLocalAnimators(mAnimatorSet, mUpdateListener, mRes);
mHasAnimatorSet = true;
mRes = null;
}
diff --git a/core/java/android/service/notification/NotificationAdjustment.aidl b/graphics/java/android/graphics/drawable/Icon.aidl
index 805fe2c67695..b82cfc49f4f4 100644
--- a/core/java/android/service/notification/NotificationAdjustment.aidl
+++ b/graphics/java/android/graphics/drawable/Icon.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.service.notification;
+package android.graphics.drawable;
-parcelable NotificationAdjustment; \ No newline at end of file
+parcelable Icon;
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 3761a99759c1..65260210042c 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -20,15 +20,9 @@ import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Insets;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PathMeasure;
import android.graphics.PixelFormat;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
@@ -38,7 +32,6 @@ import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.LayoutDirection;
import android.util.Log;
-import android.util.MathUtils;
import android.util.PathParser;
import android.util.Xml;
@@ -48,6 +41,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Stack;
@@ -196,21 +191,6 @@ public class VectorDrawable extends Drawable {
private static final String SHAPE_PATH = "path";
private static final String SHAPE_VECTOR = "vector";
- private static final int LINECAP_BUTT = 0;
- private static final int LINECAP_ROUND = 1;
- private static final int LINECAP_SQUARE = 2;
-
- private static final int LINEJOIN_MITER = 0;
- private static final int LINEJOIN_ROUND = 1;
- private static final int LINEJOIN_BEVEL = 2;
-
- // Cap the bitmap size, such that it won't hurt the performance too much
- // and it won't crash due to a very large scale.
- // The drawable will look blurry above this size.
- private static final int MAX_CACHED_BITMAP_SIZE = 2048;
-
- private static final boolean DBG_VECTOR_DRAWABLE = false;
-
private VectorDrawableState mVectorState;
private PorterDuffColorFilter mTintFilter;
@@ -218,10 +198,6 @@ public class VectorDrawable extends Drawable {
private boolean mMutated;
- // AnimatedVectorDrawable needs to turn off the cache all the time, otherwise,
- // caching the bitmap by default is allowed.
- private boolean mAllowCaching = true;
-
/** The density of the display on which this drawable will be rendered. */
private int mTargetDensity;
@@ -235,8 +211,6 @@ public class VectorDrawable extends Drawable {
private boolean mDpiScaledDirty = true;
// Temp variable, only for saving "new" operation at the draw() time.
- private final float[] mTmpFloats = new float[9];
- private final Matrix mTmpMatrix = new Matrix();
private final Rect mTmpBounds = new Rect();
public VectorDrawable() {
@@ -249,7 +223,6 @@ public class VectorDrawable extends Drawable {
*/
private VectorDrawable(@NonNull VectorDrawableState state, @Nullable Resources res) {
mVectorState = state;
-
updateLocalState(res);
}
@@ -262,7 +235,7 @@ public class VectorDrawable extends Drawable {
* displayed, or {@code null} to use the constant state defaults
*/
private void updateLocalState(Resources res) {
- final int density = Drawable.resolveDensity(res, mVectorState.mVPathRenderer.mDensity);
+ final int density = Drawable.resolveDensity(res, mVectorState.mDensity);
if (mTargetDensity != density) {
mTargetDensity = density;
mDpiScaledDirty = true;
@@ -289,7 +262,7 @@ public class VectorDrawable extends Drawable {
}
Object getTargetByName(String name) {
- return mVectorState.mVPathRenderer.mVGTargetsMap.get(name);
+ return mVectorState.mVGTargetsMap.get(name);
}
@Override
@@ -310,61 +283,23 @@ public class VectorDrawable extends Drawable {
// Color filters always override tint filters.
final ColorFilter colorFilter = (mColorFilter == null ? mTintFilter : mColorFilter);
-
- // The imageView can scale the canvas in different ways, in order to
- // avoid blurry scaling, we have to draw into a bitmap with exact pixel
- // size first. This bitmap size is determined by the bounds and the
- // canvas scale.
- canvas.getMatrix(mTmpMatrix);
- mTmpMatrix.getValues(mTmpFloats);
- float canvasScaleX = Math.abs(mTmpFloats[Matrix.MSCALE_X]);
- float canvasScaleY = Math.abs(mTmpFloats[Matrix.MSCALE_Y]);
- int scaledWidth = (int) (mTmpBounds.width() * canvasScaleX);
- int scaledHeight = (int) (mTmpBounds.height() * canvasScaleY);
- scaledWidth = Math.min(MAX_CACHED_BITMAP_SIZE, scaledWidth);
- scaledHeight = Math.min(MAX_CACHED_BITMAP_SIZE, scaledHeight);
-
- if (scaledWidth <= 0 || scaledHeight <= 0) {
- return;
- }
-
- final int saveCount = canvas.save();
- canvas.translate(mTmpBounds.left, mTmpBounds.top);
-
- // Handle RTL mirroring.
- final boolean needMirroring = needMirroring();
- if (needMirroring) {
- canvas.translate(mTmpBounds.width(), 0);
- canvas.scale(-1.0f, 1.0f);
- }
-
- // At this point, canvas has been translated to the right position.
- // And we use this bound for the destination rect for the drawBitmap, so
- // we offset to (0, 0);
- mTmpBounds.offsetTo(0, 0);
-
- mVectorState.createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
- if (!mAllowCaching) {
- mVectorState.updateCachedBitmap(scaledWidth, scaledHeight);
- } else {
- if (!mVectorState.canReuseCache()) {
- mVectorState.updateCachedBitmap(scaledWidth, scaledHeight);
- mVectorState.updateCacheStates();
- }
- }
- mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter, mTmpBounds);
- canvas.restoreToCount(saveCount);
+ final long colorFilterNativeInstance = colorFilter == null ? 0 :
+ colorFilter.native_instance;
+ boolean canReuseCache = mVectorState.canReuseCache();
+ nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(),
+ colorFilterNativeInstance, mTmpBounds, needMirroring(),
+ canReuseCache);
}
+
@Override
public int getAlpha() {
- return mVectorState.mVPathRenderer.getRootAlpha();
+ return (int) (mVectorState.getAlpha() * 255);
}
@Override
public void setAlpha(int alpha) {
- if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
- mVectorState.mVPathRenderer.setRootAlpha(alpha);
+ if (mVectorState.setAlpha(alpha / 255f)) {
invalidateSelf();
}
}
@@ -410,7 +345,7 @@ public class VectorDrawable extends Drawable {
boolean changed = false;
final VectorDrawableState state = mVectorState;
- if (state.mVPathRenderer != null && state.mVPathRenderer.onStateChange(stateSet)) {
+ if (state.onStateChange(stateSet)) {
changed = true;
state.mCacheDirty = true;
}
@@ -457,16 +392,15 @@ public class VectorDrawable extends Drawable {
* from the source density against which the constant state was loaded.
*/
void computeVectorSize() {
- final VPathRenderer pathRenderer = mVectorState.mVPathRenderer;
- final Insets opticalInsets = pathRenderer.mOpticalInsets;
+ final Insets opticalInsets = mVectorState.mOpticalInsets;
- final int sourceDensity = pathRenderer.mDensity;
+ final int sourceDensity = mVectorState.mDensity;
final int targetDensity = mTargetDensity;
if (targetDensity != sourceDensity) {
mDpiScaledWidth = Drawable.scaleFromDensity(
- (int) pathRenderer.mBaseWidth, sourceDensity, targetDensity, true);
+ (int) mVectorState.mBaseWidth, sourceDensity, targetDensity, true);
mDpiScaledHeight = Drawable.scaleFromDensity(
- (int) pathRenderer.mBaseHeight,sourceDensity, targetDensity, true);
+ (int) mVectorState.mBaseHeight,sourceDensity, targetDensity, true);
final int left = Drawable.scaleFromDensity(
opticalInsets.left, sourceDensity, targetDensity, false);
final int right = Drawable.scaleFromDensity(
@@ -477,8 +411,8 @@ public class VectorDrawable extends Drawable {
opticalInsets.bottom, sourceDensity, targetDensity, false);
mDpiScaledInsets = Insets.of(left, top, right, bottom);
} else {
- mDpiScaledWidth = (int) pathRenderer.mBaseWidth;
- mDpiScaledHeight = (int) pathRenderer.mBaseHeight;
+ mDpiScaledWidth = (int) mVectorState.mBaseWidth;
+ mDpiScaledHeight = (int) mVectorState.mBaseHeight;
mDpiScaledInsets = opticalInsets;
}
@@ -499,8 +433,7 @@ public class VectorDrawable extends Drawable {
return;
}
- final VPathRenderer path = state.mVPathRenderer;
- final boolean changedDensity = path.setDensity(
+ final boolean changedDensity = mVectorState.setDensity(
Drawable.resolveDensity(t.getResources(), 0));
mDpiScaledDirty |= changedDensity;
@@ -511,7 +444,7 @@ public class VectorDrawable extends Drawable {
state.mCacheDirty = true;
updateStateFromTypedArray(a);
} catch (XmlPullParserException e) {
- rethrowAsRuntimeException(e);
+ throw new RuntimeException(e);
} finally {
a.recycle();
}
@@ -525,8 +458,8 @@ public class VectorDrawable extends Drawable {
state.mTint = state.mTint.obtainForTheme(t);
}
- if (path != null && path.canApplyTheme()) {
- path.applyTheme(t);
+ if (mVectorState != null && mVectorState.canApplyTheme()) {
+ mVectorState.applyTheme(t);
}
// Update local properties.
@@ -540,17 +473,17 @@ public class VectorDrawable extends Drawable {
* @hide
*/
public float getPixelSize() {
- if (mVectorState == null || mVectorState.mVPathRenderer == null ||
- mVectorState.mVPathRenderer.mBaseWidth == 0 ||
- mVectorState.mVPathRenderer.mBaseHeight == 0 ||
- mVectorState.mVPathRenderer.mViewportHeight == 0 ||
- mVectorState.mVPathRenderer.mViewportWidth == 0) {
+ if (mVectorState == null ||
+ mVectorState.mBaseWidth == 0 ||
+ mVectorState.mBaseHeight == 0 ||
+ mVectorState.mViewportHeight == 0 ||
+ mVectorState.mViewportWidth == 0) {
return 1; // fall back to 1:1 pixel mapping.
}
- float intrinsicWidth = mVectorState.mVPathRenderer.mBaseWidth;
- float intrinsicHeight = mVectorState.mVPathRenderer.mBaseHeight;
- float viewportWidth = mVectorState.mVPathRenderer.mViewportWidth;
- float viewportHeight = mVectorState.mVPathRenderer.mViewportHeight;
+ float intrinsicWidth = mVectorState.mBaseWidth;
+ float intrinsicHeight = mVectorState.mBaseHeight;
+ float viewportWidth = mVectorState.mViewportWidth;
+ float viewportHeight = mVectorState.mViewportHeight;
float scaleX = viewportWidth / intrinsicWidth;
float scaleY = viewportHeight / intrinsicHeight;
return Math.min(scaleX, scaleY);
@@ -582,20 +515,20 @@ public class VectorDrawable extends Drawable {
return null;
}
- private static int applyAlpha(int color, float alpha) {
- int alphaBytes = Color.alpha(color);
- color &= 0x00FFFFFF;
- color |= ((int) (alphaBytes * alpha)) << 24;
- return color;
- }
-
@Override
public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
@NonNull AttributeSet attrs, @Nullable Theme theme)
throws XmlPullParserException, IOException {
+ if (mVectorState.mRootGroup != null || mVectorState.mNativeRendererPtr != 0) {
+ // This VD has been used to display other VD resource content, clean up.
+ mVectorState.mRootGroup = new VGroup();
+ if (mVectorState.mNativeRendererPtr != 0) {
+ nDestroyRenderer(mVectorState.mNativeRendererPtr);
+ }
+ mVectorState.mNativeRendererPtr = nCreateRenderer(mVectorState.mRootGroup.mNativePtr);
+ }
final VectorDrawableState state = mVectorState;
- state.mVPathRenderer = new VPathRenderer();
- state.mVPathRenderer.setDensity(Drawable.resolveDensity(r, 0));
+ state.setDensity(Drawable.resolveDensity(r, 0));
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawable);
updateStateFromTypedArray(a);
@@ -612,7 +545,6 @@ public class VectorDrawable extends Drawable {
private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
final VectorDrawableState state = mVectorState;
- final VPathRenderer pathRenderer = state.mVPathRenderer;
// Account for any configuration changes.
state.mChangingConfigurations |= a.getChangingConfigurations();
@@ -633,63 +565,63 @@ public class VectorDrawable extends Drawable {
state.mAutoMirrored = a.getBoolean(
R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored);
- pathRenderer.mViewportWidth = a.getFloat(
- R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
- pathRenderer.mViewportHeight = a.getFloat(
- R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
+ float viewportWidth = a.getFloat(
+ R.styleable.VectorDrawable_viewportWidth, state.mViewportWidth);
+ float viewportHeight = a.getFloat(
+ R.styleable.VectorDrawable_viewportHeight, state.mViewportHeight);
+ state.setViewportSize(viewportWidth, viewportHeight);
- if (pathRenderer.mViewportWidth <= 0) {
+ if (state.mViewportWidth <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
"<vector> tag requires viewportWidth > 0");
- } else if (pathRenderer.mViewportHeight <= 0) {
+ } else if (state.mViewportHeight <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
"<vector> tag requires viewportHeight > 0");
}
- pathRenderer.mBaseWidth = a.getDimension(
- R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth);
- pathRenderer.mBaseHeight = a.getDimension(
- R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight);
+ state.mBaseWidth = a.getDimension(
+ R.styleable.VectorDrawable_width, state.mBaseWidth);
+ state.mBaseHeight = a.getDimension(
+ R.styleable.VectorDrawable_height, state.mBaseHeight);
- if (pathRenderer.mBaseWidth <= 0) {
+ if (state.mBaseWidth <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
"<vector> tag requires width > 0");
- } else if (pathRenderer.mBaseHeight <= 0) {
+ } else if (state.mBaseHeight <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
"<vector> tag requires height > 0");
}
final int insetLeft = a.getDimensionPixelOffset(
- R.styleable.VectorDrawable_opticalInsetLeft, pathRenderer.mOpticalInsets.left);
+ R.styleable.VectorDrawable_opticalInsetLeft, state.mOpticalInsets.left);
final int insetTop = a.getDimensionPixelOffset(
- R.styleable.VectorDrawable_opticalInsetTop, pathRenderer.mOpticalInsets.top);
+ R.styleable.VectorDrawable_opticalInsetTop, state.mOpticalInsets.top);
final int insetRight = a.getDimensionPixelOffset(
- R.styleable.VectorDrawable_opticalInsetRight, pathRenderer.mOpticalInsets.right);
+ R.styleable.VectorDrawable_opticalInsetRight, state.mOpticalInsets.right);
final int insetBottom = a.getDimensionPixelOffset(
- R.styleable.VectorDrawable_opticalInsetBottom, pathRenderer.mOpticalInsets.bottom);
- pathRenderer.mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
+ R.styleable.VectorDrawable_opticalInsetBottom, state.mOpticalInsets.bottom);
+ state.mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
final float alphaInFloat = a.getFloat(
- R.styleable.VectorDrawable_alpha, pathRenderer.getAlpha());
- pathRenderer.setAlpha(alphaInFloat);
+ R.styleable.VectorDrawable_alpha, state.getAlpha());
+ state.setAlpha(alphaInFloat);
final String name = a.getString(R.styleable.VectorDrawable_name);
if (name != null) {
- pathRenderer.mRootName = name;
- pathRenderer.mVGTargetsMap.put(name, pathRenderer);
+ state.mRootName = name;
+ state.mVGTargetsMap.put(name, state);
}
}
private void inflateChildElements(Resources res, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
final VectorDrawableState state = mVectorState;
- final VPathRenderer pathRenderer = state.mVPathRenderer;
boolean noPathTag = true;
// Use a stack to help to build the group tree.
// The top of the stack is always the current group.
final Stack<VGroup> groupStack = new Stack<VGroup>();
- groupStack.push(pathRenderer.mRootGroup);
+ groupStack.push(state.mRootGroup);
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
@@ -702,7 +634,7 @@ public class VectorDrawable extends Drawable {
path.inflate(res, attrs, theme);
currentGroup.addChild(path);
if (path.getPathName() != null) {
- pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+ state.mVGTargetsMap.put(path.getPathName(), path);
}
noPathTag = false;
state.mChangingConfigurations |= path.mChangingConfigurations;
@@ -711,7 +643,7 @@ public class VectorDrawable extends Drawable {
path.inflate(res, attrs, theme);
currentGroup.addChild(path);
if (path.getPathName() != null) {
- pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+ state.mVGTargetsMap.put(path.getPathName(), path);
}
state.mChangingConfigurations |= path.mChangingConfigurations;
} else if (SHAPE_GROUP.equals(tagName)) {
@@ -720,7 +652,7 @@ public class VectorDrawable extends Drawable {
currentGroup.addChild(newChildGroup);
groupStack.push(newChildGroup);
if (newChildGroup.getGroupName() != null) {
- pathRenderer.mVGTargetsMap.put(newChildGroup.getGroupName(),
+ state.mVGTargetsMap.put(newChildGroup.getGroupName(),
newChildGroup);
}
state.mChangingConfigurations |= newChildGroup.mChangingConfigurations;
@@ -734,11 +666,6 @@ public class VectorDrawable extends Drawable {
eventType = parser.next();
}
- // Print the tree out for debug.
- if (DBG_VECTOR_DRAWABLE) {
- pathRenderer.printGroupTree();
- }
-
if (noPathTag) {
final StringBuffer tag = new StringBuffer();
@@ -757,7 +684,7 @@ public class VectorDrawable extends Drawable {
}
void setAllowCaching(boolean allowCaching) {
- mAllowCaching = allowCaching;
+ nSetAllowCaching(mVectorState.getNativeRenderer(), allowCaching);
}
private boolean needMirroring() {
@@ -778,84 +705,68 @@ public class VectorDrawable extends Drawable {
}
private static class VectorDrawableState extends ConstantState {
+ // Variables below need to be copied (deep copy if applicable) for mutation.
int[] mThemeAttrs;
int mChangingConfigurations;
- VPathRenderer mVPathRenderer;
ColorStateList mTint = null;
Mode mTintMode = DEFAULT_TINT_MODE;
boolean mAutoMirrored;
- Bitmap mCachedBitmap;
+ float mBaseWidth = 0;
+ float mBaseHeight = 0;
+ float mViewportWidth = 0;
+ float mViewportHeight = 0;
+ Insets mOpticalInsets = Insets.NONE;
+ String mRootName = null;
+ VGroup mRootGroup;
+ long mNativeRendererPtr;
+
+ int mDensity = DisplayMetrics.DENSITY_DEFAULT;
+ final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
+
+ // Fields for cache
int[] mCachedThemeAttrs;
ColorStateList mCachedTint;
Mode mCachedTintMode;
- int mCachedRootAlpha;
boolean mCachedAutoMirrored;
boolean mCacheDirty;
- /** Temporary paint object used to draw cached bitmaps. */
- Paint mTempPaint;
// Deep copy for mutate() or implicitly mutate.
public VectorDrawableState(VectorDrawableState copy) {
if (copy != null) {
mThemeAttrs = copy.mThemeAttrs;
mChangingConfigurations = copy.mChangingConfigurations;
- mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
mTint = copy.mTint;
mTintMode = copy.mTintMode;
mAutoMirrored = copy.mAutoMirrored;
+ mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
+ mNativeRendererPtr = nCreateRenderer(mRootGroup.mNativePtr);
+
+ mBaseWidth = copy.mBaseWidth;
+ mBaseHeight = copy.mBaseHeight;
+ setViewportSize(copy.mViewportWidth, copy.mViewportHeight);
+ mOpticalInsets = copy.mOpticalInsets;
+
+ mRootName = copy.mRootName;
+ mDensity = copy.mDensity;
+ if (copy.mRootName != null) {
+ mVGTargetsMap.put(copy.mRootName, this);
+ }
}
}
- public void drawCachedBitmapWithRootAlpha(Canvas canvas, ColorFilter filter,
- Rect originalBounds) {
- // The bitmap's size is the same as the bounds.
- final Paint p = getPaint(filter);
- canvas.drawBitmap(mCachedBitmap, null, originalBounds, p);
- }
-
- public boolean hasTranslucentRoot() {
- return mVPathRenderer.getRootAlpha() < 255;
- }
-
- /**
- * @return null when there is no need for alpha paint.
- */
- public Paint getPaint(ColorFilter filter) {
- if (!hasTranslucentRoot() && filter == null) {
- return null;
- }
-
- if (mTempPaint == null) {
- mTempPaint = new Paint();
- mTempPaint.setFilterBitmap(true);
+ @Override
+ public void finalize() throws Throwable {
+ if (mNativeRendererPtr != 0) {
+ nDestroyRenderer(mNativeRendererPtr);
+ mNativeRendererPtr = 0;
}
- mTempPaint.setAlpha(mVPathRenderer.getRootAlpha());
- mTempPaint.setColorFilter(filter);
- return mTempPaint;
- }
-
- public void updateCachedBitmap(int width, int height) {
- mCachedBitmap.eraseColor(Color.TRANSPARENT);
- Canvas tmpCanvas = new Canvas(mCachedBitmap);
- mVPathRenderer.draw(tmpCanvas, width, height, null);
+ super.finalize();
}
- public void createCachedBitmapIfNeeded(int width, int height) {
- if (mCachedBitmap == null || !canReuseBitmap(width, height)) {
- mCachedBitmap = Bitmap.createBitmap(width, height,
- Bitmap.Config.ARGB_8888);
- mCacheDirty = true;
- }
- }
-
- public boolean canReuseBitmap(int width, int height) {
- if (width == mCachedBitmap.getWidth()
- && height == mCachedBitmap.getHeight()) {
- return true;
- }
- return false;
+ long getNativeRenderer() {
+ return mNativeRendererPtr;
}
public boolean canReuseCache() {
@@ -863,10 +774,10 @@ public class VectorDrawable extends Drawable {
&& mCachedThemeAttrs == mThemeAttrs
&& mCachedTint == mTint
&& mCachedTintMode == mTintMode
- && mCachedAutoMirrored == mAutoMirrored
- && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) {
+ && mCachedAutoMirrored == mAutoMirrored) {
return true;
}
+ updateCacheStates();
return false;
}
@@ -876,21 +787,25 @@ public class VectorDrawable extends Drawable {
mCachedThemeAttrs = mThemeAttrs;
mCachedTint = mTint;
mCachedTintMode = mTintMode;
- mCachedRootAlpha = mVPathRenderer.getRootAlpha();
mCachedAutoMirrored = mAutoMirrored;
mCacheDirty = false;
}
+ public void applyTheme(Theme t) {
+ mRootGroup.applyTheme(t);
+ }
+
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null
- || (mVPathRenderer != null && mVPathRenderer.canApplyTheme())
+ || (mRootGroup != null && mRootGroup.canApplyTheme())
|| (mTint != null && mTint.canApplyTheme())
|| super.canApplyTheme();
}
public VectorDrawableState() {
- mVPathRenderer = new VPathRenderer();
+ mRootGroup = new VGroup();
+ mNativeRendererPtr = nCreateRenderer(mRootGroup.mNativePtr);
}
@Override
@@ -911,80 +826,13 @@ public class VectorDrawable extends Drawable {
public boolean isStateful() {
return (mTint != null && mTint.isStateful())
- || (mVPathRenderer != null && mVPathRenderer.isStateful());
- }
- }
-
- private static class VPathRenderer {
- /* Right now the internal data structure is organized as a tree.
- * Each node can be a group node, or a path.
- * A group node can have groups or paths as children, but a path node has
- * no children.
- * One example can be:
- * Root Group
- * / | \
- * Group Path Group
- * / \ |
- * Path Path Path
- *
- */
- // Variables that only used temporarily inside the draw() call, so there
- // is no need for deep copying.
- private final TempState mTempState = new TempState();
-
- /////////////////////////////////////////////////////
- // Variables below need to be copied (deep copy if applicable) for mutation.
- private int mChangingConfigurations;
- private final VGroup mRootGroup;
- float mBaseWidth = 0;
- float mBaseHeight = 0;
- float mViewportWidth = 0;
- float mViewportHeight = 0;
- Insets mOpticalInsets = Insets.NONE;
- int mRootAlpha = 0xFF;
- String mRootName = null;
-
- int mDensity = DisplayMetrics.DENSITY_DEFAULT;
-
- final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
-
- public VPathRenderer() {
- mRootGroup = new VGroup();
- }
-
- public void setRootAlpha(int alpha) {
- mRootAlpha = alpha;
- }
-
- public int getRootAlpha() {
- return mRootAlpha;
- }
-
- // setAlpha() and getAlpha() are used mostly for animation purpose, since
- // Animator like to use alpha from 0 to 1.
- public void setAlpha(float alpha) {
- setRootAlpha((int) (alpha * 255));
- }
-
- @SuppressWarnings("unused")
- public float getAlpha() {
- return getRootAlpha() / 255.0f;
+ || (mRootGroup != null && mRootGroup.isStateful());
}
- public VPathRenderer(VPathRenderer copy) {
- mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
- mBaseWidth = copy.mBaseWidth;
- mBaseHeight = copy.mBaseHeight;
- mViewportWidth = copy.mViewportWidth;
- mViewportHeight = copy.mViewportHeight;
- mOpticalInsets = copy.mOpticalInsets;
- mChangingConfigurations = copy.mChangingConfigurations;
- mRootAlpha = copy.mRootAlpha;
- mRootName = copy.mRootName;
- mDensity = copy.mDensity;
- if (copy.mRootName != null) {
- mVGTargetsMap.put(copy.mRootName, this);
- }
+ void setViewportSize(float viewportWidth, float viewportHeight) {
+ mViewportWidth = viewportWidth;
+ mViewportHeight = viewportHeight;
+ nSetRendererViewportSize(getNativeRenderer(), viewportWidth, viewportHeight);
}
public final boolean setDensity(int targetDensity) {
@@ -1012,68 +860,50 @@ public class VectorDrawable extends Drawable {
mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
}
- public boolean canApplyTheme() {
- return mRootGroup.canApplyTheme();
- }
-
- public void applyTheme(Theme t) {
- mRootGroup.applyTheme(t);
- }
-
public boolean onStateChange(int[] stateSet) {
return mRootGroup.onStateChange(stateSet);
}
- public boolean isStateful() {
- return mRootGroup.isStateful();
- }
-
- public void draw(Canvas canvas, int w, int h, ColorFilter filter) {
- final float scaleX = w / mViewportWidth;
- final float scaleY = h / mViewportHeight;
- mRootGroup.draw(canvas, mTempState, Matrix.IDENTITY_MATRIX, filter, scaleX, scaleY);
+ /**
+ * setAlpha() and getAlpha() are used mostly for animation purpose. Return true if alpha
+ * has changed.
+ */
+ public boolean setAlpha(float alpha) {
+ return nSetRootAlpha(mNativeRendererPtr, alpha);
}
- public void printGroupTree() {
- mRootGroup.printGroupTree("");
+ @SuppressWarnings("unused")
+ public float getAlpha() {
+ return nGetRootAlpha(mNativeRendererPtr);
}
}
private static class VGroup implements VObject {
- private static final String GROUP_INDENT = " ";
-
- // mStackedMatrix is only used temporarily when drawing, it combines all
- // the parents' local matrices with the current one.
- private final Matrix mStackedMatrix = new Matrix();
-
+ private static final int ROTATE_INDEX = 0;
+ private static final int PIVOT_X_INDEX = 1;
+ private static final int PIVOT_Y_INDEX = 2;
+ private static final int SCALE_X_INDEX = 3;
+ private static final int SCALE_Y_INDEX = 4;
+ private static final int TRANSLATE_X_INDEX = 5;
+ private static final int TRANSLATE_Y_INDEX = 6;
+ private static final int TRANSFORM_PROPERTY_COUNT = 7;
+
+ // Temp array to store transform values obtained from native.
+ private float[] mTransform;
/////////////////////////////////////////////////////
// Variables below need to be copied (deep copy if applicable) for mutation.
private final ArrayList<VObject> mChildren = new ArrayList<>();
-
- private float mRotate = 0;
- private float mPivotX = 0;
- private float mPivotY = 0;
- private float mScaleX = 1;
- private float mScaleY = 1;
- private float mTranslateX = 0;
- private float mTranslateY = 0;
private boolean mIsStateful;
// mLocalMatrix is updated based on the update of transformation information,
// either parsed from the XML or by animation.
- private final Matrix mLocalMatrix = new Matrix();
private int mChangingConfigurations;
private int[] mThemeAttrs;
private String mGroupName = null;
+ private long mNativePtr = 0;
public VGroup(VGroup copy, ArrayMap<String, Object> targetsMap) {
- mRotate = copy.mRotate;
- mPivotX = copy.mPivotX;
- mPivotY = copy.mPivotY;
- mScaleX = copy.mScaleX;
- mScaleY = copy.mScaleY;
- mTranslateX = copy.mTranslateX;
- mTranslateY = copy.mTranslateY;
+
mIsStateful = copy.mIsStateful;
mThemeAttrs = copy.mThemeAttrs;
mGroupName = copy.mGroupName;
@@ -1081,15 +911,14 @@ public class VectorDrawable extends Drawable {
if (mGroupName != null) {
targetsMap.put(mGroupName, this);
}
-
- mLocalMatrix.set(copy.mLocalMatrix);
+ mNativePtr = nCreateGroup(copy.mNativePtr);
final ArrayList<VObject> children = copy.mChildren;
for (int i = 0; i < children.size(); i++) {
final VObject copyChild = children.get(i);
if (copyChild instanceof VGroup) {
final VGroup copyGroup = (VGroup) copyChild;
- mChildren.add(new VGroup(copyGroup, targetsMap));
+ addChild(new VGroup(copyGroup, targetsMap));
} else {
final VPath newPath;
if (copyChild instanceof VFullPath) {
@@ -1099,7 +928,7 @@ public class VectorDrawable extends Drawable {
} else {
throw new IllegalStateException("Unknown object in the tree!");
}
- mChildren.add(newPath);
+ addChild(newPath);
if (newPath.mPathName != null) {
targetsMap.put(newPath.mPathName, newPath);
}
@@ -1108,43 +937,23 @@ public class VectorDrawable extends Drawable {
}
public VGroup() {
+ mNativePtr = nCreateGroup();
}
public String getGroupName() {
return mGroupName;
}
- public Matrix getLocalMatrix() {
- return mLocalMatrix;
- }
-
public void addChild(VObject child) {
+ nAddChild(mNativePtr, child.getNativePtr());
mChildren.add(child);
mIsStateful |= child.isStateful();
}
@Override
- public void draw(Canvas canvas, TempState temp, Matrix currentMatrix,
- ColorFilter filter, float scaleX, float scaleY) {
- // Calculate current group's matrix by preConcat the parent's and
- // and the current one on the top of the stack.
- // Basically the Mfinal = Mviewport * M0 * M1 * M2;
- // Mi the local matrix at level i of the group tree.
- mStackedMatrix.set(currentMatrix);
- mStackedMatrix.preConcat(mLocalMatrix);
-
- // Save the current clip information, which is local to this group.
- canvas.save();
-
- // Draw the group tree in the same order as the XML file.
- for (int i = 0, count = mChildren.size(); i < count; i++) {
- final VObject child = mChildren.get(i);
- child.draw(canvas, temp, mStackedMatrix, filter, scaleX, scaleY);
- }
-
- // Restore the previous clip information.
- canvas.restore();
+ public long getNativePtr() {
+ return mNativePtr;
}
@Override
@@ -1155,27 +964,43 @@ public class VectorDrawable extends Drawable {
a.recycle();
}
- private void updateStateFromTypedArray(TypedArray a) {
+ void updateStateFromTypedArray(TypedArray a) {
// Account for any configuration changes.
mChangingConfigurations |= a.getChangingConfigurations();
// Extract the theme attributes, if any.
mThemeAttrs = a.extractThemeAttrs();
-
- mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
- mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
- mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
- mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
- mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
- mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
- mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
+ if (mTransform == null) {
+ // Lazy initialization: If the group is created through copy constructor, this may
+ // never get called.
+ mTransform = new float[TRANSFORM_PROPERTY_COUNT];
+ }
+ boolean success = nGetGroupProperties(mNativePtr, mTransform, TRANSFORM_PROPERTY_COUNT);
+ if (!success) {
+ throw new RuntimeException("Error: inconsistent property count");
+ }
+ float rotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation,
+ mTransform[ROTATE_INDEX]);
+ float pivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX,
+ mTransform[PIVOT_X_INDEX]);
+ float pivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY,
+ mTransform[PIVOT_Y_INDEX]);
+ float scaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX,
+ mTransform[SCALE_X_INDEX]);
+ float scaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY,
+ mTransform[SCALE_Y_INDEX]);
+ float translateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX,
+ mTransform[TRANSLATE_X_INDEX]);
+ float translateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY,
+ mTransform[TRANSLATE_Y_INDEX]);
final String groupName = a.getString(R.styleable.VectorDrawableGroup_name);
if (groupName != null) {
mGroupName = groupName;
+ nSetName(mNativePtr, mGroupName);
}
-
- updateLocalMatrix();
+ nUpdateGroupProperties(mNativePtr, rotate, pivotX, pivotY, scaleX, scaleY,
+ translateX, translateY);
}
@Override
@@ -1216,6 +1041,16 @@ public class VectorDrawable extends Drawable {
}
@Override
+ protected void finalize() throws Throwable {
+ if (mNativePtr != 0) {
+ nDestroy(mNativePtr);
+ mNativePtr = 0;
+ }
+ super.finalize();
+ }
+
+
+ @Override
public void applyTheme(Theme t) {
if (mThemeAttrs != null) {
final TypedArray a = t.resolveAttributes(mThemeAttrs,
@@ -1236,124 +1071,75 @@ public class VectorDrawable extends Drawable {
}
}
- private void updateLocalMatrix() {
- // The order we apply is the same as the
- // RenderNode.cpp::applyViewPropertyTransforms().
- mLocalMatrix.reset();
- mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
- mLocalMatrix.postScale(mScaleX, mScaleY);
- mLocalMatrix.postRotate(mRotate, 0, 0);
- mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
- }
-
- public void printGroupTree(String indent) {
- Log.v(LOGTAG, indent + "group:" + getGroupName() + " rotation is " + mRotate);
- Log.v(LOGTAG, indent + "matrix:" + getLocalMatrix().toString());
-
- final int count = mChildren.size();
- if (count > 0) {
- indent += GROUP_INDENT;
- }
-
- // Then print all the children groups.
- for (int i = 0; i < count; i++) {
- final VObject child = mChildren.get(i);
- if (child instanceof VGroup) {
- ((VGroup) child).printGroupTree(indent);
- }
- }
- }
-
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@SuppressWarnings("unused")
public float getRotation() {
- return mRotate;
+ return nGetRotation(mNativePtr);
}
@SuppressWarnings("unused")
public void setRotation(float rotation) {
- if (rotation != mRotate) {
- mRotate = rotation;
- updateLocalMatrix();
- }
+ nSetRotation(mNativePtr, rotation);
}
@SuppressWarnings("unused")
public float getPivotX() {
- return mPivotX;
+ return nGetPivotX(mNativePtr);
}
@SuppressWarnings("unused")
public void setPivotX(float pivotX) {
- if (pivotX != mPivotX) {
- mPivotX = pivotX;
- updateLocalMatrix();
- }
+ nSetPivotX(mNativePtr, pivotX);
}
@SuppressWarnings("unused")
public float getPivotY() {
- return mPivotY;
+ return nGetPivotY(mNativePtr);
}
@SuppressWarnings("unused")
public void setPivotY(float pivotY) {
- if (pivotY != mPivotY) {
- mPivotY = pivotY;
- updateLocalMatrix();
- }
+ nSetPivotY(mNativePtr, pivotY);
}
@SuppressWarnings("unused")
public float getScaleX() {
- return mScaleX;
+ return nGetScaleX(mNativePtr);
}
@SuppressWarnings("unused")
public void setScaleX(float scaleX) {
- if (scaleX != mScaleX) {
- mScaleX = scaleX;
- updateLocalMatrix();
- }
+ nSetScaleX(mNativePtr, scaleX);
}
@SuppressWarnings("unused")
public float getScaleY() {
- return mScaleY;
+ return nGetScaleY(mNativePtr);
}
@SuppressWarnings("unused")
public void setScaleY(float scaleY) {
- if (scaleY != mScaleY) {
- mScaleY = scaleY;
- updateLocalMatrix();
- }
+ nSetScaleY(mNativePtr, scaleY);
}
@SuppressWarnings("unused")
public float getTranslateX() {
- return mTranslateX;
+ return nGetTranslateX(mNativePtr);
}
@SuppressWarnings("unused")
public void setTranslateX(float translateX) {
- if (translateX != mTranslateX) {
- mTranslateX = translateX;
- updateLocalMatrix();
- }
+ nSetTranslateX(mNativePtr, translateX);
}
@SuppressWarnings("unused")
public float getTranslateY() {
- return mTranslateY;
+ return nGetTranslateY(mNativePtr);
}
@SuppressWarnings("unused")
public void setTranslateY(float translateY) {
- if (translateY != mTranslateY) {
- mTranslateY = translateY;
- updateLocalMatrix();
- }
+ nSetTranslateY(mNativePtr, translateY);
}
}
@@ -1362,6 +1148,7 @@ public class VectorDrawable extends Drawable {
*/
private static abstract class VPath implements VObject {
protected PathParser.PathData mPathData = null;
+
String mPathName;
int mChangingConfigurations;
@@ -1379,10 +1166,6 @@ public class VectorDrawable extends Drawable {
return mPathName;
}
- public boolean isClipPath() {
- return false;
- }
-
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@SuppressWarnings("unused")
public PathParser.PathData getPathData() {
@@ -1393,79 +1176,7 @@ public class VectorDrawable extends Drawable {
@SuppressWarnings("unused")
public void setPathData(PathParser.PathData pathData) {
mPathData.setPathData(pathData);
- }
-
- @Override
- public final void draw(Canvas canvas, TempState temp, Matrix groupStackedMatrix,
- ColorFilter filter, float scaleX, float scaleY) {
- final float matrixScale = VPath.getMatrixScale(groupStackedMatrix);
- if (matrixScale == 0) {
- // When either x or y is scaled to 0, we don't need to draw anything.
- return;
- }
-
- final Path path = temp.path;
- path.reset();
- toPath(temp, path);
-
- final Matrix pathMatrix = temp.pathMatrix;
- pathMatrix.set(groupStackedMatrix);
- pathMatrix.postScale(scaleX, scaleY);
-
- final Path renderPath = temp.renderPath;
- renderPath.reset();
- renderPath.addPath(path, pathMatrix);
-
- final float minScale = Math.min(scaleX, scaleY);
- final float strokeScale = minScale * matrixScale;
- drawPath(temp, renderPath, canvas, filter, strokeScale);
- }
-
- /**
- * Writes the path's nodes to an output Path for rendering.
- *
- * @param temp temporary state variables
- * @param outPath the output path
- */
- protected void toPath(TempState temp, Path outPath) {
- if (mPathData != null) {
- PathParser.createPathFromPathData(outPath, mPathData);
- }
- }
-
- /**
- * Draws the specified path into the supplied canvas.
- */
- protected abstract void drawPath(TempState temp, Path path, Canvas canvas,
- ColorFilter filter, float strokeScale);
-
- private static float getMatrixScale(Matrix groupStackedMatrix) {
- // Given unit vectors A = (0, 1) and B = (1, 0).
- // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
- // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
- // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
- // If max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
- //
- // For non-skew case, which is most of the cases, matrix scale is computing exactly the
- // scale on x and y axis, and take the minimal of these two.
- // For skew case, an unit square will mapped to a parallelogram. And this function will
- // return the minimal height of the 2 bases.
- float[] unitVectors = new float[] {0, 1, 1, 0};
- groupStackedMatrix.mapVectors(unitVectors);
- float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]);
- float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]);
- float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1],
- unitVectors[2], unitVectors[3]);
- float maxScale = MathUtils.max(scaleX, scaleY);
-
- float matrixScale = 0;
- if (maxScale > 0) {
- matrixScale = MathUtils.abs(crossProduct) / maxScale;
- }
- if (DBG_VECTOR_DRAWABLE) {
- Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale);
- }
- return matrixScale;
+ nSetPathData(getNativePtr(), mPathData.getNativePtr());
}
}
@@ -1473,21 +1184,31 @@ public class VectorDrawable extends Drawable {
* Clip path, which only has name and pathData.
*/
private static class VClipPath extends VPath {
+ long mNativePtr = 0;
public VClipPath() {
+ mNativePtr = nCreateClipPath();
// Empty constructor.
}
public VClipPath(VClipPath copy) {
super(copy);
+ mNativePtr = nCreateClipPath(copy.mNativePtr);
}
@Override
- protected void drawPath(TempState temp, Path renderPath, Canvas canvas, ColorFilter filter,
- float strokeScale) {
- canvas.clipPath(renderPath);
+ public long getNativePtr() {
+ return mNativePtr;
}
@Override
+ protected void finalize() throws Throwable {
+ if (mNativePtr != 0) {
+ nDestroy(mNativePtr);
+ mNativePtr = 0;
+ }
+ super.finalize();
+ }
+ @Override
public void inflate(Resources r, AttributeSet attrs, Theme theme) {
final TypedArray a = obtainAttributes(r, theme, attrs,
R.styleable.VectorDrawableClipPath);
@@ -1522,95 +1243,54 @@ public class VectorDrawable extends Drawable {
final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name);
if (pathName != null) {
mPathName = pathName;
+ nSetName(mNativePtr, mPathName);
}
final String pathDataString = a.getString(R.styleable.VectorDrawableClipPath_pathData);
if (pathDataString != null) {
mPathData = new PathParser.PathData(pathDataString);
+ nSetPathString(mNativePtr, pathDataString, pathDataString.length());
}
}
-
- @Override
- public boolean isClipPath() {
- return true;
- }
}
/**
* Normal path, which contains all the fill / paint information.
*/
private static class VFullPath extends VPath {
+ private static final int STROKE_WIDTH_INDEX = 0;
+ private static final int STROKE_COLOR_INDEX = 1;
+ private static final int STROKE_ALPHA_INDEX = 2;
+ private static final int FILL_COLOR_INDEX = 3;
+ private static final int FILL_ALPHA_INDEX = 4;
+ private static final int TRIM_PATH_START_INDEX = 5;
+ private static final int TRIM_PATH_END_INDEX = 6;
+ private static final int TRIM_PATH_OFFSET_INDEX = 7;
+ private static final int STROKE_LINE_CAP_INDEX = 8;
+ private static final int STROKE_LINE_JOIN_INDEX = 9;
+ private static final int STROKE_MITER_LIMIT_INDEX = 10;
+ private static final int TOTAL_PROPERTY_COUNT = 11;
+
+ // Temp array to store property data obtained from native getter.
+ private byte[] mPropertyData;
/////////////////////////////////////////////////////
// Variables below need to be copied (deep copy if applicable) for mutation.
private int[] mThemeAttrs;
-
ColorStateList mStrokeColors = null;
- int mStrokeColor = Color.TRANSPARENT;
- float mStrokeWidth = 0;
-
ColorStateList mFillColors = null;
- int mFillColor = Color.TRANSPARENT;
- float mStrokeAlpha = 1.0f;
- int mFillRule;
- float mFillAlpha = 1.0f;
- float mTrimPathStart = 0;
- float mTrimPathEnd = 1;
- float mTrimPathOffset = 0;
-
- Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
- Paint.Join mStrokeLineJoin = Paint.Join.MITER;
- float mStrokeMiterlimit = 4;
+ private long mNativePtr = 0;
public VFullPath() {
// Empty constructor.
+ mNativePtr = nCreateFullPath();
}
public VFullPath(VFullPath copy) {
super(copy);
-
+ mNativePtr = nCreateFullPath(copy.mNativePtr);
mThemeAttrs = copy.mThemeAttrs;
-
mStrokeColors = copy.mStrokeColors;
- mStrokeColor = copy.mStrokeColor;
- mStrokeWidth = copy.mStrokeWidth;
- mStrokeAlpha = copy.mStrokeAlpha;
mFillColors = copy.mFillColors;
- mFillColor = copy.mFillColor;
- mFillRule = copy.mFillRule;
- mFillAlpha = copy.mFillAlpha;
- mTrimPathStart = copy.mTrimPathStart;
- mTrimPathEnd = copy.mTrimPathEnd;
- mTrimPathOffset = copy.mTrimPathOffset;
-
- mStrokeLineCap = copy.mStrokeLineCap;
- mStrokeLineJoin = copy.mStrokeLineJoin;
- mStrokeMiterlimit = copy.mStrokeMiterlimit;
- }
-
- private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
- switch (id) {
- case LINECAP_BUTT:
- return Paint.Cap.BUTT;
- case LINECAP_ROUND:
- return Paint.Cap.ROUND;
- case LINECAP_SQUARE:
- return Paint.Cap.SQUARE;
- default:
- return defValue;
- }
- }
-
- private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
- switch (id) {
- case LINEJOIN_MITER:
- return Paint.Join.MITER;
- case LINEJOIN_ROUND:
- return Paint.Join.ROUND;
- case LINEJOIN_BEVEL:
- return Paint.Join.BEVEL;
- default:
- return defValue;
- }
}
@Override
@@ -1618,17 +1298,22 @@ public class VectorDrawable extends Drawable {
boolean changed = false;
if (mStrokeColors != null) {
- final int oldStrokeColor = mStrokeColor;
- mStrokeColor = mStrokeColors.getColorForState(stateSet, oldStrokeColor);
- changed |= oldStrokeColor != mStrokeColor;
+ final int oldStrokeColor = getStrokeColor();
+ final int newStrokeColor = mStrokeColors.getColorForState(stateSet, oldStrokeColor);
+ changed |= oldStrokeColor != newStrokeColor;
+ if (oldStrokeColor != newStrokeColor) {
+ nSetStrokeColor(mNativePtr, newStrokeColor);
+ }
}
if (mFillColors != null) {
- final int oldFillColor = mFillColor;
- mFillColor = mFillColors.getColorForState(stateSet, oldFillColor);
- changed |= oldFillColor != mFillColor;
+ final int oldFillColor = getFillColor();
+ final int newFillColor = mFillColors.getColorForState(stateSet, oldFillColor);
+ changed |= oldFillColor != newFillColor;
+ if (oldFillColor != newFillColor) {
+ nSetFillColor(mNativePtr, newFillColor);
+ }
}
-
return changed;
}
@@ -1638,112 +1323,56 @@ public class VectorDrawable extends Drawable {
}
@Override
- public void toPath(TempState temp, Path path) {
- super.toPath(temp, path);
-
- if (mTrimPathStart != 0.0f || mTrimPathEnd != 1.0f) {
- VFullPath.applyTrim(temp, path, mTrimPathStart, mTrimPathEnd, mTrimPathOffset);
- }
+ public long getNativePtr() {
+ return mNativePtr;
}
@Override
- protected void drawPath(TempState temp, Path path, Canvas canvas, ColorFilter filter,
- float strokeScale) {
- drawPathFill(temp, path, canvas, filter);
- drawPathStroke(temp, path, canvas, filter, strokeScale);
- }
-
- /**
- * Draws this path's fill, if necessary.
- */
- private void drawPathFill(TempState temp, Path path, Canvas canvas, ColorFilter filter) {
- if (mFillColor == Color.TRANSPARENT) {
- return;
- }
-
- if (temp.mFillPaint == null) {
- temp.mFillPaint = new Paint();
- temp.mFillPaint.setStyle(Paint.Style.FILL);
- temp.mFillPaint.setAntiAlias(true);
- }
-
- final Paint fillPaint = temp.mFillPaint;
- fillPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
- fillPaint.setColorFilter(filter);
- canvas.drawPath(path, fillPaint);
+ public void inflate(Resources r, AttributeSet attrs, Theme theme) {
+ final TypedArray a = obtainAttributes(r, theme, attrs,
+ R.styleable.VectorDrawablePath);
+ updateStateFromTypedArray(a);
+ a.recycle();
}
- /**
- * Draws this path's stroke, if necessary.
- */
- private void drawPathStroke(TempState temp, Path path, Canvas canvas, ColorFilter filter,
- float strokeScale) {
- if (mStrokeColor == Color.TRANSPARENT) {
- return;
- }
-
- if (temp.mStrokePaint == null) {
- temp.mStrokePaint = new Paint();
- temp.mStrokePaint.setStyle(Paint.Style.STROKE);
- temp.mStrokePaint.setAntiAlias(true);
- }
-
- final Paint strokePaint = temp.mStrokePaint;
- if (mStrokeLineJoin != null) {
- strokePaint.setStrokeJoin(mStrokeLineJoin);
- }
-
- if (mStrokeLineCap != null) {
- strokePaint.setStrokeCap(mStrokeLineCap);
+ @Override
+ protected void finalize() throws Throwable {
+ if (mNativePtr != 0) {
+ nDestroy(mNativePtr);
+ mNativePtr = 0;
}
-
- strokePaint.setStrokeMiter(mStrokeMiterlimit);
- strokePaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
- strokePaint.setColorFilter(filter);
- strokePaint.setStrokeWidth(mStrokeWidth * strokeScale);
- canvas.drawPath(path, strokePaint);
+ super.finalize();
}
- /**
- * Applies trimming to the specified path.
- */
- private static void applyTrim(TempState temp, Path path, float mTrimPathStart,
- float mTrimPathEnd, float mTrimPathOffset) {
- if (mTrimPathStart == 0.0f && mTrimPathEnd == 1.0f) {
- // No trimming necessary.
- return;
- }
-
- if (temp.mPathMeasure == null) {
- temp.mPathMeasure = new PathMeasure();
+ private void updateStateFromTypedArray(TypedArray a) {
+ int byteCount = TOTAL_PROPERTY_COUNT * 4;
+ if (mPropertyData == null) {
+ // Lazy initialization: If the path is created through copy constructor, this may
+ // never get called.
+ mPropertyData = new byte[byteCount];
}
- final PathMeasure pathMeasure = temp.mPathMeasure;
- pathMeasure.setPath(path, false);
-
- final float len = pathMeasure.getLength();
- final float start = len * ((mTrimPathStart + mTrimPathOffset) % 1.0f);
- final float end = len * ((mTrimPathEnd + mTrimPathOffset) % 1.0f);
- path.reset();
- if (start > end) {
- pathMeasure.getSegment(start, len, path, true);
- pathMeasure.getSegment(0, end, path, true);
- } else {
- pathMeasure.getSegment(start, end, path, true);
+ // The bulk getters/setters of property data (e.g. stroke width, color, etc) allows us
+ // to pull current values from native and store modifications with only two methods,
+ // minimizing JNI overhead.
+ boolean success = nGetFullPathProperties(mNativePtr, mPropertyData, byteCount);
+ if (!success) {
+ throw new RuntimeException("Error: inconsistent property count");
}
- // Fix bug in measure.
- path.rLineTo(0, 0);
- }
-
- @Override
- public void inflate(Resources r, AttributeSet attrs, Theme theme) {
- final TypedArray a = obtainAttributes(r, theme, attrs,
- R.styleable.VectorDrawablePath);
- updateStateFromTypedArray(a);
- a.recycle();
- }
+ ByteBuffer properties = ByteBuffer.wrap(mPropertyData);
+ properties.order(ByteOrder.nativeOrder());
+ float strokeWidth = properties.getFloat(STROKE_WIDTH_INDEX * 4);
+ int strokeColor = properties.getInt(STROKE_COLOR_INDEX * 4);
+ float strokeAlpha = properties.getFloat(STROKE_ALPHA_INDEX * 4);
+ int fillColor = properties.getInt(FILL_COLOR_INDEX * 4);
+ float fillAlpha = properties.getFloat(FILL_ALPHA_INDEX * 4);
+ float trimPathStart = properties.getFloat(TRIM_PATH_START_INDEX * 4);
+ float trimPathEnd = properties.getFloat(TRIM_PATH_END_INDEX * 4);
+ float trimPathOffset = properties.getFloat(TRIM_PATH_OFFSET_INDEX * 4);
+ int strokeLineCap = properties.getInt(STROKE_LINE_CAP_INDEX * 4);
+ int strokeLineJoin = properties.getInt(STROKE_LINE_JOIN_INDEX * 4);
+ float strokeMiterLimit = properties.getFloat(STROKE_MITER_LIMIT_INDEX * 4);
- private void updateStateFromTypedArray(TypedArray a) {
// Account for any configuration changes.
mChangingConfigurations |= a.getChangingConfigurations();
@@ -1753,11 +1382,13 @@ public class VectorDrawable extends Drawable {
final String pathName = a.getString(R.styleable.VectorDrawablePath_name);
if (pathName != null) {
mPathName = pathName;
+ nSetName(mNativePtr, mPathName);
}
final String pathString = a.getString(R.styleable.VectorDrawablePath_pathData);
if (pathString != null) {
mPathData = new PathParser.PathData(pathString);
+ nSetPathString(mNativePtr, pathString, pathString.length());
}
final ColorStateList fillColors = a.getColorStateList(
@@ -1766,7 +1397,7 @@ public class VectorDrawable extends Drawable {
// If the color state list isn't stateful, discard the state
// list and keep the default (e.g. the only) color.
mFillColors = fillColors.isStateful() ? fillColors : null;
- mFillColor = fillColors.getDefaultColor();
+ fillColor = fillColors.getDefaultColor();
}
final ColorStateList strokeColors = a.getColorStateList(
@@ -1775,23 +1406,30 @@ public class VectorDrawable extends Drawable {
// If the color state list isn't stateful, discard the state
// list and keep the default (e.g. the only) color.
mStrokeColors = strokeColors.isStateful() ? strokeColors : null;
- mStrokeColor = strokeColors.getDefaultColor();
+ strokeColor = strokeColors.getDefaultColor();
}
-
- mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, mFillAlpha);
- mStrokeLineCap = getStrokeLineCap(a.getInt(
- R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
- mStrokeLineJoin = getStrokeLineJoin(a.getInt(
- R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
- mStrokeMiterlimit = a.getFloat(
- R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
- mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha, mStrokeAlpha);
- mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
- mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
- mTrimPathOffset = a.getFloat(
- R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
- mTrimPathStart = a.getFloat(
- R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
+ fillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, fillAlpha);
+
+ strokeLineCap = a.getInt(
+ R.styleable.VectorDrawablePath_strokeLineCap, strokeLineCap);
+ strokeLineJoin = a.getInt(
+ R.styleable.VectorDrawablePath_strokeLineJoin, strokeLineJoin);
+ strokeMiterLimit = a.getFloat(
+ R.styleable.VectorDrawablePath_strokeMiterLimit, strokeMiterLimit);
+ strokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha,
+ strokeAlpha);
+ strokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth,
+ strokeWidth);
+ trimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd,
+ trimPathEnd);
+ trimPathOffset = a.getFloat(
+ R.styleable.VectorDrawablePath_trimPathOffset, trimPathOffset);
+ trimPathStart = a.getFloat(
+ R.styleable.VectorDrawablePath_trimPathStart, trimPathStart);
+
+ nUpdateFullPathProperties(mNativePtr, strokeWidth, strokeColor, strokeAlpha,
+ fillColor, fillAlpha, trimPathStart, trimPathEnd, trimPathOffset,
+ strokeMiterLimit, strokeLineCap, strokeLineJoin);
}
@Override
@@ -1813,104 +1451,169 @@ public class VectorDrawable extends Drawable {
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@SuppressWarnings("unused")
int getStrokeColor() {
- return mStrokeColor;
+ return nGetStrokeColor(mNativePtr);
}
@SuppressWarnings("unused")
void setStrokeColor(int strokeColor) {
mStrokeColors = null;
- mStrokeColor = strokeColor;
+ nSetStrokeColor(mNativePtr, strokeColor);
}
@SuppressWarnings("unused")
float getStrokeWidth() {
- return mStrokeWidth;
+ return nGetStrokeWidth(mNativePtr);
}
@SuppressWarnings("unused")
void setStrokeWidth(float strokeWidth) {
- mStrokeWidth = strokeWidth;
+ nSetStrokeWidth(mNativePtr, strokeWidth);
}
@SuppressWarnings("unused")
float getStrokeAlpha() {
- return mStrokeAlpha;
+ return nGetStrokeAlpha(mNativePtr);
}
@SuppressWarnings("unused")
void setStrokeAlpha(float strokeAlpha) {
- mStrokeAlpha = strokeAlpha;
+ nSetStrokeAlpha(mNativePtr, strokeAlpha);
}
@SuppressWarnings("unused")
int getFillColor() {
- return mFillColor;
+ return nGetFillColor(mNativePtr);
}
@SuppressWarnings("unused")
void setFillColor(int fillColor) {
mFillColors = null;
- mFillColor = fillColor;
+ nSetFillColor(mNativePtr, fillColor);
}
@SuppressWarnings("unused")
float getFillAlpha() {
- return mFillAlpha;
+ return nGetFillAlpha(mNativePtr);
}
@SuppressWarnings("unused")
void setFillAlpha(float fillAlpha) {
- mFillAlpha = fillAlpha;
+ nSetFillAlpha(mNativePtr, fillAlpha);
}
@SuppressWarnings("unused")
float getTrimPathStart() {
- return mTrimPathStart;
+ return nGetTrimPathStart(mNativePtr);
}
@SuppressWarnings("unused")
void setTrimPathStart(float trimPathStart) {
- mTrimPathStart = trimPathStart;
+ nSetTrimPathStart(mNativePtr, trimPathStart);
}
@SuppressWarnings("unused")
float getTrimPathEnd() {
- return mTrimPathEnd;
+ return nGetTrimPathEnd(mNativePtr);
}
@SuppressWarnings("unused")
void setTrimPathEnd(float trimPathEnd) {
- mTrimPathEnd = trimPathEnd;
+ nSetTrimPathEnd(mNativePtr, trimPathEnd);
}
@SuppressWarnings("unused")
float getTrimPathOffset() {
- return mTrimPathOffset;
+ return nGetTrimPathOffset(mNativePtr);
}
@SuppressWarnings("unused")
void setTrimPathOffset(float trimPathOffset) {
- mTrimPathOffset = trimPathOffset;
+ nSetTrimPathOffset(mNativePtr, trimPathOffset);
}
}
- static class TempState {
- final Matrix pathMatrix = new Matrix();
- final Path path = new Path();
- final Path renderPath = new Path();
-
- PathMeasure mPathMeasure;
- Paint mFillPaint;
- Paint mStrokePaint;
- }
-
interface VObject {
- void draw(Canvas canvas, TempState temp, Matrix currentMatrix,
- ColorFilter filter, float scaleX, float scaleY);
+ long getNativePtr();
void inflate(Resources r, AttributeSet attrs, Theme theme);
boolean canApplyTheme();
void applyTheme(Theme t);
boolean onStateChange(int[] state);
boolean isStateful();
}
+
+ private static native long nCreateRenderer(long rootGroupPtr);
+ private static native void nDestroyRenderer(long rendererPtr);
+ private static native void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
+ float viewportHeight);
+ private static native boolean nSetRootAlpha(long rendererPtr, float alpha);
+ private static native float nGetRootAlpha(long rendererPtr);
+ private static native void nSetAllowCaching(long rendererPtr, boolean allowCaching);
+
+ private static native void nDraw(long rendererPtr, long canvasWrapperPtr,
+ long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache);
+ private static native long nCreateFullPath();
+ private static native long nCreateFullPath(long mNativeFullPathPtr);
+ private static native boolean nGetFullPathProperties(long pathPtr, byte[] properties,
+ int length);
+
+ private static native void nUpdateFullPathProperties(long pathPtr, float strokeWidth,
+ int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
+ float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
+ int strokeLineJoin);
+
+ private static native long nCreateClipPath();
+ private static native long nCreateClipPath(long clipPathPtr);
+
+ private static native long nCreateGroup();
+ private static native long nCreateGroup(long groupPtr);
+ private static native void nDestroy(long nodePtr);
+ private static native void nSetName(long nodePtr, String name);
+ private static native boolean nGetGroupProperties(long groupPtr, float[] properties,
+ int length);
+ private static native void nUpdateGroupProperties(long groupPtr, float rotate, float pivotX,
+ float pivotY, float scaleX, float scaleY, float translateX, float translateY);
+
+ private static native void nAddChild(long groupPtr, long nodePtr);
+ private static native void nSetPathString(long pathPtr, String pathString, int length);
+
+ /**
+ * The setters and getters below for paths and groups are here temporarily, and will be
+ * removed once the animation in AVD is replaced with RenderNodeAnimator, in which case the
+ * animation will modify these properties in native. By then no JNI hopping would be necessary
+ * for VD during animation, and these setters and getters will be obsolete.
+ */
+ // Setters and getters during animation.
+ private static native float nGetRotation(long groupPtr);
+ private static native void nSetRotation(long groupPtr, float rotation);
+ private static native float nGetPivotX(long groupPtr);
+ private static native void nSetPivotX(long groupPtr, float pivotX);
+ private static native float nGetPivotY(long groupPtr);
+ private static native void nSetPivotY(long groupPtr, float pivotY);
+ private static native float nGetScaleX(long groupPtr);
+ private static native void nSetScaleX(long groupPtr, float scaleX);
+ private static native float nGetScaleY(long groupPtr);
+ private static native void nSetScaleY(long groupPtr, float scaleY);
+ private static native float nGetTranslateX(long groupPtr);
+ private static native void nSetTranslateX(long groupPtr, float translateX);
+ private static native float nGetTranslateY(long groupPtr);
+ private static native void nSetTranslateY(long groupPtr, float translateY);
+
+ // Setters and getters for VPath during animation.
+ private static native void nSetPathData(long pathPtr, long pathDataPtr);
+ private static native float nGetStrokeWidth(long pathPtr);
+ private static native void nSetStrokeWidth(long pathPtr, float width);
+ private static native int nGetStrokeColor(long pathPtr);
+ private static native void nSetStrokeColor(long pathPtr, int strokeColor);
+ private static native float nGetStrokeAlpha(long pathPtr);
+ private static native void nSetStrokeAlpha(long pathPtr, float alpha);
+ private static native int nGetFillColor(long pathPtr);
+ private static native void nSetFillColor(long pathPtr, int fillColor);
+ private static native float nGetFillAlpha(long pathPtr);
+ private static native void nSetFillAlpha(long pathPtr, float fillAlpha);
+ private static native float nGetTrimPathStart(long pathPtr);
+ private static native void nSetTrimPathStart(long pathPtr, float trimPathStart);
+ private static native float nGetTrimPathEnd(long pathPtr);
+ private static native void nSetTrimPathEnd(long pathPtr, float trimPathEnd);
+ private static native float nGetTrimPathOffset(long pathPtr);
+ private static native void nSetTrimPathOffset(long pathPtr, float trimPathOffset);
}
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 3d4e47d84c65..914ac3d52421 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -100,16 +100,17 @@ public:
* then on success, *cookie is set to the value corresponding to the
* newly-added asset source.
*/
- bool addAssetPath(const String8& path, int32_t* cookie, bool appAsLib=false);
+ bool addAssetPath(const String8& path, int32_t* cookie,
+ bool appAsLib=false, bool isSystemAsset=false);
bool addOverlayPath(const String8& path, int32_t* cookie);
- /*
+ /*
* Convenience for adding the standard system assets. Uses the
* ANDROID_ROOT environment variable to find them.
*/
bool addDefaultAssets();
- /*
+ /*
* Iterate over the asset paths in this manager. (Previously
* added via addAssetPath() and addDefaultAssets().) On first call,
* 'cookie' must be 0, resulting in the first cookie being returned.
@@ -118,7 +119,7 @@ public:
*/
int32_t nextAssetPath(const int32_t cookie) const;
- /*
+ /*
* Return an asset path in the manager. 'which' must be between 0 and
* countAssetPaths().
*/
@@ -221,11 +222,11 @@ public:
* the current data.
*/
bool isUpToDate();
-
+
/**
* Get the known locales for this asset manager object.
*/
- void getLocales(Vector<String8>* locales) const;
+ void getLocales(Vector<String8>* locales, bool includeSystemLocales=true) const;
/**
* Generate idmap data to translate resources IDs between a package and a
@@ -237,11 +238,13 @@ public:
private:
struct asset_path
{
- asset_path() : path(""), type(kFileTypeRegular), idmap(""), isSystemOverlay(false) {}
+ asset_path() : path(""), type(kFileTypeRegular), idmap(""),
+ isSystemOverlay(false), isSystemAsset(false) {}
String8 path;
FileType type;
String8 idmap;
bool isSystemOverlay;
+ bool isSystemAsset;
};
Asset* openInPathLocked(const char* fileName, AccessMode mode,
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 49b6333e8a4d..428a2b831e1a 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1552,9 +1552,9 @@ public:
status_t add(Asset* asset, const int32_t cookie=-1, bool copyData=false);
status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false,
- bool appAsLib=false);
+ bool appAsLib=false, bool isSystemAsset=false);
- status_t add(ResTable* src);
+ status_t add(ResTable* src, bool isSystemAsset=false);
status_t addEmpty(const int32_t cookie);
status_t getError() const;
@@ -1822,9 +1822,9 @@ public:
// Return the configurations (ResTable_config) that we know about
void getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap=false,
- bool ignoreAndroidPackage=false) const;
+ bool ignoreAndroidPackage=false, bool includeSystemConfigs=true) const;
- void getLocales(Vector<String8>* locales) const;
+ void getLocales(Vector<String8>* locales, bool includeSystemLocales=true) const;
// Generate an idmap.
//
@@ -1860,7 +1860,7 @@ private:
typedef Vector<Type*> TypeList;
status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
- bool appAsLib, const int32_t cookie, bool copyData);
+ bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset=false);
ssize_t getResourcePackageIndex(uint32_t resID) const;
@@ -1873,10 +1873,11 @@ private:
size_t nameLen, uint32_t* outTypeSpecFlags) const;
status_t parsePackage(
- const ResTable_package* const pkg, const Header* const header, bool appAsLib);
+ const ResTable_package* const pkg, const Header* const header,
+ bool appAsLib, bool isSystemAsset);
void print_value(const Package* pkg, const Res_value& value) const;
-
+
mutable Mutex mLock;
status_t mError;
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 40fb0d3750a8..7adad8a4b86e 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -350,7 +350,7 @@ public final class KeyChain {
/**
* Returns the {@code PrivateKey} for the requested alias, or null
- * if no there is no result.
+ * if there is no result.
*
* <p> This method may block while waiting for a connection to another process, and must never
* be called from the main thread.
@@ -371,7 +371,7 @@ public final class KeyChain {
final IKeyChainService keyChainService = keyChainConnection.getService();
final String keyId = keyChainService.requestPrivateKey(alias);
if (keyId == null) {
- throw new KeyChainException("keystore had a problem");
+ return null;
}
return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 8a03b94492d8..6913f43a87c3 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -176,7 +176,8 @@ AssetManager::~AssetManager(void)
delete[] mVendor;
}
-bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAsLib)
+bool AssetManager::addAssetPath(
+ const String8& path, int32_t* cookie, bool appAsLib, bool isSystemAsset)
{
AutoMutex _l(mLock);
@@ -222,6 +223,7 @@ bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAs
}
delete manifestAsset;
+ ap.isSystemAsset = isSystemAsset;
mAssetPaths.add(ap);
// new paths are always added at the end
@@ -233,6 +235,7 @@ bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAs
// Load overlays, if any
asset_path oap;
for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
+ oap.isSystemAsset = isSystemAsset;
mAssetPaths.add(oap);
}
#endif
@@ -340,7 +343,7 @@ bool AssetManager::addDefaultAssets()
String8 path(root);
path.appendPath(kSystemAssets);
- return addAssetPath(path, NULL);
+ return addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
}
int32_t AssetManager::nextAssetPath(const int32_t cookie) const
@@ -682,10 +685,10 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con
ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
if (sharedRes != NULL) {
ALOGV("Copying existing resources for %s", ap.path.string());
- mResources->add(sharedRes);
+ mResources->add(sharedRes, ap.isSystemAsset);
} else {
ALOGV("Parsing resources for %s", ap.path.string());
- mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib);
+ mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib, ap.isSystemAsset);
}
onlyEmptyResources = false;
@@ -831,11 +834,11 @@ bool AssetManager::isUpToDate()
return mZipSet.isUpToDate();
}
-void AssetManager::getLocales(Vector<String8>* locales) const
+void AssetManager::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
{
ResTable* res = mResources;
if (res != NULL) {
- res->getLocales(locales);
+ res->getLocales(locales, includeSystemLocales);
}
const size_t numLocales = locales->size();
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 21b543eefa01..44f92c7bf3d6 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3080,13 +3080,16 @@ struct ResTable::Package
// table that defined the package); the ones after are skins on top of it.
struct ResTable::PackageGroup
{
- PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id, bool appAsLib)
+ PackageGroup(
+ ResTable* _owner, const String16& _name, uint32_t _id,
+ bool appAsLib, bool _isSystemAsset)
: owner(_owner)
, name(_name)
, id(_id)
, largestTypeId(0)
, bags(NULL)
, dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
+ , isSystemAsset(_isSystemAsset)
{ }
~PackageGroup() {
@@ -3178,6 +3181,10 @@ struct ResTable::PackageGroup
// by having these tables in a per-package scope rather than
// per-package-group.
DynamicRefTable dynamicRefTable;
+
+ // If the package group comes from a system asset. Used in
+ // determining non-system locales.
+ const bool isSystemAsset;
};
struct ResTable::bag_set
@@ -3572,8 +3579,9 @@ status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
copyData);
}
-status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
- bool appAsLib) {
+status_t ResTable::add(
+ Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
+ bool appAsLib, bool isSystemAsset) {
const void* data = asset->getBuffer(true);
if (data == NULL) {
ALOGW("Unable to get buffer of resource asset file");
@@ -3592,20 +3600,21 @@ status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bo
}
return addInternal(data, static_cast<size_t>(asset->getLength()),
- idmapData, idmapSize, appAsLib, cookie, copyData);
+ idmapData, idmapSize, appAsLib, cookie, copyData, isSystemAsset);
}
-status_t ResTable::add(ResTable* src)
+status_t ResTable::add(ResTable* src, bool isSystemAsset)
{
mError = src->mError;
- for (size_t i=0; i<src->mHeaders.size(); i++) {
+ for (size_t i=0; i < src->mHeaders.size(); i++) {
mHeaders.add(src->mHeaders[i]);
}
- for (size_t i=0; i<src->mPackageGroups.size(); i++) {
+ for (size_t i=0; i < src->mPackageGroups.size(); i++) {
PackageGroup* srcPg = src->mPackageGroups[i];
- PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id, false);
+ PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id,
+ false /* appAsLib */, isSystemAsset || srcPg->isSystemAsset);
for (size_t j=0; j<srcPg->packages.size(); j++) {
pg->packages.add(srcPg->packages[j]);
}
@@ -3646,7 +3655,7 @@ status_t ResTable::addEmpty(const int32_t cookie) {
}
status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
- bool appAsLib, const int32_t cookie, bool copyData)
+ bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset)
{
if (!data) {
return NO_ERROR;
@@ -3749,7 +3758,8 @@ status_t ResTable::addInternal(const void* data, size_t dataSize, const void* id
return (mError=BAD_TYPE);
}
- if (parsePackage((ResTable_package*)chunk, header, appAsLib) != NO_ERROR) {
+ if (parsePackage(
+ (ResTable_package*)chunk, header, appAsLib, isSystemAsset) != NO_ERROR) {
return mError;
}
curPackage++;
@@ -5663,7 +5673,7 @@ const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) con
}
void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
- bool ignoreAndroidPackage) const {
+ bool ignoreAndroidPackage, bool includeSystemConfigs) const {
const size_t packageCount = mPackageGroups.size();
String16 android("android");
for (size_t i = 0; i < packageCount; i++) {
@@ -5671,6 +5681,9 @@ void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMi
if (ignoreAndroidPackage && android == packageGroup->name) {
continue;
}
+ if (!includeSystemConfigs && packageGroup->isSystemAsset) {
+ continue;
+ }
const size_t typeCount = packageGroup->types.size();
for (size_t j = 0; j < typeCount; j++) {
const TypeList& typeList = packageGroup->types[j];
@@ -5707,11 +5720,14 @@ void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMi
}
}
-void ResTable::getLocales(Vector<String8>* locales) const
+void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
{
Vector<ResTable_config> configs;
ALOGV("calling getConfigurations");
- getConfigurations(&configs);
+ getConfigurations(&configs,
+ false /* ignoreMipmap */,
+ false /* ignoreAndroidPackage */,
+ includeSystemLocales /* includeSystemConfigs */);
ALOGV("called getConfigurations size=%d", (int)configs.size());
const size_t I = configs.size();
@@ -5937,7 +5953,7 @@ status_t ResTable::getEntry(
}
status_t ResTable::parsePackage(const ResTable_package* const pkg,
- const Header* const header, bool appAsLib)
+ const Header* const header, bool appAsLib, bool isSystemAsset)
{
const uint8_t* base = (const uint8_t*)pkg;
status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
@@ -5985,8 +6001,8 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
if (id >= 256) {
LOG_ALWAYS_FATAL("Package id out of range");
return NO_ERROR;
- } else if (id == 0 || appAsLib) {
- // This is a library so assign an ID
+ } else if (id == 0 || appAsLib || isSystemAsset) {
+ // This is a library or a system asset, so assign an ID
id = mNextPackageId++;
}
@@ -6018,7 +6034,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
- group = new PackageGroup(this, String16(tmpName), id, appAsLib);
+ group = new PackageGroup(this, String16(tmpName), id, appAsLib, isSystemAsset);
if (group == NULL) {
delete package;
return (mError=NO_MEMORY);
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 0d1ee46712ee..11056d4fac97 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -86,7 +86,7 @@ hwui_src_files := \
TextDropShadowCache.cpp \
Texture.cpp \
TextureCache.cpp \
- VectorDrawablePath.cpp \
+ VectorDrawable.cpp \
protos/hwui.proto
hwui_test_common_src_files := \
@@ -108,6 +108,7 @@ ifeq (true, $(HWUI_NEW_OPS))
hwui_src_files += \
BakedOpDispatcher.cpp \
BakedOpRenderer.cpp \
+ BakedOpState.cpp \
OpReorderer.cpp \
RecordingCanvas.cpp
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 0f0768f08a5e..097675a5f520 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -79,7 +79,9 @@ void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer,
.setTransform(Matrix4::identity(), TransformFlags::None)
.setModelViewIdentityEmptyBounds()
.build();
- renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
+ ClipRect renderTargetClip(opList.clip);
+ const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
+ renderer.renderGlop(nullptr, clip, glop);
}
void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
@@ -183,7 +185,9 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
.setTransform(Matrix4::identity(), TransformFlags::None)
.setModelViewIdentityEmptyBounds()
.build();
- renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
+ ClipRect renderTargetClip(opList.clip);
+ const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
+ renderer.renderGlop(nullptr, clip, glop);
}
static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer,
@@ -224,7 +228,7 @@ enum class TextRenderType {
};
static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state,
- const Rect* renderClip, TextRenderType renderType) {
+ const ClipBase* renderClip, TextRenderType renderType) {
FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
if (CC_UNLIKELY(PaintUtils::hasTextShadow(op.paint))) {
@@ -272,7 +276,7 @@ static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const Bake
bool forceFinish = (renderType == TextRenderType::Flush);
bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
- const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect : nullptr;
+ const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect() : nullptr;
fontRenderer.renderPosText(op.paint, localOpClip,
(const char*) op.glyphs, op.glyphCount, x, y,
op.positions, mustDirtyRenderTarget ? &layerBounds : nullptr, &functor, forceFinish);
@@ -287,7 +291,8 @@ static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const Bake
void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer,
const MergedBakedOpList& opList) {
- const Rect* clip = opList.clipSideFlags ? &opList.clip : nullptr;
+ ClipRect renderTargetClip(opList.clip);
+ const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
for (size_t i = 0; i < opList.count; i++) {
const BakedOpState& state = *(opList.states[i]);
const TextOp& op = *(static_cast<const TextOp*>(state.op));
@@ -297,26 +302,6 @@ void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer,
}
}
-void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) {
- LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer&, const BeginLayerOp&, const BakedOpState&) {
- LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer&, const EndLayerOp&, const BakedOpState&) {
- LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onCirclePropsOp(BakedOpRenderer&, const CirclePropsOp&, const BakedOpState&) {
- LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onRoundRectPropsOp(BakedOpRenderer&, const RoundRectPropsOp&, const BakedOpState&) {
- LOG_ALWAYS_FATAL("unsupported operation");
-}
-
namespace VertexBufferRenderFlags {
enum {
Offset = 0x1,
@@ -701,14 +686,13 @@ void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleR
}
void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) {
- const Rect* clip = state.computedState.clipSideFlags ? &state.computedState.clipRect : nullptr;
- renderTextOp(renderer, op, state, clip, TextRenderType::Flush);
+ renderTextOp(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush);
}
void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, const BakedOpState& state) {
// Note: can't trust clipSideFlags since we record with unmappedBounds == clip.
// TODO: respect clipSideFlags, once we record with bounds
- const Rect* renderTargetClip = &state.computedState.clipRect;
+ auto renderTargetClip = state.computedState.clipState;
FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
fontRenderer.setFont(op.paint, SkMatrix::I());
diff --git a/libs/hwui/BakedOpDispatcher.h b/libs/hwui/BakedOpDispatcher.h
index ed34ada90272..4dfdd3ff619a 100644
--- a/libs/hwui/BakedOpDispatcher.h
+++ b/libs/hwui/BakedOpDispatcher.h
@@ -36,13 +36,13 @@ public:
// Declares all "onMergedBitmapOps(...)" style methods for mergeable op types
#define X(Type) \
static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList);
- MAP_MERGED_OPS(X)
+ MAP_MERGEABLE_OPS(X)
#undef X
// Declares all "onBitmapOp(...)" style methods for every op type
#define X(Type) \
static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state);
- MAP_OPS(X)
+ MAP_RENDERABLE_OPS(X)
#undef X
};
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index f8282dc1073a..a0d5faed270d 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -60,27 +60,67 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const
}
void BakedOpRenderer::endLayer() {
+ if (mRenderTarget.stencil) {
+ // if stencil was used for clipping, detach it and return it to pool
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+ LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "glfbrb endlayer failed");
+ mCaches.renderBufferCache.put(mRenderTarget.stencil);
+ mRenderTarget.stencil = nullptr;
+ }
+ mRenderTarget.lastStencilClip = nullptr;
+
mRenderTarget.offscreenBuffer->updateMeshFromRegion();
- mRenderTarget.offscreenBuffer = nullptr;
+ mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.
// Detach the texture from the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
- mRenderTarget.frameBufferId = -1;
+ mRenderTarget.frameBufferId = 0;
}
void BakedOpRenderer::startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {
+ LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "primary framebufferId must be 0");
mRenderState.bindFramebuffer(0);
setViewport(width, height);
- mCaches.clearGarbage();
if (!mOpaque) {
clearColorBuffer(repaintRect);
}
+
+ mRenderState.debugOverdraw(true, true);
}
-void BakedOpRenderer::endFrame() {
+void BakedOpRenderer::endFrame(const Rect& repaintRect) {
+ if (CC_UNLIKELY(Properties::debugOverdraw)) {
+ ClipRect overdrawClip(repaintRect);
+ Rect viewportRect(mRenderTarget.viewportWidth, mRenderTarget.viewportHeight);
+ // overdraw visualization
+ for (int i = 1; i <= 4; i++) {
+ if (i < 4) {
+ // nth level of overdraw tests for n+1 draws per pixel
+ mRenderState.stencil().enableDebugTest(i + 1, false);
+ } else {
+ // 4th level tests for 4 or higher draws per pixel
+ mRenderState.stencil().enableDebugTest(4, true);
+ }
+
+ SkPaint paint;
+ paint.setColor(mCaches.getOverdrawColor(i));
+ Glop glop;
+ GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(nullptr)
+ .setMeshUnitQuad()
+ .setFillPaint(paint, 1.0f)
+ .setTransform(Matrix4::identity(), TransformFlags::None)
+ .setModelViewMapUnitToRect(viewportRect)
+ .build();
+ renderGlop(nullptr, &overdrawClip, glop);
+ }
+ mRenderState.stencil().disable();
+ }
+
+ mCaches.clearGarbage();
mCaches.pathCache.trim();
mCaches.tessellationCache.trim();
@@ -128,12 +168,121 @@ Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
return texture;
}
-void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const Rect* clip) {
+// clears and re-fills stencil with provided rendertarget space quads,
+// and then put stencil into test mode
+void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
+ int incrementThreshold) {
+ mRenderState.stencil().enableWrite(incrementThreshold);
+ mRenderState.stencil().clear();
+ Glop glop;
+ GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(nullptr)
+ .setMeshIndexedQuads(quadVertices.data(), quadVertices.size() / 4)
+ .setFillBlack()
+ .setTransform(Matrix4::identity(), TransformFlags::None)
+ .setModelViewIdentityEmptyBounds()
+ .build();
+ mRenderState.render(glop, mRenderTarget.orthoMatrix);
+ mRenderState.stencil().enableTest(incrementThreshold);
+}
+
+void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) {
+ auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
+ int quadCount = rectList.getTransformedRectanglesCount();
+ std::vector<Vertex> rectangleVertices;
+ rectangleVertices.reserve(quadCount * 4);
+ for (int i = 0; i < quadCount; i++) {
+ const TransformedRectangle& tr(rectList.getTransformedRectangle(i));
+ const Matrix4& transform = tr.getTransform();
+ Rect bounds = tr.getBounds();
+ if (transform.rectToRect()) {
+ // If rectToRect, can simply map bounds before storing verts
+ transform.mapRect(bounds);
+ bounds.doIntersect(clip->rect);
+ if (bounds.isEmpty()) {
+ continue; // will be outside of scissor, skip
+ }
+ }
+
+ rectangleVertices.push_back(Vertex{bounds.left, bounds.top});
+ rectangleVertices.push_back(Vertex{bounds.right, bounds.top});
+ rectangleVertices.push_back(Vertex{bounds.left, bounds.bottom});
+ rectangleVertices.push_back(Vertex{bounds.right, bounds.bottom});
+
+ if (!transform.rectToRect()) {
+ // If not rectToRect, must map each point individually
+ for (auto cur = rectangleVertices.end() - 4; cur < rectangleVertices.end(); cur++) {
+ transform.mapPoint(cur->x, cur->y);
+ }
+ }
+ }
+ setupStencilQuads(rectangleVertices, rectList.getTransformedRectanglesCount());
+}
+
+void BakedOpRenderer::setupStencilRegion(const ClipBase* clip) {
+ auto&& region = reinterpret_cast<const ClipRegion*>(clip)->region;
+
+ std::vector<Vertex> regionVertices;
+ SkRegion::Cliperator it(region, clip->rect.toSkIRect());
+ while (!it.done()) {
+ const SkIRect& r = it.rect();
+ regionVertices.push_back(Vertex{(float)r.fLeft, (float)r.fTop});
+ regionVertices.push_back(Vertex{(float)r.fRight, (float)r.fTop});
+ regionVertices.push_back(Vertex{(float)r.fLeft, (float)r.fBottom});
+ regionVertices.push_back(Vertex{(float)r.fRight, (float)r.fBottom});
+ it.next();
+ }
+ setupStencilQuads(regionVertices, 0);
+}
+
+void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* clip) {
+ // prepare scissor / stencil
mRenderState.scissor().setEnabled(clip != nullptr);
if (clip) {
- mRenderState.scissor().set(clip->left, mRenderTarget.viewportHeight - clip->bottom,
- clip->getWidth(), clip->getHeight());
+ mRenderState.scissor().set(mRenderTarget.viewportHeight, clip->rect);
+ }
+
+ if (CC_LIKELY(!Properties::debugOverdraw)) {
+ // only modify stencil mode and content when it's not used for overdraw visualization
+ if (CC_UNLIKELY(clip && clip->mode != ClipMode::Rectangle)) {
+ // NOTE: this pointer check is only safe for non-rect clips,
+ // since rect clips may be created on the stack
+ if (mRenderTarget.lastStencilClip != clip) {
+ // Stencil needed, but current stencil isn't up to date
+ mRenderTarget.lastStencilClip = clip;
+
+ if (mRenderTarget.frameBufferId != 0 && !mRenderTarget.stencil) {
+ OffscreenBuffer* layer = mRenderTarget.offscreenBuffer;
+ mRenderTarget.stencil = mCaches.renderBufferCache.get(
+ Stencil::getLayerStencilFormat(),
+ layer->texture.width, layer->texture.height);
+ // stencil is bound + allocated - associate it with current FBO
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, mRenderTarget.stencil->getName());
+ }
+
+ if (clip->mode == ClipMode::RectangleList) {
+ setupStencilRectList(clip);
+ } else {
+ setupStencilRegion(clip);
+ }
+ } else {
+ // stencil is up to date - just need to ensure it's enabled (since an unclipped
+ // or scissor-only clipped op may have been drawn, disabling the stencil)
+ int incrementThreshold = 0;
+ if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
+ auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
+ incrementThreshold = rectList.getTransformedRectanglesCount();
+ }
+ mRenderState.stencil().enableTest(incrementThreshold);
+ }
+ } else {
+ // either scissor or no clip, so disable stencil test
+ mRenderState.stencil().disable();
+ }
}
+
+ // dirty offscreenbuffer
if (dirtyBounds && mRenderTarget.offscreenBuffer) {
// register layer damage to draw-back region
android::Rect dirty(dirtyBounds->left, dirtyBounds->top,
@@ -142,17 +291,18 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const Rect* clip) {
}
}
-void BakedOpRenderer::renderGlop(const Rect* dirtyBounds, const Rect* clip, const Glop& glop) {
+void BakedOpRenderer::renderGlop(const Rect* dirtyBounds, const ClipBase* clip,
+ const Glop& glop) {
prepareRender(dirtyBounds, clip);
mRenderState.render(glop, mRenderTarget.orthoMatrix);
if (!mRenderTarget.frameBufferId) mHasDrawn = true;
}
void BakedOpRenderer::renderFunctor(const FunctorOp& op, const BakedOpState& state) {
- prepareRender(&state.computedState.clippedBounds, &state.computedState.clipRect);
+ prepareRender(&state.computedState.clippedBounds, state.computedState.getClipIfNeeded());
DrawGlInfo info;
- auto&& clip = state.computedState.clipRect;
+ auto&& clip = state.computedState.clipRect();
info.clipLeft = clip.left;
info.clipTop = clip.top;
info.clipRight = clip.right;
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index f158e8bb49c3..65e8b29a9ed2 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -27,6 +27,7 @@ class Caches;
struct Glop;
class Layer;
class RenderState;
+struct ClipBase;
/**
* Main rendering manager for a collection of work - one frame + any contained FBOs.
@@ -59,7 +60,7 @@ public:
Caches& caches() { return mCaches; }
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect);
- void endFrame();
+ void endFrame(const Rect& repaintRect);
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height);
void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect);
void endLayer();
@@ -68,21 +69,23 @@ public:
const LightInfo& getLightInfo() const { return mLightInfo; }
void renderGlop(const BakedOpState& state, const Glop& glop) {
- bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
renderGlop(&state.computedState.clippedBounds,
- useScissor ? &state.computedState.clipRect : nullptr,
+ state.computedState.getClipIfNeeded(),
glop);
}
void renderFunctor(const FunctorOp& op, const BakedOpState& state);
- void renderGlop(const Rect* dirtyBounds, const Rect* clip, const Glop& glop);
+ void renderGlop(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop);
bool offscreenRenderTarget() { return mRenderTarget.offscreenBuffer != nullptr; }
void dirtyRenderTarget(const Rect& dirtyRect);
bool didDraw() const { return mHasDrawn; }
private:
void setViewport(uint32_t width, uint32_t height);
void clearColorBuffer(const Rect& clearRect);
- void prepareRender(const Rect* dirtyBounds, const Rect* clip);
+ void prepareRender(const Rect* dirtyBounds, const ClipBase* clip);
+ void setupStencilRectList(const ClipBase* clip);
+ void setupStencilRegion(const ClipBase* clip);
+ void setupStencilQuads(std::vector<Vertex>& quadVertices, int incrementThreshold);
RenderState& mRenderState;
Caches& mCaches;
@@ -92,10 +95,23 @@ private:
// render target state - setup by start/end layer/frame
// only valid to use in between start/end pairs.
struct {
+ // If not drawing to a layer: fbo = 0, offscreenBuffer = null,
+ // Otherwise these refer to currently painting layer's state
GLuint frameBufferId = 0;
OffscreenBuffer* offscreenBuffer = nullptr;
+
+ // Used when drawing to a layer and using stencil clipping. otherwise null.
+ RenderBuffer* stencil = nullptr;
+
+ // value representing the ClipRectList* or ClipRegion* currently stored in
+ // the stencil of the current render target
+ const ClipBase* lastStencilClip = nullptr;
+
+ // Size of renderable region in current render target - for layers, may not match actual
+ // bounds of FBO texture. offscreenBuffer->texture has this information.
uint32_t viewportWidth = 0;
uint32_t viewportHeight = 0;
+
Matrix4 orthoMatrix;
} mRenderTarget;
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
new file mode 100644
index 000000000000..e6b943a606d5
--- /dev/null
+++ b/libs/hwui/BakedOpState.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "BakedOpState.h"
+
+#include "ClipArea.h"
+
+namespace android {
+namespace uirenderer {
+
+ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp, bool expandForStroke) {
+ // resolvedMatrix = parentMatrix * localMatrix
+ transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
+
+ // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
+ clippedBounds = recordedOp.unmappedBounds;
+ if (CC_UNLIKELY(expandForStroke)) {
+ // account for non-hairline stroke
+ clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f);
+ }
+ transform.mapRect(clippedBounds);
+ if (CC_UNLIKELY(expandForStroke
+ && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
+ // account for hairline stroke when stroke may be < 1 scaled pixel
+ // Non translate || strokeWidth < 1 is conservative, but will cover all cases
+ clippedBounds.outset(0.5f);
+ }
+
+ // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
+ clipState = snapshot.mutateClipArea().serializeIntersectedClip(allocator,
+ recordedOp.localClip, *(snapshot.transform));
+ LOG_ALWAYS_FATAL_IF(!clipState, "must clip!");
+
+ const Rect& clipRect = clipState->rect;
+ if (CC_UNLIKELY(clipRect.isEmpty() || !clippedBounds.intersects(clipRect))) {
+ // Rejected based on either empty clip, or bounds not intersecting with clip
+ if (clipState) {
+ allocator.rewindIfLastAlloc(clipState);
+ clipState = nullptr;
+ }
+ 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;
+ clippedBounds.doIntersect(clipRect);
+ }
+}
+
+ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot) {
+ transform = *snapshot.transform;
+
+ // Since the op doesn't have known bounds, we conservatively set the mapped bounds
+ // to the current clipRect, and clipSideFlags to Full.
+ clipState = snapshot.mutateClipArea().serializeClip(allocator);
+ LOG_ALWAYS_FATAL_IF(!clipState, "clipState required");
+ clippedBounds = clipState->rect;
+ transform.mapRect(clippedBounds);
+ clipSideFlags = OpClipSideFlags::Full;
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index b12c0c970352..9df4e3aa5442 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -52,89 +52,35 @@ struct MergedBakedOpList {
*/
class ResolvedRenderState {
public:
- // TODO: remove the mapRects/matrix multiply when snapshot & recorded transforms are translates
- ResolvedRenderState(const Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke) {
- /* TODO: benchmark a fast path for translate-only matrices, such as:
- if (CC_LIKELY(snapshot.transform->getType() == Matrix4::kTypeTranslate
- && recordedOp.localMatrix.getType() == Matrix4::kTypeTranslate)) {
- float translateX = snapshot.transform->getTranslateX() + recordedOp.localMatrix.getTranslateX();
- float translateY = snapshot.transform->getTranslateY() + recordedOp.localMatrix.getTranslateY();
- transform.loadTranslate(translateX, translateY, 0);
-
- // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
- clipRect = recordedOp.localClipRect;
- clipRect.translate(translateX, translateY);
- clipRect.doIntersect(snapshot.getClipRect());
- clipRect.snapToPixelBoundaries();
-
- // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
- clippedBounds = recordedOp.unmappedBounds;
- clippedBounds.translate(translateX, translateY);
- } ... */
-
- // resolvedMatrix = parentMatrix * localMatrix
- transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
-
- // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
- clipRect = recordedOp.localClipRect;
- snapshot.transform->mapRect(clipRect);
- clipRect.doIntersect(snapshot.getRenderTargetClip());
- clipRect.snapToPixelBoundaries();
-
- // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
- clippedBounds = recordedOp.unmappedBounds;
- if (CC_UNLIKELY(expandForStroke)) {
- // account for non-hairline stroke
- clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f);
- }
- transform.mapRect(clippedBounds);
- if (CC_UNLIKELY(expandForStroke
- && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
- // account for hairline stroke when stroke may be < 1 scaled pixel
- // Non translate || strokeWidth < 1 is conservative, but will cover all cases
- clippedBounds.outset(0.5f);
- }
+ ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp, bool expandForStroke);
- 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;
- clippedBounds.doIntersect(clipRect);
-
- /**
- * TODO: once we support complex clips, we may want to reject to avoid that work where
- * possible. Should we:
- * 1 - quickreject based on clippedBounds, quick early (duplicating logic in resolvedOp)
- * 2 - merge stuff into tryConstruct factory method, so it can handle quickRejection
- * and early return null in one place.
- */
- }
-
- /**
- * Constructor for unbounded ops without transform/clip (namely shadows)
- *
- * Since the op doesn't have known bounds, we conservatively set the mapped bounds
- * to the current clipRect, and clipSideFlags to Full.
- */
- ResolvedRenderState(const Snapshot& snapshot) {
- transform = *snapshot.transform;
- clipRect = snapshot.getRenderTargetClip();
- clippedBounds = clipRect;
- transform.mapRect(clippedBounds);
- clipSideFlags = OpClipSideFlags::Full;
- }
+ // Constructor for unbounded ops without transform/clip (namely shadows)
+ ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot);
Rect computeLocalSpaceClip() const {
Matrix4 inverse;
inverse.loadInverse(transform);
- Rect outClip(clipRect);
+ Rect outClip(clipRect());
inverse.mapRect(outClip);
return outClip;
}
Matrix4 transform;
- Rect clipRect;
+ const Rect& clipRect() const {
+ return clipState->rect;
+ }
+ bool requiresClip() const {
+ return clipSideFlags != OpClipSideFlags::None
+ || CC_UNLIKELY(clipState->mode != ClipMode::Rectangle);
+ }
+
+ // returns the clip if it's needed to draw the operation, otherwise nullptr
+ const ClipBase* getClipIfNeeded() const {
+ return requiresClip() ? clipState : nullptr;
+ }
+ const ClipBase* clipState = nullptr;
int clipSideFlags = 0;
Rect clippedBounds;
};
@@ -147,8 +93,9 @@ public:
class BakedOpState {
public:
static BakedOpState* tryConstruct(LinearAllocator& allocator,
- const Snapshot& snapshot, const RecordedOp& recordedOp) {
- BakedOpState* bakedState = new (allocator) BakedOpState(snapshot, recordedOp, false);
+ Snapshot& snapshot, const RecordedOp& recordedOp) {
+ BakedOpState* bakedState = new (allocator) BakedOpState(
+ allocator, snapshot, recordedOp, false);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
allocator.rewindIfLastAlloc(bakedState);
@@ -165,13 +112,13 @@ public:
};
static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
- const Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
+ Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
: true;
BakedOpState* bakedState = new (allocator) BakedOpState(
- snapshot, recordedOp, expandForStroke);
+ allocator, snapshot, recordedOp, expandForStroke);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
allocator.rewindIfLastAlloc(bakedState);
@@ -181,11 +128,11 @@ public:
}
static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
- const Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
+ Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
if (snapshot.getRenderTargetClip().isEmpty()) return nullptr;
// clip isn't empty, so construct the op
- return new (allocator) BakedOpState(snapshot, shadowOpPtr);
+ return new (allocator) BakedOpState(allocator, snapshot, shadowOpPtr);
}
static void* operator new(size_t size, LinearAllocator& allocator) {
@@ -202,15 +149,16 @@ public:
const RecordedOp* op;
private:
- BakedOpState(const Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke)
- : computedState(snapshot, recordedOp, expandForStroke)
+ BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp, bool expandForStroke)
+ : computedState(allocator, snapshot, recordedOp, expandForStroke)
, alpha(snapshot.alpha)
, roundRectClipState(snapshot.roundRectClipState)
, projectionPathMask(snapshot.projectionPathMask)
, op(&recordedOp) {}
- BakedOpState(const Snapshot& snapshot, const ShadowOp* shadowOpPtr)
- : computedState(snapshot)
+ BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr)
+ : computedState(allocator, snapshot)
, alpha(snapshot.alpha)
, roundRectClipState(snapshot.roundRectClipState)
, projectionPathMask(snapshot.projectionPathMask)
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index cf76e6be46c4..cf2726b5f530 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -45,6 +45,21 @@ CanvasState::~CanvasState() {
}
}
+void CanvasState::initializeRecordingSaveStack(int viewportWidth, int viewportHeight) {
+ if (mWidth != viewportWidth || mHeight != viewportHeight) {
+ mWidth = viewportWidth;
+ mHeight = viewportHeight;
+ mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight);
+ mCanvas.onViewportInitialized();
+ }
+
+ freeAllSnapshots();
+ mSnapshot = allocSnapshot(&mFirstSnapshot,
+ SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ mSnapshot->setRelativeLightCenter(Vector3());
+ mSaveCount = 1;
+}
+
void CanvasState::initializeSaveStack(
int viewportWidth, int viewportHeight,
float clipLeft, float clipTop,
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index 4709ef41915f..b9e87ae5595d 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -80,6 +80,12 @@ public:
* Initializes the first snapshot, computing the projection matrix,
* and stores the dimensions of the render target.
*/
+ void initializeRecordingSaveStack(int viewportWidth, int viewportHeight);
+
+ /**
+ * Initializes the first snapshot, computing the projection matrix,
+ * and stores the dimensions of the render target.
+ */
void initializeSaveStack(int viewportWidth, int viewportHeight,
float clipLeft, float clipTop, float clipRight, float clipBottom,
const Vector3& lightCenter);
@@ -168,6 +174,7 @@ private:
void freeAllSnapshots();
/// indicates that the clip has been changed since the last time it was consumed
+ // TODO: delete when switching to HWUI_NEW_OPS
bool mDirtyClip;
/// Dimensions of the drawing surface
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 5f166cafd01c..160090dcd8cc 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -15,10 +15,11 @@
*/
#include "ClipArea.h"
+#include "utils/LinearAllocator.h"
+
#include <SkPath.h>
#include <limits>
-
-#include "Rect.h"
+#include <type_traits>
namespace android {
namespace uirenderer {
@@ -171,12 +172,18 @@ SkRegion RectangleList::convertToRegion(const SkRegion& clip) const {
return rectangleListAsRegion;
}
+void RectangleList::transform(const Matrix4& transform) {
+ for (int index = 0; index < mTransformedRectanglesCount; index++) {
+ mTransformedRectangles[index].transform(transform);
+ }
+}
+
/*
* ClipArea
*/
ClipArea::ClipArea()
- : mMode(Mode::Rectangle) {
+ : mMode(ClipMode::Rectangle) {
}
/*
@@ -184,39 +191,44 @@ ClipArea::ClipArea()
*/
void ClipArea::setViewportDimensions(int width, int height) {
+ mPostViewportClipObserved = false;
mViewportBounds.set(0, 0, width, height);
mClipRect = mViewportBounds;
}
void ClipArea::setEmpty() {
- mMode = Mode::Rectangle;
+ onClipUpdated();
+ mMode = ClipMode::Rectangle;
mClipRect.setEmpty();
mClipRegion.setEmpty();
mRectangleList.setEmpty();
}
void ClipArea::setClip(float left, float top, float right, float bottom) {
- mMode = Mode::Rectangle;
+ onClipUpdated();
+ mMode = ClipMode::Rectangle;
mClipRect.set(left, top, right, bottom);
mClipRegion.setEmpty();
}
void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
SkRegion::Op op) {
+ onClipUpdated();
switch (mMode) {
- case Mode::Rectangle:
+ case ClipMode::Rectangle:
rectangleModeClipRectWithTransform(r, transform, op);
break;
- case Mode::RectangleList:
+ case ClipMode::RectangleList:
rectangleListModeClipRectWithTransform(r, transform, op);
break;
- case Mode::Region:
+ case ClipMode::Region:
regionModeClipRectWithTransform(r, transform, op);
break;
}
}
void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
+ onClipUpdated();
enterRegionMode();
mClipRegion.op(region, op);
onClipRegionUpdated();
@@ -224,6 +236,7 @@ void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
SkRegion::Op op) {
+ onClipUpdated();
SkMatrix skTransform;
transform->copyTo(skTransform);
SkPath transformed;
@@ -241,7 +254,7 @@ void ClipArea::enterRectangleMode() {
// Entering rectangle mode discards any
// existing clipping information from the other modes.
// The only way this occurs is by a clip setting operation.
- mMode = Mode::Rectangle;
+ mMode = ClipMode::Rectangle;
}
void ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
@@ -276,8 +289,8 @@ void ClipArea::enterRectangleListMode() {
// Is is only legal to enter rectangle list mode from
// rectangle mode, since rectangle list mode cannot represent
// all clip areas that can be represented by a region.
- ALOG_ASSERT(mMode == Mode::Rectangle);
- mMode = Mode::RectangleList;
+ ALOG_ASSERT(mMode == ClipMode::Rectangle);
+ mMode = ClipMode::RectangleList;
mRectangleList.set(mClipRect, Matrix4::identity());
}
@@ -295,12 +308,11 @@ void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
*/
void ClipArea::enterRegionMode() {
- Mode oldMode = mMode;
- mMode = Mode::Region;
- if (oldMode != Mode::Region) {
- if (oldMode == Mode::Rectangle) {
- mClipRegion.setRect(mClipRect.left, mClipRect.top,
- mClipRect.right, mClipRect.bottom);
+ ClipMode oldMode = mMode;
+ mMode = ClipMode::Region;
+ if (oldMode != ClipMode::Region) {
+ if (oldMode == ClipMode::Rectangle) {
+ mClipRegion.setRect(mClipRect.toSkIRect());
} else {
mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
onClipRegionUpdated();
@@ -330,5 +342,172 @@ void ClipArea::onClipRegionUpdated() {
}
}
+/**
+ * Clip serialization
+ */
+
+const ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
+ if (!mPostViewportClipObserved) {
+ // Only initial clip-to-viewport observed, so no serialization of clip necessary
+ return nullptr;
+ }
+
+ static_assert(std::is_trivially_destructible<Rect>::value,
+ "expect Rect to be trivially destructible");
+ static_assert(std::is_trivially_destructible<RectangleList>::value,
+ "expect RectangleList to be trivially destructible");
+
+ if (mLastSerialization == nullptr) {
+ switch (mMode) {
+ case ClipMode::Rectangle:
+ mLastSerialization = allocator.create<ClipRect>(mClipRect);
+ break;
+ case ClipMode::RectangleList:
+ mLastSerialization = allocator.create<ClipRectList>(mRectangleList);
+ break;
+ case ClipMode::Region:
+ mLastSerialization = allocator.create<ClipRegion>(mClipRegion);
+ break;
+ }
+ }
+ return mLastSerialization;
+}
+
+inline static const Rect& getRect(const ClipBase* scb) {
+ return reinterpret_cast<const ClipRect*>(scb)->rect;
+}
+
+inline static const RectangleList& getRectList(const ClipBase* scb) {
+ return reinterpret_cast<const ClipRectList*>(scb)->rectList;
+}
+
+inline static const SkRegion& getRegion(const ClipBase* scb) {
+ return reinterpret_cast<const ClipRegion*>(scb)->region;
+}
+
+// Conservative check for too many rectangles to fit in rectangle list.
+// For simplicity, doesn't account for rect merging
+static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
+ int currentRectCount = clipArea.isRectangleList()
+ ? clipArea.getRectangleList().getTransformedRectanglesCount()
+ : 1;
+ int recordedRectCount = (scb->mode == ClipMode::RectangleList)
+ ? getRectList(scb).getTransformedRectanglesCount()
+ : 1;
+ return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
+}
+
+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 (!mLastResolutionResult
+ || recordedClip != mLastResolutionClip
+ || recordedClipTransform != mLastResolutionTransform) {
+ mLastResolutionClip = recordedClip;
+ mLastResolutionTransform = recordedClipTransform;
+
+ if (CC_LIKELY(mMode == ClipMode::Rectangle
+ && recordedClip->mode == ClipMode::Rectangle
+ && recordedClipTransform.rectToRect())) {
+ // common case - result is a single rectangle
+ auto rectClip = allocator.create<ClipRect>(getRect(recordedClip));
+ recordedClipTransform.mapRect(rectClip->rect);
+ rectClip->rect.doIntersect(mClipRect);
+ mLastResolutionResult = rectClip;
+ } else if (CC_UNLIKELY(mMode == ClipMode::Region
+ || recordedClip->mode == ClipMode::Region
+ || cannotFitInRectangleList(*this, recordedClip))) {
+ // region case
+ SkRegion other;
+ switch (recordedClip->mode) {
+ case ClipMode::Rectangle:
+ if (CC_LIKELY(recordedClipTransform.rectToRect())) {
+ // simple transform, skip creating SkPath
+ Rect resultClip(getRect(recordedClip));
+ recordedClipTransform.mapRect(resultClip);
+ other.setRect(resultClip.toSkIRect());
+ } else {
+ SkPath transformedRect = pathFromTransformedRectangle(getRect(recordedClip),
+ recordedClipTransform);
+ other.setPath(transformedRect, createViewportRegion());
+ }
+ break;
+ case ClipMode::RectangleList: {
+ RectangleList transformedList(getRectList(recordedClip));
+ transformedList.transform(recordedClipTransform);
+ other = transformedList.convertToRegion(createViewportRegion());
+ break;
+ }
+ case ClipMode::Region:
+ other = getRegion(recordedClip);
+
+ // TODO: handle non-translate transforms properly!
+ other.translate(recordedClipTransform.getTranslateX(),
+ recordedClipTransform.getTranslateY());
+ }
+
+ ClipRegion* regionClip = allocator.create<ClipRegion>();
+ switch (mMode) {
+ case ClipMode::Rectangle:
+ regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
+ break;
+ case ClipMode::RectangleList:
+ regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
+ other, SkRegion::kIntersect_Op);
+ break;
+ case ClipMode::Region:
+ regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
+ break;
+ }
+ regionClip->rect.set(regionClip->region.getBounds());
+ mLastResolutionResult = regionClip;
+ } else {
+ auto rectListClip = allocator.create<ClipRectList>(mRectangleList);
+ auto&& rectList = rectListClip->rectList;
+ if (mMode == ClipMode::Rectangle) {
+ rectList.set(mClipRect, Matrix4::identity());
+ }
+
+ if (recordedClip->mode == ClipMode::Rectangle) {
+ rectList.intersectWith(getRect(recordedClip), recordedClipTransform);
+ } else {
+ const RectangleList& other = getRectList(recordedClip);
+ for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
+ auto&& tr = other.getTransformedRectangle(i);
+ Matrix4 totalTransform(recordedClipTransform);
+ totalTransform.multiply(tr.getTransform());
+ rectList.intersectWith(tr.getBounds(), totalTransform);
+ }
+ }
+ rectListClip->rect = rectList.calculateBounds();
+ mLastResolutionResult = rectListClip;
+ }
+ }
+ return mLastResolutionResult;
+}
+
+void ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
+ if (!clip) return; // nothing to do
+
+ if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
+ clipRectWithTransform(getRect(clip), &transform, SkRegion::kIntersect_Op);
+ } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
+ auto&& rectList = getRectList(clip);
+ for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
+ auto&& tr = rectList.getTransformedRectangle(i);
+ Matrix4 totalTransform(transform);
+ totalTransform.multiply(tr.getTransform());
+ clipRectWithTransform(tr.getBounds(), &totalTransform, SkRegion::kIntersect_Op);
+ }
+ } else {
+ SkRegion region(getRegion(clip));
+ // TODO: handle non-translate transforms properly!
+ region.translate(transform.getTranslateX(), transform.getTranslateY());
+ clipRegion(region, SkRegion::kIntersect_Op);
+ }
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index 268301c62fc9..479796db042a 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -16,15 +16,17 @@
#ifndef CLIPAREA_H
#define CLIPAREA_H
-#include <SkRegion.h>
-
#include "Matrix.h"
#include "Rect.h"
#include "utils/Pair.h"
+#include <SkRegion.h>
+
namespace android {
namespace uirenderer {
+class LinearAllocator;
+
Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform);
class TransformedRectangle {
@@ -50,6 +52,12 @@ public:
return mTransform;
}
+ void transform(const Matrix4& transform) {
+ Matrix4 t;
+ t.loadMultiply(transform, mTransform);
+ mTransform = t;
+ }
+
private:
Rect mBounds;
Matrix4 mTransform;
@@ -66,27 +74,62 @@ public:
void setEmpty();
void set(const Rect& bounds, const Matrix4& transform);
bool intersectWith(const Rect& bounds, const Matrix4& transform);
+ void transform(const Matrix4& transform);
SkRegion convertToRegion(const SkRegion& clip) const;
Rect calculateBounds() const;
-private:
enum {
kMaxTransformedRectangles = 5
};
+private:
int mTransformedRectanglesCount;
TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles];
};
-class ClipArea {
-private:
- enum class Mode {
- Rectangle,
- Region,
- RectangleList
- };
+enum class ClipMode {
+ Rectangle,
+ RectangleList,
+ // region and path - intersected. if either is empty, don't use
+ Region
+};
+
+struct ClipBase {
+ ClipBase(ClipMode mode)
+ : mode(mode) {}
+ ClipBase(const Rect& rect)
+ : mode(ClipMode::Rectangle)
+ , rect(rect) {}
+ const ClipMode mode;
+ // Bounds of the clipping area, used to define the scissor, and define which
+ // portion of the stencil is updated/used
+ Rect rect;
+};
+
+struct ClipRect : ClipBase {
+ ClipRect(const Rect& rect)
+ : ClipBase(rect) {}
+};
+
+struct ClipRectList : ClipBase {
+ ClipRectList(const RectangleList& rectList)
+ : ClipBase(ClipMode::RectangleList)
+ , rectList(rectList) {}
+ RectangleList rectList;
+};
+
+struct ClipRegion : ClipBase {
+ ClipRegion(const SkRegion& region)
+ : ClipBase(ClipMode::Region)
+ , region(region) {}
+ ClipRegion()
+ : ClipBase(ClipMode::Region) {}
+ SkRegion region;
+};
+
+class ClipArea {
public:
ClipArea();
@@ -117,17 +160,22 @@ public:
}
bool isRegion() const {
- return Mode::Region == mMode;
+ return ClipMode::Region == mMode;
}
bool isSimple() const {
- return mMode == Mode::Rectangle;
+ return mMode == ClipMode::Rectangle;
}
bool isRectangleList() const {
- return mMode == Mode::RectangleList;
+ return mMode == ClipMode::RectangleList;
}
+ const ClipBase* serializeClip(LinearAllocator& allocator);
+ const ClipBase* serializeIntersectedClip(LinearAllocator& allocator,
+ const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+ void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+
private:
void enterRectangleMode();
void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
@@ -145,6 +193,13 @@ private:
void ensureClipRegion();
void onClipRegionUpdated();
+ // Called by every state modifying public method.
+ void onClipUpdated() {
+ mPostViewportClipObserved = true;
+ mLastSerialization = nullptr;
+ mLastResolutionResult = nullptr;
+ }
+
SkRegion createViewportRegion() {
return SkRegion(mViewportBounds.toSkIRect());
}
@@ -155,7 +210,22 @@ private:
pathAsRegion.setPath(path, createViewportRegion());
}
- Mode mMode;
+ ClipMode mMode;
+ bool mPostViewportClipObserved = false;
+
+ /**
+ * If mLastSerialization is non-null, it represents an already serialized copy
+ * of the current clip state. If null, it has not been computed.
+ */
+ const ClipBase* mLastSerialization = nullptr;
+
+ /**
+ * This pair of pointers is a single entry cache of most recently seen
+ */
+ const ClipBase* mLastResolutionResult = nullptr;
+ const ClipBase* mLastResolutionClip = nullptr;
+ Matrix4 mLastResolutionTransform;
+
Rect mViewportBounds;
Rect mClipRect;
SkRegion mClipRegion;
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index ff4dc4aef94a..99944985cda8 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -47,6 +47,7 @@ namespace uirenderer {
#if HWUI_NEW_OPS
class BakedOpState;
class BakedOpRenderer;
+struct ClipBase;
#else
class OpenGLRenderer;
#endif
@@ -57,7 +58,7 @@ public:
#if HWUI_NEW_OPS
BakedOpRenderer* renderer,
const BakedOpState* bakedState,
- const Rect* clip,
+ const ClipBase* clip,
#else
OpenGLRenderer* renderer,
#endif
@@ -81,7 +82,7 @@ public:
#if HWUI_NEW_OPS
BakedOpRenderer* renderer;
const BakedOpState* bakedState;
- const Rect* clip;
+ const ClipBase* clip;
#else
OpenGLRenderer* renderer;
#endif
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index bcf819eb42e0..e72f39621d57 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -64,7 +64,7 @@ namespace TransformFlags {
// Canvas transform isn't applied to the mesh at draw time,
//since it's already built in.
- MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove
+ MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS
};
};
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 2507ff377133..45fc16cc3136 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -78,7 +78,7 @@ GlopBuilder& GlopBuilder::setMeshTexturedIndexedVbo(GLuint vbo, GLsizei elementC
mOutGlop->mesh.vertices = {
vbo,
VertexAttribFlags::TextureCoord,
- nullptr, nullptr, nullptr,
+ nullptr, (const void*) kMeshTextureOffset, nullptr,
kTextureVertexStride };
mOutGlop->mesh.elementCount = elementCount;
return *this;
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index eb9b55f196bb..c305f65db601 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -243,6 +243,7 @@ void JankTracker::dumpData(const ProfileData* data, int fd) {
dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
(float) data->jankFrameCount / (float) data->totalFrameCount * 100.0f);
+ dprintf(fd, "\n50th percentile: %ums", findPercentile(data, 50));
dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index ad9559ffdf9f..3f492d507b0d 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -460,7 +460,7 @@ void OpReorderer::deferNodePropsAndOps(RenderNode& node) {
deferBeginLayerOp(*new (mAllocator) BeginLayerOp(
saveLayerBounds,
Matrix4::identity(),
- saveLayerBounds,
+ nullptr, // no record-time clip - need only respect defer-time one
&saveLayerPaint));
deferNodeOps(node);
deferEndLayerOp(*new (mAllocator) EndLayerOp());
@@ -604,7 +604,7 @@ void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) {
mCanvasState.getLocalClipBounds(),
mCanvasState.currentSnapshot()->getRelativeLightCenter());
BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
- mAllocator, *mCanvasState.currentSnapshot(), shadowOp);
+ mAllocator, *mCanvasState.writableSnapshot(), shadowOp);
if (CC_LIKELY(bakedOpState)) {
currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
}
@@ -652,9 +652,7 @@ void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) {
[](OpReorderer& reorderer, const RecordedOp& op) { reorderer.defer##Type(static_cast<const Type&>(op)); },
void OpReorderer::deferNodeOps(const RenderNode& renderNode) {
typedef void (*OpDispatcher) (OpReorderer& reorderer, const RecordedOp& op);
- static OpDispatcher receivers[] = {
- MAP_OPS(OP_RECEIVER)
- };
+ static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER);
// can't be null, since DL=null node rejection happens before deferNodePropsAndOps
const DisplayList& displayList = *(renderNode.getDisplayList());
@@ -681,10 +679,10 @@ void OpReorderer::deferRenderNodeOpImpl(const RenderNodeOp& op) {
if (op.renderNode->nothingToDraw()) return;
int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
- // apply state from RecordedOp
+ // apply state from RecordedOp (clip first, since op's clip is transformed by current matrix)
+ mCanvasState.writableSnapshot()->mutateClipArea().applyClip(op.localClip,
+ *mCanvasState.currentSnapshot()->transform);
mCanvasState.concatMatrix(op.localMatrix);
- mCanvasState.clipRect(op.localClipRect.left, op.localClipRect.top,
- op.localClipRect.right, op.localClipRect.bottom, SkRegion::kIntersect_Op);
// then apply state from node properties, and defer ops
deferNodePropsAndOps(*op.renderNode);
@@ -706,7 +704,7 @@ void OpReorderer::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
BakedOpState::StrokeBehavior strokeBehavior) {
// Note: here we account for stroke when baking the op
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
- mAllocator, *mCanvasState.currentSnapshot(), op, strokeBehavior);
+ mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior);
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
}
@@ -769,7 +767,7 @@ void OpReorderer::deferCirclePropsOp(const CirclePropsOp& op) {
const OvalOp* resolvedOp = new (mAllocator) OvalOp(
unmappedBounds,
op.localMatrix,
- op.localClipRect,
+ op.localClip,
op.paint);
deferOvalOp(*resolvedOp);
}
@@ -829,7 +827,7 @@ void OpReorderer::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp(
Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
op.localMatrix,
- op.localClipRect,
+ op.localClip,
op.paint, *op.rx, *op.ry);
deferRoundRectOp(*resolvedOp);
}
@@ -953,7 +951,7 @@ void OpReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) {
LayerOp* drawLayerOp = new (mAllocator) LayerOp(
beginLayerOp.unmappedBounds,
beginLayerOp.localMatrix,
- beginLayerOp.localClipRect,
+ beginLayerOp.localClip,
beginLayerOp.paint,
&mLayerReorderers[finishedLayerIndex].offscreenBuffer);
BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
@@ -968,13 +966,5 @@ void OpReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) {
}
}
-void OpReorderer::deferLayerOp(const LayerOp& op) {
- LOG_ALWAYS_FATAL("unsupported");
-}
-
-void OpReorderer::deferShadowOp(const ShadowOp& op) {
- LOG_ALWAYS_FATAL("unsupported");
-}
-
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
index dbbce8b15170..429913f6c82d 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -138,7 +138,7 @@ public:
template <typename StaticDispatcher, typename Renderer>
void replayBakedOps(Renderer& renderer) {
/**
- * defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
+ * Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
* dispatch the op via a method on a static dispatcher when the op is replayed.
*
* For example a BitmapOp would resolve, via the lambda lookup, to calling:
@@ -149,29 +149,19 @@ public:
[](void* renderer, const BakedOpState& state) { \
StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), static_cast<const Type&>(*(state.op)), state); \
},
- static BakedOpReceiver unmergedReceivers[] = {
- MAP_OPS(X)
- };
+ static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
#undef X
/**
- * defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
- * static dispatcher when the group of merged ops is replayed. Unmergeable ops trigger
- * a LOG_ALWAYS_FATAL().
+ * Defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
+ * static dispatcher when the group of merged ops is replayed.
*/
#define X(Type) \
[](void* renderer, const MergedBakedOpList& opList) { \
- LOG_ALWAYS_FATAL("op type %d does not support merging", opList.states[0]->op->opId); \
- },
- #define Y(Type) \
- [](void* renderer, const MergedBakedOpList& opList) { \
StaticDispatcher::onMerged##Type##s(*(static_cast<Renderer*>(renderer)), opList); \
},
- static MergedOpReceiver mergedReceivers[] = {
- MAP_OPS_BASED_ON_MERGEABILITY(X, Y)
- };
+ static MergedOpReceiver mergedReceivers[] = BUILD_MERGEABLE_OP_LUT(X);
#undef X
- #undef Y
// Relay through layers in reverse order, since layers
// later in the list will be drawn by earlier ones
@@ -192,7 +182,7 @@ public:
const LayerReorderer& fbo0 = mLayerReorderers[0];
renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect);
fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
- renderer.endFrame();
+ renderer.endFrame(fbo0.repaintRect);
}
void dump() const {
@@ -223,7 +213,7 @@ private:
LayerReorderer& currentLayer() { return mLayerReorderers[mLayerStack.back()]; }
BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) {
- return BakedOpState::tryConstruct(mAllocator, *mCanvasState.currentSnapshot(), recordedOp);
+ return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
}
// should always be surrounded by a save/restore pair, and not called if DisplayList is null
@@ -256,9 +246,9 @@ private:
* These private methods are called from within deferImpl to defer each individual op
* type differently.
*/
-#define INTERNAL_OP_HANDLER(Type) \
- void defer##Type(const Type& op);
- MAP_OPS(INTERNAL_OP_HANDLER)
+#define X(Type) void defer##Type(const Type& op);
+ MAP_DEFERRABLE_OPS(X)
+#undef X
std::vector<std::unique_ptr<SkPath> > mFrameAllocatedPaths;
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index 4c87b1898ae5..c4bbb7495a4c 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_HWUI_PATHPARSER_H
#define ANDROID_HWUI_PATHPARSER_H
-#include "VectorDrawablePath.h"
+#include "VectorDrawable.h"
#include "utils/VectorDrawableUtils.h"
#include <jni.h>
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 0669596b21ca..083aeb7ed585 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -53,6 +53,8 @@ int Properties::overrideSpotShadowStrength = -1;
ProfileType Properties::sProfileType = ProfileType::None;
bool Properties::sDisableProfileBars = false;
+bool Properties::waitForGpuCompletion = false;
+
static int property_get_int(const char* key, int defaultValue) {
char buf[PROPERTY_VALUE_MAX] = {'\0',};
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 1dde7e054aab..88f1dbc98926 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -285,6 +285,9 @@ public:
static ProfileType getProfileType();
+ // Should be used only by test apps
+ static bool waitForGpuCompletion;
+
private:
static ProfileType sProfileType;
static bool sDisableProfileBars;
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index cfdd0d211dac..b243f990d27d 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -33,68 +33,96 @@ class SkPaint;
namespace android {
namespace uirenderer {
+struct ClipBase;
class OffscreenBuffer;
class RenderNode;
struct Vertex;
/**
- * On of the provided macros is executed for each op type in order. The first will be used for ops
- * that cannot merge, and the second for those that can.
+ * Authoritative op list, used for generating the op ID enum, ID based LUTS, and
+ * the functions to which they dispatch. Parameter macros are executed for each op,
+ * in order, based on the op's type.
*
- * This serves as the authoritative list of ops, used for generating ID enum, and ID based LUTs.
+ * There are 4 types of op:
+ *
+ * Pre render - not directly consumed by renderer, reorder stage resolves this into renderable type
+ * Render only - generated renderable ops - never passed to a reorderer
+ * Unmergeable - reorderable, renderable (but not mergeable)
+ * Mergeable - reorderable, renderable (and mergeable)
*/
-#define MAP_OPS_BASED_ON_MERGEABILITY(U_OP_FN, M_OP_FN) \
- U_OP_FN(ArcOp) \
- M_OP_FN(BitmapOp) \
- U_OP_FN(BitmapMeshOp) \
- U_OP_FN(BitmapRectOp) \
- U_OP_FN(CirclePropsOp) \
- U_OP_FN(FunctorOp) \
- U_OP_FN(LinesOp) \
- U_OP_FN(OvalOp) \
- M_OP_FN(PatchOp) \
- U_OP_FN(PathOp) \
- U_OP_FN(PointsOp) \
- U_OP_FN(RectOp) \
- U_OP_FN(RenderNodeOp) \
- U_OP_FN(RoundRectOp) \
- U_OP_FN(RoundRectPropsOp) \
- U_OP_FN(ShadowOp) \
- U_OP_FN(SimpleRectsOp) \
- M_OP_FN(TextOp) \
- U_OP_FN(TextOnPathOp) \
- U_OP_FN(TextureLayerOp) \
- U_OP_FN(BeginLayerOp) \
- U_OP_FN(EndLayerOp) \
- U_OP_FN(LayerOp)
+#define MAP_OPS_BASED_ON_TYPE(PRE_RENDER_OP_FN, RENDER_ONLY_OP_FN, UNMERGEABLE_OP_FN, MERGEABLE_OP_FN) \
+ PRE_RENDER_OP_FN(RenderNodeOp) \
+ PRE_RENDER_OP_FN(CirclePropsOp) \
+ PRE_RENDER_OP_FN(RoundRectPropsOp) \
+ PRE_RENDER_OP_FN(BeginLayerOp) \
+ PRE_RENDER_OP_FN(EndLayerOp) \
+ \
+ RENDER_ONLY_OP_FN(ShadowOp) \
+ RENDER_ONLY_OP_FN(LayerOp) \
+ \
+ UNMERGEABLE_OP_FN(ArcOp) \
+ UNMERGEABLE_OP_FN(BitmapMeshOp) \
+ UNMERGEABLE_OP_FN(BitmapRectOp) \
+ UNMERGEABLE_OP_FN(FunctorOp) \
+ UNMERGEABLE_OP_FN(LinesOp) \
+ UNMERGEABLE_OP_FN(OvalOp) \
+ UNMERGEABLE_OP_FN(PathOp) \
+ UNMERGEABLE_OP_FN(PointsOp) \
+ UNMERGEABLE_OP_FN(RectOp) \
+ UNMERGEABLE_OP_FN(RoundRectOp) \
+ UNMERGEABLE_OP_FN(SimpleRectsOp) \
+ UNMERGEABLE_OP_FN(TextOnPathOp) \
+ UNMERGEABLE_OP_FN(TextureLayerOp) \
+ \
+ MERGEABLE_OP_FN(BitmapOp) \
+ MERGEABLE_OP_FN(PatchOp) \
+ MERGEABLE_OP_FN(TextOp)
/**
- * The provided macro is executed for each op type in order. This is used in cases where
- * merge-ability of ops doesn't matter.
+ * LUT generators, which will insert nullptr for unsupported ops
*/
-#define MAP_OPS(OP_FN) \
- MAP_OPS_BASED_ON_MERGEABILITY(OP_FN, OP_FN)
+#define NULLPTR_OP_FN(Type) nullptr,
+
+#define BUILD_DEFERRABLE_OP_LUT(OP_FN) \
+ { MAP_OPS_BASED_ON_TYPE(OP_FN, NULLPTR_OP_FN, OP_FN, OP_FN) }
+
+#define BUILD_MERGEABLE_OP_LUT(OP_FN) \
+ { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, NULLPTR_OP_FN, NULLPTR_OP_FN, OP_FN) }
+
+#define BUILD_RENDERABLE_OP_LUT(OP_FN) \
+ { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
+/**
+ * Op mapping functions, which skip unsupported ops.
+ *
+ * Note: Do not use for LUTS, since these do not preserve ID order.
+ */
#define NULL_OP_FN(Type)
-#define MAP_MERGED_OPS(OP_FN) \
- MAP_OPS_BASED_ON_MERGEABILITY(NULL_OP_FN, OP_FN)
+#define MAP_MERGEABLE_OPS(OP_FN) \
+ MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, NULL_OP_FN, NULL_OP_FN, OP_FN)
+
+#define MAP_RENDERABLE_OPS(OP_FN) \
+ MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, OP_FN, OP_FN, OP_FN)
+
+#define MAP_DEFERRABLE_OPS(OP_FN) \
+ MAP_OPS_BASED_ON_TYPE(OP_FN, NULL_OP_FN, OP_FN, OP_FN)
// Generate OpId enum
#define IDENTITY_FN(Type) Type,
namespace RecordedOpId {
enum {
- MAP_OPS(IDENTITY_FN)
+ MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN)
Count,
};
}
-static_assert(RecordedOpId::ArcOp == 0,
+static_assert(RecordedOpId::RenderNodeOp == 0,
"First index must be zero for LUTs to work");
-#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint
-#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect
-#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, paint)
-#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, nullptr)
+#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint
+#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip
+#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, paint)
+#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr)
struct RecordedOp {
/* ID from RecordedOpId - generally used for jumping into function tables */
@@ -106,8 +134,8 @@ struct RecordedOp {
/* transform in recording space (vs DisplayList origin) */
const Matrix4 localMatrix;
- /* clip in recording space */
- const Rect localClipRect;
+ /* clip in recording space - nullptr if not clipped */
+ const ClipBase* localClip;
/* optional paint, stored in base object to simplify merging logic */
const SkPaint* paint;
@@ -116,7 +144,7 @@ protected:
: opId(opId)
, unmappedBounds(unmappedBounds)
, localMatrix(localMatrix)
- , localClipRect(localClipRect)
+ , localClip(localClip)
, paint(paint) {}
};
@@ -187,9 +215,9 @@ struct BitmapRectOp : RecordedOp {
};
struct CirclePropsOp : RecordedOp {
- CirclePropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint,
+ CirclePropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
float* x, float* y, float* radius)
- : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClipRect, paint)
+ : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClip, paint)
, x(x)
, y(y)
, radius(radius) {}
@@ -259,9 +287,9 @@ struct RoundRectOp : RecordedOp {
};
struct RoundRectPropsOp : RecordedOp {
- RoundRectPropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint,
+ RoundRectPropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
float* left, float* top, float* right, float* bottom, float *rx, float *ry)
- : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClipRect, paint)
+ : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClip, paint)
, left(left)
, top(top)
, right(right)
@@ -286,12 +314,13 @@ struct RoundRectPropsOp : RecordedOp {
*/
struct ShadowOp : RecordedOp {
ShadowOp(const RenderNodeOp& casterOp, float casterAlpha, const SkPath* casterPath,
- const Rect& clipRect, const Vector3& lightCenter)
- : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), clipRect, nullptr)
+ const Rect& localClipRect, const Vector3& lightCenter)
+ : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr)
, shadowMatrixXY(casterOp.localMatrix)
, shadowMatrixZ(casterOp.localMatrix)
, casterAlpha(casterAlpha)
, casterPath(casterPath)
+ , localClipRect(localClipRect)
, lightCenter(lightCenter) {
const RenderNode& node = *casterOp.renderNode;
node.applyViewPropertyTransforms(shadowMatrixXY, false);
@@ -301,6 +330,7 @@ struct ShadowOp : RecordedOp {
Matrix4 shadowMatrixZ;
const float casterAlpha;
const SkPath* casterPath;
+ const Rect localClipRect;
const Vector3 lightCenter;
};
@@ -374,7 +404,7 @@ struct BeginLayerOp : RecordedOp {
*/
struct EndLayerOp : RecordedOp {
EndLayerOp()
- : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), Rect(), nullptr) {}
+ : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {}
};
/**
@@ -388,13 +418,13 @@ struct LayerOp : RecordedOp {
LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
: SUPER_PAINTLESS(LayerOp)
, layerHandle(layerHandle)
- , alpha(paint->getAlpha() / 255.0f)
+ , alpha(paint ? paint->getAlpha() / 255.0f : 1.0f)
, mode(PaintUtils::getXfermodeDirect(paint))
- , colorFilter(paint->getColorFilter())
+ , colorFilter(paint ? paint->getColorFilter() : nullptr)
, destroy(true) {}
LayerOp(RenderNode& node)
- : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), Rect(node.getWidth(), node.getHeight()), nullptr)
+ : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), nullptr, nullptr)
, layerHandle(node.getLayerHandle())
, alpha(node.properties().layerProperties().alpha() / 255.0f)
, mode(node.properties().layerProperties().xferMode())
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index f75d8d4f6479..f7f6caff22b6 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -39,7 +39,7 @@ void RecordingCanvas::reset(int width, int height) {
"prepareDirty called a second time during a recording!");
mDisplayList = new DisplayList();
- mState.initializeSaveStack(width, height, 0, 0, width, height, Vector3());
+ mState.initializeRecordingSaveStack(width, height);
mDeferredBarrierType = DeferredBarrierType::InOrder;
mState.setDirtyClip(false);
@@ -155,6 +155,8 @@ int RecordingCanvas::saveLayer(float left, float top, float right, float bottom,
return saveValue;
}
+ auto previousClip = getRecordedClip(); // note: done while snapshot == previous
+
snapshot.flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
snapshot.initializeViewport(untransformedBounds.getWidth(), untransformedBounds.getHeight());
snapshot.transform->loadTranslate(-untransformedBounds.left, -untransformedBounds.top, 0.0f);
@@ -167,7 +169,7 @@ int RecordingCanvas::saveLayer(float left, float top, float right, float bottom,
addOp(new (alloc()) BeginLayerOp(
Rect(left, top, right, bottom),
*previous.transform, // transform to *draw* with
- previous.getRenderTargetClip(), // clip to *draw* with
+ previousClip, // clip to *draw* with
refPaint(paint)));
return saveValue;
@@ -229,11 +231,10 @@ void RecordingCanvas::drawColor(int color, SkXfermode::Mode mode) {
}
void RecordingCanvas::drawPaint(const SkPaint& paint) {
- // TODO: more efficient recording?
addOp(new (alloc()) RectOp(
- mState.getRenderTargetClipBounds(),
+ mState.getRenderTargetClipBounds(), // OK, since we've not passed transform
Matrix4::identity(),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint)));
}
@@ -253,7 +254,7 @@ void RecordingCanvas::drawPoints(const float* points, int floatCount, const SkPa
addOp(new (alloc()) PointsOp(
calcBoundsOfPoints(points, floatCount),
*mState.currentSnapshot()->transform,
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
}
@@ -264,7 +265,7 @@ void RecordingCanvas::drawLines(const float* points, int floatCount, const SkPai
addOp(new (alloc()) LinesOp(
calcBoundsOfPoints(points, floatCount),
*mState.currentSnapshot()->transform,
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
}
@@ -272,7 +273,7 @@ void RecordingCanvas::drawRect(float left, float top, float right, float bottom,
addOp(new (alloc()) RectOp(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint)));
}
@@ -305,7 +306,7 @@ void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const
addOp(new (alloc()) SimpleRectsOp(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(paint), rectData, vertexCount));
}
@@ -339,7 +340,7 @@ void RecordingCanvas::drawRoundRect(float left, float top, float right, float bo
addOp(new (alloc()) RoundRectOp(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint), rx, ry));
}
@@ -358,7 +359,7 @@ void RecordingCanvas::drawRoundRect(
refBitmapsInShader(paint->value.getShader());
addOp(new (alloc()) RoundRectPropsOp(
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
&paint->value,
&left->value, &top->value, &right->value, &bottom->value,
&rx->value, &ry->value));
@@ -380,7 +381,7 @@ void RecordingCanvas::drawCircle(
refBitmapsInShader(paint->value.getShader());
addOp(new (alloc()) CirclePropsOp(
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
&paint->value,
&x->value, &y->value, &radius->value));
}
@@ -390,7 +391,7 @@ void RecordingCanvas::drawOval(float left, float top, float right, float bottom,
addOp(new (alloc()) OvalOp(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint)));
}
@@ -399,7 +400,7 @@ void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
addOp(new (alloc()) ArcOp(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint),
startAngle, sweepAngle, useCenter));
}
@@ -408,7 +409,7 @@ void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
addOp(new (alloc()) PathOp(
Rect(path.getBounds()),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint), refPath(&path)));
}
@@ -459,7 +460,7 @@ void RecordingCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float sr
addOp(new (alloc()) BitmapRectOp(
Rect(dstLeft, dstTop, dstRight, dstBottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(paint), refBitmap(bitmap),
Rect(srcLeft, srcTop, srcRight, srcBottom)));
}
@@ -471,7 +472,7 @@ void RecordingCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int
addOp(new (alloc()) BitmapMeshOp(
calcBoundsOfPoints(vertices, vertexCount * 2),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight,
refBuffer<float>(vertices, vertexCount * 2), // 2 floats per vertex
refBuffer<int>(colors, vertexCount))); // 1 color per vertex
@@ -483,7 +484,7 @@ void RecordingCanvas::drawNinePatch(const SkBitmap& bitmap, const android::Res_p
addOp(new (alloc()) PatchOp(
Rect(dstLeft, dstTop, dstRight, dstBottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
}
@@ -499,7 +500,7 @@ void RecordingCanvas::drawText(const uint16_t* glyphs, const float* positions, i
addOp(new (alloc()) TextOp(
Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint), glyphs, positions, glyphCount, x, y));
drawTextDecorations(x, y, totalAdvance, paint);
}
@@ -509,9 +510,9 @@ void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int glyphCount, con
if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
addOp(new (alloc()) TextOnPathOp(
- mState.getRenderTargetClipBounds(), // TODO: explicitly define bounds
+ mState.getLocalClipBounds(), // TODO: explicitly define bounds
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint), glyphs, glyphCount, refPath(&path), hOffset, vOffset));
}
@@ -519,7 +520,7 @@ void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
addOp(new (alloc()) BitmapOp(
Rect(bitmap->width(), bitmap->height()),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(paint), refBitmap(*bitmap)));
}
@@ -528,7 +529,7 @@ void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
RenderNodeOp* op = new (alloc()) RenderNodeOp(
Rect(stagingProps.getWidth(), stagingProps.getHeight()),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
renderNode);
int opIndex = addOp(op);
int childIndex = mDisplayList->addChild(op);
@@ -554,16 +555,16 @@ void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
addOp(new (alloc()) TextureLayerOp(
Rect(layer->getWidth(), layer->getHeight()),
totalTransform,
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
layer));
}
void RecordingCanvas::callDrawGLFunction(Functor* functor) {
mDisplayList->functors.push_back(functor);
addOp(new (alloc()) FunctorOp(
- mState.getRenderTargetClipBounds(), // TODO: explicitly define bounds
+ mState.getLocalClipBounds(), // TODO: explicitly define bounds
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
functor));
}
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 470f9ecb5024..1a2ac97f5364 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -36,6 +36,7 @@
namespace android {
namespace uirenderer {
+struct ClipBase;
class DeferredLayerUpdater;
struct RecordedOp;
@@ -199,6 +200,9 @@ public:
virtual bool drawTextAbsolutePos() const override { return false; }
private:
+ const ClipBase* getRecordedClip() {
+ return mState.writableSnapshot()->mutateClipArea().serializeClip(alloc());
+ }
void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
void drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint);
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 194aa5735a7e..5fac3a1497c0 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -167,6 +167,7 @@ public:
const SkRegion& getClipRegion() const { return mClipArea->getClipRegion(); }
bool clipIsSimple() const { return mClipArea->isSimple(); }
const ClipArea& getClipArea() const { return *mClipArea; }
+ ClipArea& mutateClipArea() { return *mClipArea; }
/**
* Resets the clip to the specified rect.
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
new file mode 100644
index 000000000000..56cb10476118
--- /dev/null
+++ b/libs/hwui/VectorDrawable.cpp
@@ -0,0 +1,492 @@
+/*
+ * 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 "VectorDrawable.h"
+
+#include "PathParser.h"
+#include "SkImageInfo.h"
+#include <utils/Log.h>
+#include "utils/Macros.h"
+#include "utils/VectorDrawableUtils.h"
+
+#include <math.h>
+#include <string.h>
+
+namespace android {
+namespace uirenderer {
+namespace VectorDrawable {
+
+const int Tree::MAX_CACHED_BITMAP_SIZE = 2048;
+
+void Path::draw(Canvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY) {
+ float matrixScale = getMatrixScale(groupStackedMatrix);
+ if (matrixScale == 0) {
+ // When either x or y is scaled to 0, we don't need to draw anything.
+ return;
+ }
+
+ const SkPath updatedPath = getUpdatedPath();
+ SkMatrix pathMatrix(groupStackedMatrix);
+ pathMatrix.postScale(scaleX, scaleY);
+
+ //TODO: try apply the path matrix to the canvas instead of creating a new path.
+ SkPath renderPath;
+ renderPath.reset();
+ renderPath.addPath(updatedPath, pathMatrix);
+
+ float minScale = fmin(scaleX, scaleY);
+ float strokeScale = minScale * matrixScale;
+ drawPath(outCanvas, renderPath, strokeScale);
+}
+
+void Path::setPathData(const Data& data) {
+ if (mData == data) {
+ return;
+ }
+ // Updates the path data. Note that we don't generate a new Skia path right away
+ // because there are cases where the animation is changing the path data, but the view
+ // that hosts the VD has gone off screen, in which case we won't even draw. So we
+ // postpone the Skia path generation to the draw time.
+ mData = data;
+ mSkPathDirty = true;
+}
+
+void Path::dump() {
+ ALOGD("Path: %s has %zu points", mName.c_str(), mData.points.size());
+}
+
+float Path::getMatrixScale(const SkMatrix& groupStackedMatrix) {
+ // Given unit vectors A = (0, 1) and B = (1, 0).
+ // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
+ // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
+ // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
+ // If max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
+ //
+ // For non-skew case, which is most of the cases, matrix scale is computing exactly the
+ // scale on x and y axis, and take the minimal of these two.
+ // For skew case, an unit square will mapped to a parallelogram. And this function will
+ // return the minimal height of the 2 bases.
+ SkVector skVectors[2];
+ skVectors[0].set(0, 1);
+ skVectors[1].set(1, 0);
+ groupStackedMatrix.mapVectors(skVectors, 2);
+ float scaleX = hypotf(skVectors[0].fX, skVectors[0].fY);
+ float scaleY = hypotf(skVectors[1].fX, skVectors[1].fY);
+ float crossProduct = skVectors[0].cross(skVectors[1]);
+ float maxScale = fmax(scaleX, scaleY);
+
+ float matrixScale = 0;
+ if (maxScale > 0) {
+ matrixScale = fabs(crossProduct) / maxScale;
+ }
+ return matrixScale;
+}
+Path::Path(const char* pathStr, size_t strLength) {
+ PathParser::ParseResult result;
+ PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
+ if (!result.failureOccurred) {
+ VectorDrawableUtils::verbsToPath(&mSkPath, mData);
+ }
+}
+
+Path::Path(const Data& data) {
+ mData = data;
+ // Now we need to construct a path
+ VectorDrawableUtils::verbsToPath(&mSkPath, data);
+}
+
+Path::Path(const Path& path) : Node(path) {
+ mData = path.mData;
+ VectorDrawableUtils::verbsToPath(&mSkPath, mData);
+}
+
+bool Path::canMorph(const Data& morphTo) {
+ return VectorDrawableUtils::canMorph(mData, morphTo);
+}
+
+bool Path::canMorph(const Path& path) {
+ return canMorph(path.mData);
+}
+
+const SkPath& Path::getUpdatedPath() {
+ if (mSkPathDirty) {
+ mSkPath.reset();
+ VectorDrawableUtils::verbsToPath(&mSkPath, mData);
+ mSkPathDirty = false;
+ }
+ return mSkPath;
+}
+
+void Path::setPath(const char* pathStr, size_t strLength) {
+ PathParser::ParseResult result;
+ mSkPathDirty = true;
+ PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
+}
+
+FullPath::FullPath(const FullPath& path) : Path(path) {
+ mStrokeWidth = path.mStrokeWidth;
+ mStrokeColor = path.mStrokeColor;
+ mStrokeAlpha = path.mStrokeAlpha;
+ mFillColor = path.mFillColor;
+ mFillAlpha = path.mFillAlpha;
+ mTrimPathStart = path.mTrimPathStart;
+ mTrimPathEnd = path.mTrimPathEnd;
+ mTrimPathOffset = path.mTrimPathOffset;
+ mStrokeMiterLimit = path.mStrokeMiterLimit;
+ mStrokeLineCap = path.mStrokeLineCap;
+ mStrokeLineJoin = path.mStrokeLineJoin;
+}
+
+const SkPath& FullPath::getUpdatedPath() {
+ if (!mSkPathDirty && !mTrimDirty) {
+ return mTrimmedSkPath;
+ }
+ Path::getUpdatedPath();
+ if (mTrimPathStart != 0.0f || mTrimPathEnd != 1.0f) {
+ applyTrim();
+ return mTrimmedSkPath;
+ } else {
+ return mSkPath;
+ }
+}
+
+void FullPath::updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
+ SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
+ float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin) {
+ mStrokeWidth = strokeWidth;
+ mStrokeColor = strokeColor;
+ mStrokeAlpha = strokeAlpha;
+ mFillColor = fillColor;
+ mFillAlpha = fillAlpha;
+ mStrokeMiterLimit = strokeMiterLimit;
+ mStrokeLineCap = SkPaint::Cap(strokeLineCap);
+ mStrokeLineJoin = SkPaint::Join(strokeLineJoin);
+
+ // If any trim property changes, mark trim dirty and update the trim path
+ setTrimPathStart(trimPathStart);
+ setTrimPathEnd(trimPathEnd);
+ setTrimPathOffset(trimPathOffset);
+}
+
+inline SkColor applyAlpha(SkColor color, float alpha) {
+ int alphaBytes = SkColorGetA(color);
+ return SkColorSetA(color, alphaBytes * alpha);
+}
+
+void FullPath::drawPath(Canvas* outCanvas, const SkPath& renderPath, float strokeScale){
+ // Draw path's fill, if fill color isn't transparent.
+ if (mFillColor != SK_ColorTRANSPARENT) {
+ mPaint.setStyle(SkPaint::Style::kFill_Style);
+ mPaint.setAntiAlias(true);
+ mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
+ outCanvas->drawPath(renderPath, mPaint);
+ }
+ // Draw path's stroke, if stroke color isn't transparent
+ if (mStrokeColor != SK_ColorTRANSPARENT) {
+ mPaint.setStyle(SkPaint::Style::kStroke_Style);
+ mPaint.setAntiAlias(true);
+ mPaint.setStrokeJoin(mStrokeLineJoin);
+ mPaint.setStrokeCap(mStrokeLineCap);
+ mPaint.setStrokeMiter(mStrokeMiterLimit);
+ mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
+ mPaint.setStrokeWidth(mStrokeWidth * strokeScale);
+ outCanvas->drawPath(renderPath, mPaint);
+ }
+}
+
+/**
+ * Applies trimming to the specified path.
+ */
+void FullPath::applyTrim() {
+ if (mTrimPathStart == 0.0f && mTrimPathEnd == 1.0f) {
+ // No trimming necessary.
+ return;
+ }
+ SkPathMeasure measure(mSkPath, false);
+ float len = SkScalarToFloat(measure.getLength());
+ float start = len * fmod((mTrimPathStart + mTrimPathOffset), 1.0f);
+ float end = len * fmod((mTrimPathEnd + mTrimPathOffset), 1.0f);
+
+ mTrimmedSkPath.reset();
+ if (start > end) {
+ measure.getSegment(start, len, &mTrimmedSkPath, true);
+ measure.getSegment(0, end, &mTrimmedSkPath, true);
+ } else {
+ measure.getSegment(start, end, &mTrimmedSkPath, true);
+ }
+ mTrimDirty = false;
+}
+
+inline int putData(int8_t* outBytes, int startIndex, float value) {
+ int size = sizeof(float);
+ memcpy(&outBytes[startIndex], &value, size);
+ return size;
+}
+
+inline int putData(int8_t* outBytes, int startIndex, int value) {
+ int size = sizeof(int);
+ memcpy(&outBytes[startIndex], &value, size);
+ return size;
+}
+
+struct FullPathProperties {
+ // TODO: Consider storing full path properties in this struct instead of the fields.
+ float strokeWidth;
+ SkColor strokeColor;
+ float strokeAlpha;
+ SkColor fillColor;
+ float fillAlpha;
+ float trimPathStart;
+ float trimPathEnd;
+ float trimPathOffset;
+ int32_t strokeLineCap;
+ int32_t strokeLineJoin;
+ float strokeMiterLimit;
+};
+
+REQUIRE_COMPATIBLE_LAYOUT(FullPathProperties);
+
+static_assert(sizeof(float) == sizeof(int32_t), "float is not the same size as int32_t");
+static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor is not the same size as int32_t");
+
+bool FullPath::getProperties(int8_t* outProperties, int length) {
+ int propertyDataSize = sizeof(FullPathProperties);
+ if (length != propertyDataSize) {
+ LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
+ propertyDataSize, length);
+ return false;
+ }
+ // TODO: consider replacing the property fields with a FullPathProperties struct.
+ FullPathProperties properties;
+ properties.strokeWidth = mStrokeWidth;
+ properties.strokeColor = mStrokeColor;
+ properties.strokeAlpha = mStrokeAlpha;
+ properties.fillColor = mFillColor;
+ properties.fillAlpha = mFillAlpha;
+ properties.trimPathStart = mTrimPathStart;
+ properties.trimPathEnd = mTrimPathEnd;
+ properties.trimPathOffset = mTrimPathOffset;
+ properties.strokeLineCap = mStrokeLineCap;
+ properties.strokeLineJoin = mStrokeLineJoin;
+ properties.strokeMiterLimit = mStrokeMiterLimit;
+
+ memcpy(outProperties, &properties, length);
+ return true;
+}
+
+void ClipPath::drawPath(Canvas* outCanvas, const SkPath& renderPath,
+ float strokeScale){
+ outCanvas->clipPath(&renderPath, SkRegion::kIntersect_Op);
+}
+
+Group::Group(const Group& group) : Node(group) {
+ mRotate = group.mRotate;
+ mPivotX = group.mPivotX;
+ mPivotY = group.mPivotY;
+ mScaleX = group.mScaleX;
+ mScaleY = group.mScaleY;
+ mTranslateX = group.mTranslateX;
+ mTranslateY = group.mTranslateY;
+}
+
+void Group::draw(Canvas* outCanvas, const SkMatrix& currentMatrix, float scaleX,
+ float scaleY) {
+ // TODO: Try apply the matrix to the canvas instead of passing it down the tree
+
+ // Calculate current group's matrix by preConcat the parent's and
+ // and the current one on the top of the stack.
+ // Basically the Mfinal = Mviewport * M0 * M1 * M2;
+ // Mi the local matrix at level i of the group tree.
+ SkMatrix stackedMatrix;
+ getLocalMatrix(&stackedMatrix);
+ stackedMatrix.postConcat(currentMatrix);
+
+ // Save the current clip information, which is local to this group.
+ outCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
+ // Draw the group tree in the same order as the XML file.
+ for (Node* child : mChildren) {
+ child->draw(outCanvas, stackedMatrix, scaleX, scaleY);
+ }
+ // Restore the previous clip information.
+ outCanvas->restore();
+}
+
+void Group::dump() {
+ ALOGD("Group %s has %zu children: ", mName.c_str(), mChildren.size());
+ for (size_t i = 0; i < mChildren.size(); i++) {
+ mChildren[i]->dump();
+ }
+}
+
+void Group::updateLocalMatrix(float rotate, float pivotX, float pivotY,
+ float scaleX, float scaleY, float translateX, float translateY) {
+ setRotation(rotate);
+ setPivotX(pivotX);
+ setPivotY(pivotY);
+ setScaleX(scaleX);
+ setScaleY(scaleY);
+ setTranslateX(translateX);
+ setTranslateY(translateY);
+}
+
+void Group::getLocalMatrix(SkMatrix* outMatrix) {
+ outMatrix->reset();
+ // TODO: use rotate(mRotate, mPivotX, mPivotY) and scale with pivot point, instead of
+ // translating to pivot for rotating and scaling, then translating back.
+ outMatrix->postTranslate(-mPivotX, -mPivotY);
+ outMatrix->postScale(mScaleX, mScaleY);
+ outMatrix->postRotate(mRotate, 0, 0);
+ outMatrix->postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
+}
+
+void Group::addChild(Node* child) {
+ mChildren.push_back(child);
+}
+
+bool Group::getProperties(float* outProperties, int length) {
+ int propertyCount = static_cast<int>(Property::Count);
+ if (length != propertyCount) {
+ LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
+ propertyCount, length);
+ return false;
+ }
+ for (int i = 0; i < propertyCount; i++) {
+ Property currentProperty = static_cast<Property>(i);
+ switch (currentProperty) {
+ case Property::Rotate_Property:
+ outProperties[i] = mRotate;
+ break;
+ case Property::PivotX_Property:
+ outProperties[i] = mPivotX;
+ break;
+ case Property::PivotY_Property:
+ outProperties[i] = mPivotY;
+ break;
+ case Property::ScaleX_Property:
+ outProperties[i] = mScaleX;
+ break;
+ case Property::ScaleY_Property:
+ outProperties[i] = mScaleY;
+ break;
+ case Property::TranslateX_Property:
+ outProperties[i] = mTranslateX;
+ break;
+ case Property::TranslateY_Property:
+ outProperties[i] = mTranslateY;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Invalid input index: %d", i);
+ return false;
+ }
+ }
+ return true;
+}
+
+void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
+ const SkRect& bounds, bool needsMirroring, bool canReuseCache) {
+ // The imageView can scale the canvas in different ways, in order to
+ // avoid blurry scaling, we have to draw into a bitmap with exact pixel
+ // size first. This bitmap size is determined by the bounds and the
+ // canvas scale.
+ outCanvas->getMatrix(&mCanvasMatrix);
+ mBounds = bounds;
+ float canvasScaleX = 1.0f;
+ float canvasScaleY = 1.0f;
+ if (mCanvasMatrix.getSkewX() == 0 && mCanvasMatrix.getSkewY() == 0) {
+ // Only use the scale value when there's no skew or rotation in the canvas matrix.
+ canvasScaleX = mCanvasMatrix.getScaleX();
+ canvasScaleY = mCanvasMatrix.getScaleY();
+ }
+ int scaledWidth = (int) (mBounds.width() * canvasScaleX);
+ int scaledHeight = (int) (mBounds.height() * canvasScaleY);
+ scaledWidth = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledWidth);
+ scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
+
+ if (scaledWidth <= 0 || scaledHeight <= 0) {
+ return;
+ }
+
+ int saveCount = outCanvas->save(SkCanvas::SaveFlags::kMatrixClip_SaveFlag);
+ outCanvas->translate(mBounds.fLeft, mBounds.fTop);
+
+ // Handle RTL mirroring.
+ if (needsMirroring) {
+ outCanvas->translate(mBounds.width(), 0);
+ outCanvas->scale(-1.0f, 1.0f);
+ }
+
+ // At this point, canvas has been translated to the right position.
+ // And we use this bound for the destination rect for the drawBitmap, so
+ // we offset to (0, 0);
+ mBounds.offsetTo(0, 0);
+
+ createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
+ if (!mAllowCaching) {
+ updateCachedBitmap(scaledWidth, scaledHeight);
+ } else {
+ if (!canReuseCache || mCacheDirty) {
+ updateCachedBitmap(scaledWidth, scaledHeight);
+ }
+ }
+ drawCachedBitmapWithRootAlpha(outCanvas, colorFilter, mBounds);
+
+ outCanvas->restoreToCount(saveCount);
+}
+
+void Tree::drawCachedBitmapWithRootAlpha(Canvas* outCanvas, SkColorFilter* filter,
+ const SkRect& originalBounds) {
+ SkPaint* paint;
+ if (mRootAlpha == 1.0f && filter == NULL) {
+ paint = NULL;
+ } else {
+ mPaint.setFilterQuality(kLow_SkFilterQuality);
+ mPaint.setAlpha(mRootAlpha * 255);
+ mPaint.setColorFilter(filter);
+ paint = &mPaint;
+ }
+ outCanvas->drawBitmap(mCachedBitmap, 0, 0, mCachedBitmap.width(), mCachedBitmap.height(),
+ originalBounds.fLeft, originalBounds.fTop, originalBounds.fRight,
+ originalBounds.fBottom, paint);
+}
+
+void Tree::updateCachedBitmap(int width, int height) {
+ mCachedBitmap.eraseColor(SK_ColorTRANSPARENT);
+ Canvas* outCanvas = Canvas::create_canvas(mCachedBitmap);
+ float scaleX = width / mViewportWidth;
+ float scaleY = height / mViewportHeight;
+ mRootNode->draw(outCanvas, SkMatrix::I(), scaleX, scaleY);
+ mCacheDirty = false;
+}
+
+void Tree::createCachedBitmapIfNeeded(int width, int height) {
+ if (!canReuseBitmap(width, height)) {
+ SkImageInfo info = SkImageInfo::Make(width, height,
+ kN32_SkColorType, kPremul_SkAlphaType);
+ mCachedBitmap.setInfo(info);
+ // TODO: Count the bitmap cache against app's java heap
+ mCachedBitmap.allocPixels(info);
+ mCacheDirty = true;
+ }
+}
+
+bool Tree::canReuseBitmap(int width, int height) {
+ return width == mCachedBitmap.width() && height == mCachedBitmap.height();
+}
+
+}; // namespace VectorDrawable
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
new file mode 100644
index 000000000000..6c84b052faf4
--- /dev/null
+++ b/libs/hwui/VectorDrawable.h
@@ -0,0 +1,330 @@
+/*
+ * 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 ANDROID_HWUI_VPATH_H
+#define ANDROID_HWUI_VPATH_H
+
+#include "Canvas.h"
+#include <SkBitmap.h>
+#include <SkColor.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
+#include <SkPath.h>
+#include <SkPathMeasure.h>
+#include <SkRect.h>
+
+#include <cutils/compiler.h>
+#include <stddef.h>
+#include <vector>
+#include <string>
+
+namespace android {
+namespace uirenderer {
+
+namespace VectorDrawable {
+#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP(field, value) ? (flag = true, true): false);
+#define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
+
+/* A VectorDrawable is composed of a tree of nodes.
+ * Each node can be a group node, or a path.
+ * A group node can have groups or paths as children, but a path node has
+ * no children.
+ * One example can be:
+ * Root Group
+ * / | \
+ * Group Path Group
+ * / \ |
+ * Path Path Path
+ *
+ */
+class ANDROID_API Node {
+public:
+ Node(const Node& node) {
+ mName = node.mName;
+ }
+ Node() {}
+ virtual void draw(Canvas* outCanvas, const SkMatrix& currentMatrix,
+ float scaleX, float scaleY) = 0;
+ virtual void dump() = 0;
+ void setName(const char* name) {
+ mName = name;
+ }
+ virtual ~Node(){}
+protected:
+ std::string mName;
+};
+
+class ANDROID_API Path : public Node {
+public:
+ struct ANDROID_API Data {
+ std::vector<char> verbs;
+ std::vector<size_t> verbSizes;
+ std::vector<float> points;
+ bool operator==(const Data& data) const {
+ return verbs == data.verbs && verbSizes == data.verbSizes
+ && points == data.points;
+ }
+ };
+ Path(const Data& nodes);
+ Path(const Path& path);
+ Path(const char* path, size_t strLength);
+ Path() {}
+ void dump() override;
+ bool canMorph(const Data& path);
+ bool canMorph(const Path& path);
+ void draw(Canvas* outCanvas, const SkMatrix& groupStackedMatrix,
+ float scaleX, float scaleY) override;
+ void setPath(const char* path, size_t strLength);
+ void setPathData(const Data& data);
+ static float getMatrixScale(const SkMatrix& groupStackedMatrix);
+
+protected:
+ virtual const SkPath& getUpdatedPath();
+ virtual void drawPath(Canvas *outCanvas, const SkPath& renderPath,
+ float strokeScale) = 0;
+ Data mData;
+ SkPath mSkPath;
+ bool mSkPathDirty = true;
+};
+
+class ANDROID_API FullPath: public Path {
+public:
+ FullPath(const FullPath& path); // for cloning
+ FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
+ FullPath() : Path() {}
+ FullPath(const Data& nodes) : Path(nodes) {}
+
+ void updateProperties(float strokeWidth, SkColor strokeColor,
+ float strokeAlpha, SkColor fillColor, float fillAlpha,
+ float trimPathStart, float trimPathEnd, float trimPathOffset,
+ float strokeMiterLimit, int strokeLineCap, int strokeLineJoin);
+ float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+ void setStrokeWidth(float strokeWidth) {
+ mStrokeWidth = strokeWidth;
+ }
+ SkColor getStrokeColor() {
+ return mStrokeColor;
+ }
+ void setStrokeColor(SkColor strokeColor) {
+ mStrokeColor = strokeColor;
+ }
+ float getStrokeAlpha() {
+ return mStrokeAlpha;
+ }
+ void setStrokeAlpha(float strokeAlpha) {
+ mStrokeAlpha = strokeAlpha;
+ }
+ SkColor getFillColor() {
+ return mFillColor;
+ }
+ void setFillColor(SkColor fillColor) {
+ mFillColor = fillColor;
+ }
+ float getFillAlpha() {
+ return mFillAlpha;
+ }
+ void setFillAlpha(float fillAlpha) {
+ mFillAlpha = fillAlpha;
+ }
+ float getTrimPathStart() {
+ return mTrimPathStart;
+ }
+ void setTrimPathStart(float trimPathStart) {
+ VD_SET_PROP_WITH_FLAG(mTrimPathStart, trimPathStart, mTrimDirty);
+ }
+ float getTrimPathEnd() {
+ return mTrimPathEnd;
+ }
+ void setTrimPathEnd(float trimPathEnd) {
+ VD_SET_PROP_WITH_FLAG(mTrimPathEnd, trimPathEnd, mTrimDirty);
+ }
+ float getTrimPathOffset() {
+ return mTrimPathOffset;
+ }
+ void setTrimPathOffset(float trimPathOffset) {
+ VD_SET_PROP_WITH_FLAG(mTrimPathOffset, trimPathOffset, mTrimDirty);
+ }
+ bool getProperties(int8_t* outProperties, int length);
+
+protected:
+ const SkPath& getUpdatedPath() override;
+ void drawPath(Canvas* outCanvas, const SkPath& renderPath,
+ float strokeScale) override;
+
+private:
+ // Applies trimming to the specified path.
+ void applyTrim();
+ float mStrokeWidth = 0;
+ SkColor mStrokeColor = SK_ColorTRANSPARENT;
+ float mStrokeAlpha = 1;
+ SkColor mFillColor = SK_ColorTRANSPARENT;
+ float mFillAlpha = 1;
+ float mTrimPathStart = 0;
+ float mTrimPathEnd = 1;
+ float mTrimPathOffset = 0;
+ bool mTrimDirty = true;
+ SkPaint::Cap mStrokeLineCap = SkPaint::Cap::kButt_Cap;
+ SkPaint::Join mStrokeLineJoin = SkPaint::Join::kMiter_Join;
+ float mStrokeMiterLimit = 4;
+ SkPath mTrimmedSkPath;
+ SkPaint mPaint;
+};
+
+class ANDROID_API ClipPath: public Path {
+public:
+ ClipPath(const ClipPath& path) : Path(path) {}
+ ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
+ ClipPath() : Path() {}
+ ClipPath(const Data& nodes) : Path(nodes) {}
+
+protected:
+ void drawPath(Canvas* outCanvas, const SkPath& renderPath,
+ float strokeScale) override;
+};
+
+class ANDROID_API Group: public Node {
+public:
+ Group(const Group& group);
+ Group() {}
+ float getRotation() {
+ return mRotate;
+ }
+ void setRotation(float rotation) {
+ mRotate = rotation;
+ }
+ float getPivotX() {
+ return mPivotX;
+ }
+ void setPivotX(float pivotX) {
+ mPivotX = pivotX;
+ }
+ float getPivotY() {
+ return mPivotY;
+ }
+ void setPivotY(float pivotY) {
+ mPivotY = pivotY;
+ }
+ float getScaleX() {
+ return mScaleX;
+ }
+ void setScaleX(float scaleX) {
+ mScaleX = scaleX;
+ }
+ float getScaleY() {
+ return mScaleY;
+ }
+ void setScaleY(float scaleY) {
+ mScaleY = scaleY;
+ }
+ float getTranslateX() {
+ return mTranslateX;
+ }
+ void setTranslateX(float translateX) {
+ mTranslateX = translateX;
+ }
+ float getTranslateY() {
+ return mTranslateY;
+ }
+ void setTranslateY(float translateY) {
+ mTranslateY = translateY;
+ }
+ virtual void draw(Canvas* outCanvas, const SkMatrix& currentMatrix,
+ float scaleX, float scaleY) override;
+ void updateLocalMatrix(float rotate, float pivotX, float pivotY,
+ float scaleX, float scaleY, float translateX, float translateY);
+ void getLocalMatrix(SkMatrix* outMatrix);
+ void addChild(Node* child);
+ void dump() override;
+ bool getProperties(float* outProperties, int length);
+
+private:
+ enum class Property {
+ Rotate_Property = 0,
+ PivotX_Property,
+ PivotY_Property,
+ ScaleX_Property,
+ ScaleY_Property,
+ TranslateX_Property,
+ TranslateY_Property,
+ // Count of the properties, must be at the end.
+ Count,
+ };
+ float mRotate = 0;
+ float mPivotX = 0;
+ float mPivotY = 0;
+ float mScaleX = 1;
+ float mScaleY = 1;
+ float mTranslateX = 0;
+ float mTranslateY = 0;
+ std::vector<Node*> mChildren;
+};
+
+class ANDROID_API Tree {
+public:
+ Tree(Group* rootNode) : mRootNode(rootNode) {}
+ void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
+ const SkRect& bounds, bool needsMirroring, bool canReuseCache);
+ void drawCachedBitmapWithRootAlpha(Canvas* outCanvas, SkColorFilter* filter,
+ const SkRect& originalBounds);
+
+ void updateCachedBitmap(int width, int height);
+ void createCachedBitmapIfNeeded(int width, int height);
+ bool canReuseBitmap(int width, int height);
+ void setAllowCaching(bool allowCaching) {
+ mAllowCaching = allowCaching;
+ }
+ bool setRootAlpha(float rootAlpha) {
+ return VD_SET_PROP(mRootAlpha, rootAlpha);
+ }
+
+ float getRootAlpha() {
+ return mRootAlpha;
+ }
+ void setViewportSize(float viewportWidth, float viewportHeight) {
+ mViewportWidth = viewportWidth;
+ mViewportHeight = viewportHeight;
+ }
+
+private:
+ // Cap the bitmap size, such that it won't hurt the performance too much
+ // and it won't crash due to a very large scale.
+ // The drawable will look blurry above this size.
+ const static int MAX_CACHED_BITMAP_SIZE;
+
+ bool mCacheDirty = true;
+ bool mAllowCaching = true;
+ float mViewportWidth = 0;
+ float mViewportHeight = 0;
+ float mRootAlpha = 1.0f;
+
+ Group* mRootNode;
+ SkRect mBounds;
+ SkMatrix mCanvasMatrix;
+ SkPaint mPaint;
+ SkPathMeasure mPathMeasure;
+ SkBitmap mCachedBitmap;
+
+};
+
+} // namespace VectorDrawable
+
+typedef VectorDrawable::Path::Data PathData;
+} // namespace uirenderer
+} // namespace android
+
+#endif // ANDROID_HWUI_VPATH_H
diff --git a/libs/hwui/VectorDrawablePath.cpp b/libs/hwui/VectorDrawablePath.cpp
deleted file mode 100644
index c9a54ca870fa..000000000000
--- a/libs/hwui/VectorDrawablePath.cpp
+++ /dev/null
@@ -1,59 +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 "VectorDrawablePath.h"
-
-#include "PathParser.h"
-#include "utils/VectorDrawableUtils.h"
-
-#include <math.h>
-#include <utils/Log.h>
-
-namespace android {
-namespace uirenderer {
-
-
-VectorDrawablePath::VectorDrawablePath(const char* pathStr, size_t strLength) {
- PathParser::ParseResult result;
- PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
- if (!result.failureOccurred) {
- VectorDrawableUtils::verbsToPath(&mSkPath, mData);
- }
-}
-
-VectorDrawablePath::VectorDrawablePath(const PathData& data) {
- mData = data;
- // Now we need to construct a path
- VectorDrawableUtils::verbsToPath(&mSkPath, data);
-}
-
-VectorDrawablePath::VectorDrawablePath(const VectorDrawablePath& path) {
- mData = path.mData;
- VectorDrawableUtils::verbsToPath(&mSkPath, mData);
-}
-
-
-bool VectorDrawablePath::canMorph(const PathData& morphTo) {
- return VectorDrawableUtils::canMorph(mData, morphTo);
-}
-
-bool VectorDrawablePath::canMorph(const VectorDrawablePath& path) {
- return canMorph(path.mData);
-}
-
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/VectorDrawablePath.h b/libs/hwui/VectorDrawablePath.h
deleted file mode 100644
index 2e56349b3aa4..000000000000
--- a/libs/hwui/VectorDrawablePath.h
+++ /dev/null
@@ -1,55 +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 ANDROID_HWUI_VPATH_H
-#define ANDROID_HWUI_VPATH_H
-
-#include <cutils/compiler.h>
-#include "SkPath.h"
-#include <vector>
-
-namespace android {
-namespace uirenderer {
-
-struct ANDROID_API PathData {
- // TODO: Try using FatVector instead of std::vector and do a micro benchmark on the performance
- // difference.
- std::vector<char> verbs;
- std::vector<size_t> verbSizes;
- std::vector<float> points;
- bool operator== (const PathData& data) const {
- return verbs == data.verbs && verbSizes == data.verbSizes && points == data.points;
- }
-
-};
-
-class VectorDrawablePath {
-public:
- VectorDrawablePath(const PathData& nodes);
- VectorDrawablePath(const VectorDrawablePath& path);
- VectorDrawablePath(const char* path, size_t strLength);
- bool canMorph(const PathData& path);
- bool canMorph(const VectorDrawablePath& path);
-
-private:
- PathData mData;
- SkPath mSkPath;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // ANDROID_HWUI_VPATH_H
diff --git a/libs/hwui/renderstate/Scissor.cpp b/libs/hwui/renderstate/Scissor.cpp
index 95dcd18867d9..61dd8c3200a4 100644
--- a/libs/hwui/renderstate/Scissor.cpp
+++ b/libs/hwui/renderstate/Scissor.cpp
@@ -15,6 +15,8 @@
*/
#include "renderstate/Scissor.h"
+#include "Rect.h"
+
#include <utils/Log.h>
namespace android {
@@ -71,6 +73,26 @@ bool Scissor::set(GLint x, GLint y, GLint width, GLint height) {
return false;
}
+void Scissor::set(int viewportHeight, const Rect& clip) {
+ // transform to Y-flipped GL space, and prevent negatives
+ GLint x = std::max(0, (int)clip.left);
+ GLint y = std::max(0, viewportHeight - (int)clip.bottom);
+ GLint width = std::max(0, ((int)clip.right) - x);
+ GLint height = std::max(0, (viewportHeight - (int)clip.top) - y);
+
+ if (x != mScissorX
+ || y != mScissorY
+ || width != mScissorWidth
+ || height != mScissorHeight) {
+ glScissor(x, y, width, height);
+
+ mScissorX = x;
+ mScissorY = y;
+ mScissorWidth = width;
+ mScissorHeight = height;
+ }
+}
+
void Scissor::reset() {
mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
}
diff --git a/libs/hwui/renderstate/Scissor.h b/libs/hwui/renderstate/Scissor.h
index b37ec583686f..f30224470059 100644
--- a/libs/hwui/renderstate/Scissor.h
+++ b/libs/hwui/renderstate/Scissor.h
@@ -22,11 +22,14 @@
namespace android {
namespace uirenderer {
+class Rect;
+
class Scissor {
friend class RenderState;
public:
bool setEnabled(bool enabled);
bool set(GLint x, GLint y, GLint width, GLint height);
+ void set(int viewportHeight, const Rect& clip);
void reset();
bool isEnabled() { return mEnabled; }
void dump();
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 78df29759a44..466fef9def09 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -29,8 +29,6 @@
#define GLES_VERSION 2
-#define WAIT_FOR_GPU_COMPLETION 0
-
// Android-specific addition that is used to show when frames began in systrace
EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
@@ -179,7 +177,10 @@ void EglManager::loadConfig() {
}
void EglManager::createContext() {
- EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE };
+ EGLint attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
+ EGL_NONE
+ };
mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attribs);
LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
"Failed to create context, error = %s", egl_error_str());
@@ -318,12 +319,10 @@ void EglManager::damageFrame(const Frame& frame, const SkRect& dirty) {
bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
-#if WAIT_FOR_GPU_COMPLETION
- {
+ if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
ATRACE_NAME("Finishing GPU work");
fence();
}
-#endif
EGLint rects[4];
frame.map(screenDirty, rects);
diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h
index df8d194f641b..706f2ff75222 100644
--- a/libs/hwui/tests/common/TestScene.h
+++ b/libs/hwui/tests/common/TestScene.h
@@ -37,6 +37,7 @@ class TestScene {
public:
struct Options {
int count = 0;
+ int reportFrametimeWeight = 0;
};
template <class T>
diff --git a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
new file mode 100644
index 000000000000..db6402ce136f
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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 "TestSceneBase.h"
+
+class ClippingAnimation;
+
+static TestScene::Registrar _RectGrid(TestScene::Info{
+ "clip",
+ "Complex clip cases"
+ "Low CPU/GPU load.",
+ TestScene::simpleCreateScene<ClippingAnimation>
+});
+
+class ClippingAnimation : public TestScene {
+public:
+ sp<RenderNode> card;
+ void createContent(int width, int height, TestCanvas& canvas) override {
+ canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
+ card = TestUtils::createNode(0, 0, 200, 400,
+ [](RenderProperties& props, TestCanvas& canvas) {
+ canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+ {
+ canvas.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op);
+ canvas.translate(100, 100);
+ canvas.rotate(45);
+ canvas.translate(-100, -100);
+ canvas.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op);
+ canvas.drawColor(Color::Blue_500, SkXfermode::kSrcOver_Mode);
+ }
+ canvas.restore();
+
+ canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+ {
+ SkPath clipCircle;
+ clipCircle.addCircle(100, 300, 100);
+ canvas.clipPath(&clipCircle, SkRegion::kIntersect_Op);
+ canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
+ }
+ canvas.restore();
+
+ // put on a layer, to test stencil attachment
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ props.setAlpha(0.9f);
+ });
+ canvas.drawRenderNode(card.get());
+ }
+ void doFrame(int frameNr) override {
+ int curFrame = frameNr % 150;
+ card->mutateStagingProperties().setTranslationX(curFrame);
+ card->mutateStagingProperties().setTranslationY(curFrame);
+ card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ }
+};
diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h
index ac781243c25e..935ddcf9212d 100644
--- a/libs/hwui/tests/common/scenes/TestSceneBase.h
+++ b/libs/hwui/tests/common/scenes/TestSceneBase.h
@@ -22,6 +22,7 @@
#include "tests/common/TestContext.h"
#include "tests/common/TestScene.h"
#include "tests/common/TestUtils.h"
+#include "utils/Color.h"
#include <functional>
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 82612206cac8..a843e9265ef1 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -38,6 +38,30 @@ public:
}
};
+template<class T>
+class ModifiedMovingAverage {
+public:
+ ModifiedMovingAverage(int weight) : mWeight(weight) {}
+
+ T add(T today) {
+ if (!mHasValue) {
+ mAverage = today;
+ } else {
+ mAverage = (((mWeight - 1) * mAverage) + today) / mWeight;
+ }
+ return mAverage;
+ }
+
+ T average() {
+ return mAverage;
+ }
+
+private:
+ bool mHasValue = false;
+ int mWeight;
+ T mAverage;
+};
+
void run(const TestScene::Info& info, const TestScene::Options& opts) {
// Switch to the real display
gDisplay = getBuiltInDisplay();
@@ -67,22 +91,35 @@ void run(const TestScene::Info& info, const TestScene::Options& opts) {
proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
// Do a few cold runs then reset the stats so that the caches are all hot
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < 5; i++) {
testContext.waitForVsync();
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
proxy->syncAndDrawFrame();
}
+
proxy->resetProfileInfo();
+ proxy->fence();
+
+ ModifiedMovingAverage<double> avgMs(opts.reportFrametimeWeight);
for (int i = 0; i < opts.count; i++) {
testContext.waitForVsync();
-
- ATRACE_NAME("UI-Draw Frame");
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
- UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
- scene->doFrame(i);
- proxy->syncAndDrawFrame();
+ {
+ ATRACE_NAME("UI-Draw Frame");
+ UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
+ scene->doFrame(i);
+ proxy->syncAndDrawFrame();
+ }
+ proxy->fence();
+ nsecs_t done = systemTime(CLOCK_MONOTONIC);
+ if (opts.reportFrametimeWeight) {
+ avgMs.add((done - vsync) / 1000000.0);
+ if (i % 10 == 9) {
+ printf("Average frametime %.3fms\n", avgMs.average());
+ }
+ }
}
proxy->dumpProfileInfo(STDOUT_FILENO, 0);
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 619713c58c9a..1616a95857d8 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -17,6 +17,7 @@
#include "tests/common/TestScene.h"
#include "protos/hwui.pb.h"
+#include "Properties.h"
#include <getopt.h>
#include <stdio.h>
@@ -25,26 +26,38 @@
#include <unordered_map>
#include <vector>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
using namespace android;
using namespace android::uirenderer;
using namespace android::uirenderer::test;
-static int gFrameCount = 150;
static int gRepeatCount = 1;
static std::vector<TestScene::Info> gRunTests;
+static TestScene::Options gOpts;
void run(const TestScene::Info& info, const TestScene::Options& opts);
static void printHelp() {
- printf("\
-USAGE: hwuitest [OPTIONS] <TESTNAME>\n\
-\n\
-OPTIONS:\n\
- -c, --count=NUM NUM loops a test should run (example, number of frames)\n\
- -r, --runs=NUM Repeat the test(s) NUM times\n\
- -h, --help Display this help\n\
- --list List all tests\n\
-\n");
+ printf(R"(
+USAGE: hwuitest [OPTIONS] <TESTNAME>
+
+OPTIONS:
+ -c, --count=NUM NUM loops a test should run (example, number of frames)
+ -r, --runs=NUM Repeat the test(s) NUM times
+ -h, --help Display this help
+ --list List all tests
+ --wait-for-gpu Set this to wait for the GPU before producing the
+ next frame. Note that without locked clocks this will
+ pathologically bad performance due to large idle time
+ --report-frametime[=weight] If set, the test will print to stdout the
+ moving average frametime. Weight is optional, default is 10
+ --cpuset=name Adds the test to the specified cpuset before running
+ Not supported on all devices and needs root
+)");
}
static void listTests() {
@@ -77,11 +90,56 @@ static void listTests() {
}
}
+static void moveToCpuSet(const char* cpusetName) {
+ if (access("/dev/cpuset/tasks", F_OK)) {
+ fprintf(stderr, "don't have access to cpusets, skipping...\n");
+ return;
+ }
+ static const int BUF_SIZE = 100;
+ char buffer[BUF_SIZE];
+
+ if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
+ fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
+ return;
+ }
+ int fd = open(buffer, O_WRONLY | O_CLOEXEC);
+ if (fd == -1) {
+ fprintf(stderr, "Error opening file %d\n", errno);
+ return;
+ }
+ pid_t pid = getpid();
+
+ int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long) pid);
+ if (towrite >= BUF_SIZE) {
+ fprintf(stderr, "Buffer wasn't large enough?\n");
+ } else {
+ if (write(fd, buffer, towrite) != towrite) {
+ fprintf(stderr, "Failed to write, errno=%d", errno);
+ }
+ }
+ close(fd);
+}
+
+// For options that only exist in long-form. Anything in the
+// 0-255 range is reserved for short options (which just use their ASCII value)
+namespace LongOpts {
+enum {
+ Reserved = 255,
+ List,
+ WaitForGpu,
+ ReportFrametime,
+ CpuSet,
+};
+}
+
static const struct option LONG_OPTIONS[] = {
{ "frames", required_argument, nullptr, 'f' },
{ "repeat", required_argument, nullptr, 'r' },
{ "help", no_argument, nullptr, 'h' },
- { "list", no_argument, nullptr, 'l' },
+ { "list", no_argument, nullptr, LongOpts::List },
+ { "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu },
+ { "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime },
+ { "cpuset", required_argument, nullptr, LongOpts::CpuSet },
{ 0, 0, 0, 0 }
};
@@ -89,8 +147,6 @@ static const char* SHORT_OPTIONS = "c:r:h";
void parseOptions(int argc, char* argv[]) {
int c;
- // temporary variable
- int count;
bool error = false;
opterr = 0;
@@ -110,31 +166,53 @@ void parseOptions(int argc, char* argv[]) {
// (although none of the current LONG_OPTIONS do this...)
break;
- case 'l':
+ case LongOpts::List:
listTests();
exit(EXIT_SUCCESS);
break;
case 'c':
- count = atoi(optarg);
- if (!count) {
+ gOpts.count = atoi(optarg);
+ if (!gOpts.count) {
fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
error = true;
- } else {
- gFrameCount = (count > 0 ? count : INT_MAX);
}
break;
case 'r':
- count = atoi(optarg);
- if (!count) {
+ gRepeatCount = atoi(optarg);
+ if (!gRepeatCount) {
fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
error = true;
} else {
- gRepeatCount = (count > 0 ? count : INT_MAX);
+ gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
+ }
+ break;
+
+ case LongOpts::ReportFrametime:
+ if (optarg) {
+ gOpts.reportFrametimeWeight = atoi(optarg);
+ if (!gOpts.reportFrametimeWeight) {
+ fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
+ error = true;
+ }
+ } else {
+ gOpts.reportFrametimeWeight = 10;
}
break;
+ case LongOpts::WaitForGpu:
+ Properties::waitForGpuCompletion = true;
+ break;
+
+ case LongOpts::CpuSet:
+ if (!optarg) {
+ error = true;
+ break;
+ }
+ moveToCpuSet(optarg);
+ break;
+
case 'h':
printHelp();
exit(EXIT_SUCCESS);
@@ -172,13 +250,14 @@ void parseOptions(int argc, char* argv[]) {
}
int main(int argc, char* argv[]) {
+ // set defaults
+ gOpts.count = 150;
+
parseOptions(argc, argv);
- TestScene::Options opts;
- opts.count = gFrameCount;
for (int i = 0; i < gRepeatCount; i++) {
for (auto&& test : gRunTests) {
- run(test, opts);
+ run(test, gOpts);
}
}
printf("Success!\n");
diff --git a/libs/hwui/tests/microbench/PathParserBench.cpp b/libs/hwui/tests/microbench/PathParserBench.cpp
index 3d9fafac6c93..bd742c6ededf 100644
--- a/libs/hwui/tests/microbench/PathParserBench.cpp
+++ b/libs/hwui/tests/microbench/PathParserBench.cpp
@@ -17,7 +17,7 @@
#include <benchmark/Benchmark.h>
#include "PathParser.h"
-#include "VectorDrawablePath.h"
+#include "VectorDrawable.h"
#include <SkPath.h>
diff --git a/libs/hwui/tests/scripts/prep_volantis.sh b/libs/hwui/tests/scripts/prep_volantis.sh
new file mode 100755
index 000000000000..09d4869523ba
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_volantis.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+# 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.
+
+adb root
+adb wait-for-device
+adb shell stop mpdecision
+adb shell stop perfd
+adb shell stop
+for pid in $( adb shell ps | awk '{ if ( $9 == "surfaceflinger" ) { print $2 } }' ); do
+ adb shell kill $pid
+done
+adb shell setprop debug.egl.traceGpuCompletion 1
+adb shell daemonize surfaceflinger
+sleep 3
+adb shell setprop service.bootanim.exit 1
+
+# cpu possible frequencies
+# 204000 229500 255000 280500 306000 331500 357000 382500 408000 433500 459000
+# 484500 510000 535500 561000 586500 612000 637500 663000 688500 714000 739500
+# 765000 790500 816000 841500 867000 892500 918000 943500 969000 994500 1020000
+# 1122000 1224000 1326000 1428000 1530000 1632000 1734000 1836000 1938000
+# 2014500 2091000 2193000 2295000 2397000 2499000
+
+S=1326000
+echo "set cpu $cpu to $S hz";
+adb shell "echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed"
+
+#disable hotplug
+adb shell "echo 0 > /sys/devices/system/cpu/cpuquiet/tegra_cpuquiet/enable"
+
+# gbus possible rates
+# 72000 108000 180000 252000 324000 396000 468000 540000 612000 648000
+# 684000 708000 756000 804000 852000 (kHz)
+
+S=324000000
+echo "set gpu to $s hz"
+adb shell "echo 1 > /d/clock/override.gbus/state"
+adb shell "echo $S > /d/clock/override.gbus/rate"
diff --git a/libs/hwui/tests/unit/BakedOpStateTests.cpp b/libs/hwui/tests/unit/BakedOpStateTests.cpp
index f9f5316a58df..3fd822d71310 100644
--- a/libs/hwui/tests/unit/BakedOpStateTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpStateTests.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include <BakedOpState.h>
+#include <ClipArea.h>
#include <RecordedOp.h>
#include <tests/common/TestUtils.h>
@@ -24,31 +25,33 @@ namespace android {
namespace uirenderer {
TEST(ResolvedRenderState, construct) {
+ LinearAllocator allocator;
Matrix4 translate10x20;
translate10x20.loadTranslate(10, 20, 0);
SkPaint paint;
- RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, Rect(100, 200), &paint);
+ ClipRect clip(Rect(100, 200));
+ RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, &clip, &paint);
{
// recorded with transform, no parent transform
auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
- ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20);
- EXPECT_EQ(Rect(100, 200), state.clipRect);
+ EXPECT_EQ(Rect(100, 200), state.clipRect());
EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
}
{
// recorded with transform and parent transform
auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
- ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
Matrix4 expectedTranslate;
expectedTranslate.loadTranslate(20, 40, 0);
EXPECT_MATRIX_APPROX_EQ(expectedTranslate, state.transform);
// intersection of parent & transformed child clip
- EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect);
+ EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect());
// translated and also clipped
EXPECT_EQ(Rect(50, 80, 100, 200), state.clippedBounds);
@@ -57,22 +60,24 @@ TEST(ResolvedRenderState, construct) {
}
TEST(ResolvedRenderState, computeLocalSpaceClip) {
+ LinearAllocator allocator;
Matrix4 translate10x20;
translate10x20.loadTranslate(10, 20, 0);
SkPaint paint;
- RectOp recordedOp(Rect(1000, 1000), translate10x20, Rect(100, 200), &paint);
+ ClipRect clip(Rect(100, 200));
+ RectOp recordedOp(Rect(1000, 1000), translate10x20, &clip, &paint);
{
// recorded with transform, no parent transform
auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
- ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip())
<< "Local clip rect should be 100x200, offset by -10,-20";
}
{
// recorded with transform + parent transform
auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
- ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip())
<< "Local clip rect should be 90x190, offset by -10,-20";
}
@@ -149,6 +154,7 @@ const static StrokeTestCase sStrokeTestCases[] = {
};
TEST(ResolvedRenderState, construct_expandForStroke) {
+ LinearAllocator allocator;
// Loop over table of test cases and verify different combinations of stroke width and transform
for (auto&& testCase : sStrokeTestCases) {
SkPaint strokedPaint;
@@ -156,14 +162,15 @@ TEST(ResolvedRenderState, construct_expandForStroke) {
strokedPaint.setStyle(SkPaint::kStroke_Style);
strokedPaint.setStrokeWidth(testCase.strokeWidth);
+ ClipRect clip(Rect(200, 200));
RectOp recordedOp(Rect(50, 50, 150, 150),
- Matrix4::identity(), Rect(200, 200), &strokedPaint);
+ Matrix4::identity(), &clip, &strokedPaint);
Matrix4 snapshotMatrix;
snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200));
- ResolvedRenderState state(*parentSnapshot, recordedOp, true);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true);
testCase.validator(state);
}
}
@@ -175,8 +182,9 @@ TEST(BakedOpState, tryConstruct) {
translate100x0.loadTranslate(100, 0, 0);
SkPaint paint;
+ ClipRect clip(Rect(100, 200));
{
- RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, Rect(100, 200), &paint);
+ RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp);
@@ -184,7 +192,7 @@ TEST(BakedOpState, tryConstruct) {
EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
}
{
- RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), Rect(100, 200), &paint);
+ RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, successOp);
@@ -218,7 +226,8 @@ TEST(BakedOpState, tryStrokeableOpConstruct) {
SkPaint paint;
paint.setStyle(SkPaint::kStrokeAndFill_Style);
paint.setStrokeWidth(0.0f);
- RectOp rejectOp(Rect(100, 200), Matrix4::identity(), Rect(100, 200), &paint);
+ ClipRect clip(Rect(100, 200));
+ RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
BakedOpState::StrokeBehavior::StyleDefined);
@@ -231,7 +240,8 @@ TEST(BakedOpState, tryStrokeableOpConstruct) {
SkPaint paint;
paint.setStyle(SkPaint::kStrokeAndFill_Style);
paint.setStrokeWidth(10.0f);
- RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
+ ClipRect clip(Rect(200, 200));
+ RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
BakedOpState::StrokeBehavior::StyleDefined);
@@ -245,7 +255,8 @@ TEST(BakedOpState, tryStrokeableOpConstruct) {
SkPaint paint;
paint.setStyle(SkPaint::kFill_Style);
paint.setStrokeWidth(10.0f);
- RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
+ ClipRect clip(Rect(200, 200));
+ RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
BakedOpState::StrokeBehavior::Forced);
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index c4d305e5de18..4cae737ab295 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -119,5 +119,122 @@ TEST(ClipArea, replaceNegative) {
EXPECT_EQ(expected, area.getClipRect());
}
+TEST(ClipArea, serializeClip) {
+ ClipArea area(createClipArea());
+ LinearAllocator allocator;
+
+ // unset clip
+ EXPECT_EQ(nullptr, area.serializeClip(allocator));
+
+ // rect clip
+ area.setClip(0, 0, 200, 200);
+ {
+ auto serializedClip = area.serializeClip(allocator);
+ 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(serializedClip, area.serializeClip(allocator))
+ << "Requery of clip on unmodified ClipArea must return same pointer.";
+ }
+
+ // rect list
+ Matrix4 rotate;
+ rotate.loadRotate(2.0f);
+ area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
+ {
+ auto serializedClip = area.serializeClip(allocator);
+ 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(serializedClip, area.serializeClip(allocator))
+ << "Requery of clip on unmodified ClipArea must return same pointer.";
+ }
+
+ // region
+ SkPath circlePath;
+ circlePath.addCircle(100, 100, 100);
+ area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
+ {
+ auto serializedClip = area.serializeClip(allocator);
+ 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())
+ << "Clip region should be 200x200";
+ EXPECT_EQ(serializedClip, area.serializeClip(allocator))
+ << "Requery of clip on unmodified ClipArea must return same pointer.";
+ }
}
+
+TEST(ClipArea, serializeIntersectedClip) {
+ ClipArea area(createClipArea());
+ LinearAllocator allocator;
+
+ // simple state;
+ EXPECT_EQ(nullptr, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
+ area.setClip(0, 0, 200, 200);
+ {
+ auto origRectClip = area.serializeClip(allocator);
+ ASSERT_NE(nullptr, origRectClip);
+ EXPECT_EQ(origRectClip, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
+ }
+
+ // rect
+ {
+ ClipRect recordedClip(Rect(100, 100));
+ Matrix4 translateScale;
+ translateScale.loadTranslate(100, 100, 0);
+ translateScale.scale(2, 3, 1);
+ auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
+ ASSERT_NE(nullptr, resolvedClip);
+ ASSERT_EQ(ClipMode::Rectangle, resolvedClip->mode);
+ EXPECT_EQ(Rect(100, 100, 200, 200),
+ reinterpret_cast<const ClipRect*>(resolvedClip)->rect);
+
+ EXPECT_EQ(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip, translateScale))
+ << "Must return previous serialization, since input is same";
+
+ ClipRect recordedClip2(Rect(100, 100));
+ EXPECT_NE(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip2, translateScale))
+ << "Shouldn't return previous serialization, since matrix location is different";
+ }
+
+ // rect list
+ Matrix4 rotate;
+ rotate.loadRotate(2.0f);
+ area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
+ {
+ ClipRect recordedClip(Rect(100, 100));
+ auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity());
+ ASSERT_NE(nullptr, resolvedClip);
+ ASSERT_EQ(ClipMode::RectangleList, resolvedClip->mode);
+ auto clipRectList = reinterpret_cast<const ClipRectList*>(resolvedClip);
+ EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
+ }
+
+ // region
+ SkPath circlePath;
+ circlePath.addCircle(100, 100, 100);
+ area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
+ {
+ SkPath ovalPath;
+ ovalPath.addOval(SkRect::MakeLTRB(50, 0, 150, 200));
+
+ ClipRegion recordedClip;
+ recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200)));
+
+ Matrix4 translate10x20;
+ translate10x20.loadTranslate(10, 20, 0);
+ auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip,
+ translate10x20); // Note: only translate for now, others not handled correctly
+ ASSERT_NE(nullptr, resolvedClip);
+ ASSERT_EQ(ClipMode::Region, resolvedClip->mode);
+ auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip);
+ EXPECT_EQ(SkIRect::MakeLTRB(60, 20, 160, 200), clipRegion->region.getBounds());
+ }
}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index 78d65ddaa19d..5c442901045e 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -27,7 +27,7 @@ struct SimplePair {
int two = 2;
};
-TEST(LinearAllocator, alloc) {
+TEST(LinearAllocator, create) {
LinearAllocator la;
EXPECT_EQ(0u, la.usedSize());
la.alloc(64);
@@ -35,7 +35,7 @@ TEST(LinearAllocator, alloc) {
// so the usedSize isn't strictly defined
EXPECT_LE(64u, la.usedSize());
EXPECT_GT(80u, la.usedSize());
- auto pair = la.alloc<SimplePair>();
+ auto pair = la.create<SimplePair>();
EXPECT_LE(64u + sizeof(SimplePair), la.usedSize());
EXPECT_GT(80u + sizeof(SimplePair), la.usedSize());
EXPECT_EQ(1, pair->one);
@@ -47,8 +47,8 @@ TEST(LinearAllocator, dtor) {
{
LinearAllocator la;
for (int i = 0; i < 5; i++) {
- la.alloc<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
- la.alloc<SimplePair>();
+ la.create<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
+ la.create<SimplePair>();
}
la.alloc(100);
for (int i = 0; i < 5; i++) {
@@ -75,7 +75,7 @@ TEST(LinearAllocator, rewind) {
la.rewindIfLastAlloc(addr, 100);
EXPECT_GT(16u, la.usedSize());
size_t emptySize = la.usedSize();
- auto sigdtor = la.alloc<TestUtils::SignalingDtor>();
+ auto sigdtor = la.create<TestUtils::SignalingDtor>();
sigdtor->setSignal(&destroyed);
EXPECT_EQ(0, destroyed);
EXPECT_LE(emptySize, la.usedSize());
diff --git a/libs/hwui/tests/unit/OpReordererTests.cpp b/libs/hwui/tests/unit/OpReordererTests.cpp
index b28e4361bc4a..66dccb4b0d4f 100644
--- a/libs/hwui/tests/unit/OpReordererTests.cpp
+++ b/libs/hwui/tests/unit/OpReordererTests.cpp
@@ -64,14 +64,14 @@ public:
ADD_FAILURE() << "Layer updates not expected in this test";
}
virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
- virtual void endFrame() {}
+ virtual void endFrame(const Rect& repaintRect) {}
// define virtual defaults for single draw methods
#define X(Type) \
virtual void on##Type(const Type&, const BakedOpState&) { \
ADD_FAILURE() << #Type " not expected in this test"; \
}
- MAP_OPS(X)
+ MAP_RENDERABLE_OPS(X)
#undef X
// define virtual defaults for merged draw methods
@@ -79,7 +79,7 @@ public:
virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
}
- MAP_MERGED_OPS(X)
+ MAP_MERGEABLE_OPS(X)
#undef X
int getIndex() { return mIndex; }
@@ -99,7 +99,7 @@ public:
static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
renderer.on##Type(op, state); \
}
- MAP_OPS(X);
+ MAP_RENDERABLE_OPS(X);
#undef X
// define merged op methods, which redirect to TestRendererBase
@@ -107,7 +107,7 @@ public:
static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
renderer.onMerged##Type##s(opList); \
}
- MAP_MERGED_OPS(X);
+ MAP_MERGEABLE_OPS(X);
#undef X
};
@@ -127,7 +127,7 @@ TEST(OpReorderer, simple) {
void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
EXPECT_EQ(2, mIndex++);
}
- void endFrame() override {
+ void endFrame(const Rect& repaintRect) override {
EXPECT_EQ(3, mIndex++);
}
};
@@ -327,7 +327,7 @@ RENDERTHREAD_TEST(OpReorderer, textureLayer) {
public:
void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(0, mIndex++);
- EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect);
+ EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
Matrix4 expected;
@@ -405,7 +405,7 @@ TEST(OpReorderer, clipped) {
void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
EXPECT_EQ(0, mIndex++);
EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
- EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect);
+ EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
EXPECT_TRUE(state.computedState.transform.isIdentity());
}
};
@@ -439,7 +439,7 @@ TEST(OpReorderer, saveLayerSimple) {
EXPECT_EQ(1, mIndex++);
EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
- EXPECT_EQ(Rect(180, 180), state.computedState.clipRect);
+ EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
Matrix4 expectedTransform;
expectedTransform.loadTranslate(-10, -10, 0);
@@ -448,7 +448,7 @@ TEST(OpReorderer, saveLayerSimple) {
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(3, mIndex++);
EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
- EXPECT_EQ(Rect(200, 200), state.computedState.clipRect);
+ EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
EXPECT_TRUE(state.computedState.transform.isIdentity());
}
};
@@ -494,7 +494,7 @@ TEST(OpReorderer, saveLayerNested) {
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
EXPECT_EQ(7, mIndex++);
}
- void endFrame() override {
+ void endFrame(const Rect& repaintRect) override {
EXPECT_EQ(9, mIndex++);
}
void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -574,7 +574,7 @@ RENDERTHREAD_TEST(OpReorderer, hwLayerSimple) {
EXPECT_TRUE(state.computedState.transform.isIdentity())
<< "Transform should be reset within layer";
- EXPECT_EQ(state.computedState.clipRect, Rect(25, 25, 75, 75))
+ EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
<< "Damage rect should be used to clip layer content";
}
void endLayer() override {
@@ -586,7 +586,7 @@ RENDERTHREAD_TEST(OpReorderer, hwLayerSimple) {
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(4, mIndex++);
}
- void endFrame() override {
+ void endFrame(const Rect& repaintRect) override {
EXPECT_EQ(5, mIndex++);
}
};
@@ -675,7 +675,7 @@ RENDERTHREAD_TEST(OpReorderer, hwLayerComplex) {
EXPECT_EQ(200u, layer->viewportHeight);
} else { ADD_FAILURE(); }
}
- void endFrame() override {
+ void endFrame(const Rect& repaintRect) override {
EXPECT_EQ(12, mIndex++);
}
};
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 08f927ce00fd..a63cb18d7c4b 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -33,6 +33,14 @@ static void playbackOps(const DisplayList& displayList,
}
}
+#define EXPECT_CLIP_RECT(expRect, clipStatePtr) \
+ EXPECT_NE(nullptr, (clipStatePtr)) << "Op is unclipped"; \
+ if ((clipStatePtr)->mode == ClipMode::Rectangle) { \
+ EXPECT_EQ((expRect), reinterpret_cast<const ClipRect*>(clipStatePtr)->rect); \
+ } else { \
+ ADD_FAILURE() << "ClipState not a rect"; \
+ }
+
TEST(RecordingCanvas, emptyPlayback) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -41,6 +49,22 @@ TEST(RecordingCanvas, emptyPlayback) {
playbackOps(*dl, [](const RecordedOp& op) { ADD_FAILURE(); });
}
+TEST(RecordingCanvas, clipRect) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
+ canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+ canvas.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
+ canvas.drawRect(0, 0, 50, 50, SkPaint());
+ canvas.drawRect(50, 50, 100, 100, SkPaint());
+ canvas.restore();
+ });
+
+ ASSERT_EQ(2u, dl->getOps().size()) << "Must be exactly two ops";
+ EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[0]->localClip);
+ EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[1]->localClip);
+ EXPECT_EQ(dl->getOps()[0]->localClip, dl->getOps()[1]->localClip)
+ << "Clip should be serialized once";
+}
+
TEST(RecordingCanvas, drawLines) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
SkPaint paint;
@@ -66,7 +90,7 @@ TEST(RecordingCanvas, drawRect) {
ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
auto op = *(dl->getOps()[0]);
ASSERT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_EQ(Rect(100, 200), op.localClipRect);
+ EXPECT_EQ(nullptr, op.localClip);
EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
}
@@ -83,7 +107,7 @@ TEST(RecordingCanvas, drawText) {
playbackOps(*dl, [&count](const RecordedOp& op) {
count++;
ASSERT_EQ(RecordedOpId::TextOp, op.opId);
- EXPECT_EQ(Rect(200, 200), op.localClipRect);
+ EXPECT_EQ(nullptr, op.localClip);
EXPECT_TRUE(op.localMatrix.isIdentity());
EXPECT_TRUE(op.unmappedBounds.contains(25, 15, 50, 25))
<< "Op expected to be 25+ pixels wide, 10+ pixels tall";
@@ -185,7 +209,7 @@ TEST(RecordingCanvas, backgroundAndImage) {
ASSERT_NE(nullptr, op.paint);
EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
EXPECT_EQ(Rect(100, 200), op.unmappedBounds);
- EXPECT_EQ(Rect(100, 200), op.localClipRect);
+ EXPECT_EQ(nullptr, op.localClip);
Matrix4 expectedMatrix;
expectedMatrix.loadIdentity();
@@ -194,7 +218,7 @@ TEST(RecordingCanvas, backgroundAndImage) {
ASSERT_EQ(RecordedOpId::BitmapOp, op.opId);
EXPECT_EQ(nullptr, op.paint);
EXPECT_EQ(Rect(25, 25), op.unmappedBounds);
- EXPECT_EQ(Rect(100, 200), op.localClipRect);
+ EXPECT_EQ(nullptr, op.localClip);
Matrix4 expectedMatrix;
expectedMatrix.loadTranslate(25, 25, 0);
@@ -219,12 +243,12 @@ TEST(RecordingCanvas, saveLayer_simple) {
case 0:
EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
- EXPECT_EQ(Rect(200, 200), op.localClipRect);
+ EXPECT_EQ(nullptr, op.localClip);
EXPECT_TRUE(op.localMatrix.isIdentity());
break;
case 1:
EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_EQ(Rect(180, 160), op.localClipRect);
+ EXPECT_CLIP_RECT(Rect(180, 160), op.localClip);
EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
expectedMatrix.loadTranslate(-10, -20, 0);
EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
@@ -254,8 +278,8 @@ TEST(RecordingCanvas, saveLayer_viewportCrop) {
if (count++ == 1) {
Matrix4 expectedMatrix;
EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_EQ(Rect(100, 100), op.localClipRect) << "Recorded clip rect should be"
- " intersection of viewport and saveLayer bounds, in layer space";
+ EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be
+ // intersection of viewport and saveLayer bounds, in layer space;
EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
expectedMatrix.loadTranslate(-100, -100, 0);
EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
@@ -281,7 +305,7 @@ TEST(RecordingCanvas, saveLayer_rotateUnclipped) {
playbackOps(*dl, [&count](const RecordedOp& op) {
if (count++ == 1) {
EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_EQ(Rect(100, 100), op.localClipRect);
+ EXPECT_CLIP_RECT(Rect(100, 100), op.localClip);
EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.localMatrix)
<< "Recorded op shouldn't see any canvas transform before the saveLayer";
@@ -312,7 +336,16 @@ TEST(RecordingCanvas, saveLayer_rotateClipped) {
// ...and get about 58.6, 58.6, 341.4 341.4, because the bounds are clipped by
// the parent 200x200 viewport, but prior to rotation
- EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136), op.localClipRect);
+ ASSERT_NE(nullptr, op.localClip);
+ ASSERT_EQ(ClipMode::Rectangle, op.localClip->mode);
+ // NOTE: this check relies on saveLayer altering the clip post-viewport init. This
+ // causes the clip to be recorded by contained draw commands, though it's not necessary
+ // since the same clip will be computed at draw time. If such a change is made, this
+ // check could be done at record time by querying the clip, or the clip could be altered
+ // slightly so that it is serialized.
+ EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136),
+ (reinterpret_cast<const ClipRect*>(op.localClip))->rect);
+
EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
expectedMatrix.loadIdentity();
EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 77dd73acff10..720854779c98 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include "PathParser.h"
+#include "VectorDrawable.h"
#include "utils/MathUtils.h"
#include "utils/VectorDrawableUtils.h"
@@ -98,6 +99,65 @@ const static TestData sTestDataSet[] = {
}
},
+ // Check box VectorDrawable path data
+ {
+ // Path
+ "M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z",
+ {
+ {'M', 'l', 'c', 'l', 'c', 'l', 'c', 'l', 'c', 'Z', 'M', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'Z'},
+ {2, 2, 6, 2, 6, 2, 6, 2, 6, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
+ {0.0, -1.0, 0.0, 0.0, 0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0, 0.0, 0.0, -0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0, 0.0, 0.0, 0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0, 7.0, -9.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0, -1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0, 0.0, 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0, 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0, 0.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(0.0, -1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(-0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0);
+ outPath->close();
+ outPath->moveTo(0.0, -1.0);
+ outPath->moveTo(7.0, -9.0);
+ outPath->rCubicTo(0.0, 0.0, -14.0, 0.0, -14.0, 0.0);
+ outPath->rCubicTo(-1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, 14.0, 0.0, 14.0);
+ outPath->rCubicTo(0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0);
+ outPath->rCubicTo(0.0, 0.0, 14.0, 0.0, 14.0, 0.0);
+ outPath->rCubicTo(1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, -14.0, 0.0, -14.0);
+ outPath->rCubicTo(0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+ outPath->close();
+ outPath->moveTo(7.0, -9.0);
+ }
+ },
+
+ // pie1 in progress bar
+ {
+ "M300,70 a230,230 0 1,0 1,0 z",
+ {
+ {'M', 'a', 'z', },
+ {2, 7, 0, },
+ {300.0, 70.0, 230.0, 230.0, 0.0, 1.0, 0.0, 1.0, 0.0, },
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(300.0, 70.0);
+ outPath->cubicTo(239.06697794203706, 70.13246340443499, 180.6164396449267, 94.47383115953485, 137.6004913602211, 137.6302781499585);
+ outPath->cubicTo(94.58454307551551, 180.78672514038215, 70.43390412842275, 239.3163266242308, 70.50013586976587, 300.2494566687817);
+ outPath->cubicTo(70.56636761110899, 361.1825867133326, 94.84418775550249, 419.65954850554147, 137.9538527586204, 462.72238058830936);
+ outPath->cubicTo(181.06351776173827, 505.7852126710772, 239.5668339599056, 529.999456521097, 300.49999999999994, 529.999456521097);
+ outPath->cubicTo(361.43316604009436, 529.999456521097, 419.93648223826176, 505.78521267107726, 463.0461472413797, 462.7223805883093);
+ outPath->cubicTo(506.1558122444976, 419.65954850554135, 530.433632388891, 361.1825867133324, 530.4998641302341, 300.2494566687815);
+ outPath->cubicTo(530.5660958715771, 239.31632662423056, 506.4154569244844, 180.7867251403819, 463.3995086397787, 137.6302781499583);
+ outPath->cubicTo(420.383560355073, 94.47383115953468, 361.93302205796255, 70.13246340443492, 300.9999999999996, 70.00000000000003);
+ outPath->close();
+ outPath->moveTo(300.0, 70.0);
+ }
+ },
+
// Random long data
{
// Path
@@ -178,6 +238,7 @@ const StringPath sStringPaths[] = {
{"1-2e34567", false}
};
+
static bool hasSameVerbs(const PathData& from, const PathData& to) {
return from.verbs == to.verbs && from.verbSizes == to.verbSizes;
}
@@ -284,6 +345,49 @@ TEST(VectorDrawableUtils, interpolatePathData) {
}
}
+TEST(VectorDrawable, matrixScale) {
+ struct MatrixAndScale {
+ float buffer[9];
+ float matrixScale;
+ };
+
+ const MatrixAndScale sMatrixAndScales[] {
+ {
+ {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ 1.0
+ },
+ {
+ {1.0f, 0.0f, 240.0f, 0.0f, 1.0f, 240.0f, 0.0f, 0.0f, 1.0f},
+ 1.0f,
+ },
+ {
+ {1.5f, 0.0f, 24.0f, 0.0f, 1.5f, 24.0f, 0.0f, 0.0f, 1.0f},
+ 1.5f,
+ },
+ {
+ {0.99999994f, 0.0f, 300.0f, 0.0f, 0.99999994f, 158.57864f, 0.0f, 0.0f, 1.0f},
+ 0.99999994f,
+ },
+ {
+ {0.7071067f, 0.7071067f, 402.5305f, -0.7071067f, 0.7071067f, 169.18524f, 0.0f, 0.0f, 1.0f},
+ 0.99999994f,
+ },
+ {
+ {0.0f, 0.9999999f, 482.5305f, -0.9999999f, 0.0f, 104.18525f, 0.0f, 0.0f, 1.0f},
+ 0.9999999f,
+ },
+ {
+ {-0.35810637f, -0.93368083f, 76.55821f, 0.93368083f, -0.35810637f, 89.538506f, 0.0f, 0.0f, 1.0f},
+ 1.0000001f,
+ },
+ };
+ for (MatrixAndScale matrixAndScale : sMatrixAndScales) {
+ SkMatrix matrix;
+ matrix.set9(matrixAndScale.buffer);
+ float actualMatrixScale = VectorDrawable::Path::getMatrixScale(matrix);
+ EXPECT_EQ(matrixAndScale.matrixScale, actualMatrixScale);
+ }
+}
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index e1c6f6c70428..dcbc0dda951a 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -56,12 +56,12 @@ public:
void* alloc(size_t size);
/**
- * Allocates an instance of the template type with the default constructor
+ * Allocates an instance of the template type with the given construction parameters
* and adds it to the automatic destruction list.
*/
- template<class T>
- T* alloc() {
- T* ret = new (*this) T;
+ template<class T, typename... Params>
+ T* create(Params... params) {
+ T* ret = new (*this) T(params...);
autoDestroy(ret);
return ret;
}
diff --git a/libs/hwui/utils/VectorDrawableUtils.h b/libs/hwui/utils/VectorDrawableUtils.h
index 21c1cdcc37f3..b5ef5102d219 100644
--- a/libs/hwui/utils/VectorDrawableUtils.h
+++ b/libs/hwui/utils/VectorDrawableUtils.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_HWUI_VECTORDRAWABLE_UTILS_H
#define ANDROID_HWUI_VECTORDRAWABLE_UTILS_H
-#include "VectorDrawablePath.h"
+#include "VectorDrawable.h"
#include <cutils/compiler.h>
#include "SkPath.h"
diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java
index 41b369dc38ae..dd069218463a 100644
--- a/media/java/android/media/MediaInserter.java
+++ b/media/java/android/media/MediaInserter.java
@@ -16,8 +16,8 @@
package android.media;
+import android.content.ContentProviderClient;
import android.content.ContentValues;
-import android.content.IContentProvider;
import android.net.Uri;
import android.os.RemoteException;
@@ -37,13 +37,11 @@ public class MediaInserter {
private final HashMap<Uri, List<ContentValues>> mPriorityRowMap =
new HashMap<Uri, List<ContentValues>>();
- private final IContentProvider mProvider;
- private final String mPackageName;
+ private final ContentProviderClient mProvider;
private final int mBufferSizePerUri;
- public MediaInserter(IContentProvider provider, String packageName, int bufferSizePerUri) {
+ public MediaInserter(ContentProviderClient provider, int bufferSizePerUri) {
mProvider = provider;
- mPackageName = packageName;
mBufferSizePerUri = bufferSizePerUri;
}
@@ -90,7 +88,7 @@ public class MediaInserter {
if (!list.isEmpty()) {
ContentValues[] valuesArray = new ContentValues[list.size()];
valuesArray = list.toArray(valuesArray);
- mProvider.bulkInsert(mPackageName, tableUri, valuesArray);
+ mProvider.bulkInsert(tableUri, valuesArray);
list.clear();
}
}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 9ea672287d88..96c616be359d 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -16,14 +16,10 @@
package android.media;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-
+import android.content.ContentProviderClient;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
-import android.content.IContentProvider;
import android.database.Cursor;
import android.database.SQLException;
import android.drm.DrmManagerClient;
@@ -50,6 +46,12 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Xml;
+import dalvik.system.CloseGuard;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
@@ -61,6 +63,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Internal service helper that no-one should use directly.
@@ -107,8 +110,7 @@ import java.util.Locale;
*
* {@hide}
*/
-public class MediaScanner
-{
+public class MediaScanner implements AutoCloseable {
static {
System.loadLibrary("media_jni");
native_init();
@@ -302,21 +304,23 @@ public class MediaScanner
};
private long mNativeContext;
- private Context mContext;
- private String mPackageName;
- private IContentProvider mMediaProvider;
- private Uri mAudioUri;
- private Uri mVideoUri;
- private Uri mImagesUri;
- private Uri mThumbsUri;
- private Uri mPlaylistsUri;
- private Uri mFilesUri;
- private Uri mFilesUriNoNotify;
- private boolean mProcessPlaylists, mProcessGenres;
+ private final Context mContext;
+ private final String mPackageName;
+ private final String mVolumeName;
+ private final ContentProviderClient mMediaProvider;
+ private final Uri mAudioUri;
+ private final Uri mVideoUri;
+ private final Uri mImagesUri;
+ private final Uri mThumbsUri;
+ private final Uri mPlaylistsUri;
+ private final Uri mFilesUri;
+ private final Uri mFilesUriNoNotify;
+ private final boolean mProcessPlaylists;
+ private final boolean mProcessGenres;
private int mMtpObjectHandle;
- private final String mExternalStoragePath;
- private final boolean mExternalIsEmulated;
+ private final AtomicBoolean mClosed = new AtomicBoolean();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
/** whether to use bulk inserts or individual inserts for each item */
private static final boolean ENABLE_BULK_INSERTS = true;
@@ -345,10 +349,6 @@ public class MediaScanner
*/
private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config.";
- // set to true if file path comparisons should be case insensitive.
- // this should be set when scanning files on a case insensitive file system.
- private boolean mCaseInsensitivePaths;
-
private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
private static class FileEntry {
@@ -378,26 +378,59 @@ public class MediaScanner
int bestmatchlevel;
}
- private ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<PlaylistEntry>();
+ private final ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<>();
+ private final ArrayList<FileEntry> mPlayLists = new ArrayList<>();
private MediaInserter mMediaInserter;
- private ArrayList<FileEntry> mPlayLists;
-
private DrmManagerClient mDrmManagerClient = null;
- public MediaScanner(Context c) {
+ public MediaScanner(Context c, String volumeName) {
native_setup();
mContext = c;
mPackageName = c.getPackageName();
+ mVolumeName = volumeName;
+
mBitmapOptions.inSampleSize = 1;
mBitmapOptions.inJustDecodeBounds = true;
setDefaultRingtoneFileNames();
- mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath();
- mExternalIsEmulated = Environment.isExternalStorageEmulated();
- //mClient.testGenreNameConverter();
+ mMediaProvider = mContext.getContentResolver()
+ .acquireContentProviderClient(MediaStore.AUTHORITY);
+
+ mAudioUri = Audio.Media.getContentUri(volumeName);
+ mVideoUri = Video.Media.getContentUri(volumeName);
+ mImagesUri = Images.Media.getContentUri(volumeName);
+ mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
+ mFilesUri = Files.getContentUri(volumeName);
+ mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
+
+ if (!volumeName.equals("internal")) {
+ // we only support playlists on external media
+ mProcessPlaylists = true;
+ mProcessGenres = true;
+ mPlaylistsUri = Playlists.getContentUri(volumeName);
+ } else {
+ mProcessPlaylists = false;
+ mProcessGenres = false;
+ mPlaylistsUri = null;
+ }
+
+ final Locale locale = mContext.getResources().getConfiguration().locale;
+ if (locale != null) {
+ String language = locale.getLanguage();
+ String country = locale.getCountry();
+ if (language != null) {
+ if (country != null) {
+ setLocale(language + "_" + country);
+ } else {
+ setLocale(language);
+ }
+ }
+ }
+
+ mCloseGuard.open("close");
}
private void setDefaultRingtoneFileNames() {
@@ -956,7 +989,7 @@ public class MediaScanner
if (inserter != null) {
inserter.flushAll();
}
- result = mMediaProvider.insert(mPackageName, tableUri, values);
+ result = mMediaProvider.insert(tableUri, values);
} else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
inserter.insertwithPriority(tableUri, values);
} else {
@@ -988,7 +1021,7 @@ public class MediaScanner
}
values.put(FileColumns.MEDIA_TYPE, mediaType);
}
- mMediaProvider.update(mPackageName, result, values, null, null);
+ mMediaProvider.update(result, values, null, null);
}
if(needToSetSettings) {
@@ -1055,11 +1088,7 @@ public class MediaScanner
String where = null;
String[] selectionArgs = null;
- if (mPlayLists == null) {
- mPlayLists = new ArrayList<FileEntry>();
- } else {
- mPlayLists.clear();
- }
+ mPlayLists.clear();
if (filePath != null) {
// query for only one file
@@ -1077,8 +1106,7 @@ public class MediaScanner
// filesystem is mounted and unmounted while the scanner is running).
Uri.Builder builder = mFilesUri.buildUpon();
builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false");
- MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, mPackageName,
- builder.build());
+ MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, builder.build());
// Build the list of files from the content provider
try {
@@ -1097,7 +1125,7 @@ public class MediaScanner
c.close();
c = null;
}
- c = mMediaProvider.query(mPackageName, limitUri, FILES_PRESCAN_PROJECTION,
+ c = mMediaProvider.query(limitUri, FILES_PRESCAN_PROJECTION,
where, selectionArgs, MediaStore.Files.FileColumns._ID, null);
if (c == null) {
break;
@@ -1138,8 +1166,7 @@ public class MediaScanner
if (path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
deleter.flush();
String parent = new File(path).getParent();
- mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL,
- parent, null);
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, parent, null);
}
}
}
@@ -1157,7 +1184,7 @@ public class MediaScanner
// compute original size of images
mOriginalCount = 0;
- c = mMediaProvider.query(mPackageName, mImagesUri, ID_PROJECTION, null, null, null, null);
+ c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null, null);
if (c != null) {
mOriginalCount = c.getCount();
c.close();
@@ -1189,7 +1216,6 @@ public class MediaScanner
try {
c = mMediaProvider.query(
- mPackageName,
mThumbsUri,
new String [] { "_data" },
null,
@@ -1225,13 +1251,11 @@ public class MediaScanner
static class MediaBulkDeleter {
StringBuilder whereClause = new StringBuilder();
ArrayList<String> whereArgs = new ArrayList<String>(100);
- final IContentProvider mProvider;
- final String mPackageName;
+ final ContentProviderClient mProvider;
final Uri mBaseUri;
- public MediaBulkDeleter(IContentProvider provider, String packageName, Uri baseUri) {
+ public MediaBulkDeleter(ContentProviderClient provider, Uri baseUri) {
mProvider = provider;
- mPackageName = packageName;
mBaseUri = baseUri;
}
@@ -1250,7 +1274,7 @@ public class MediaScanner
if (size > 0) {
String [] foo = new String [size];
foo = whereArgs.toArray(foo);
- int numrows = mProvider.delete(mPackageName, mBaseUri,
+ int numrows = mProvider.delete(mBaseUri,
MediaStore.MediaColumns._ID + " IN (" +
whereClause.toString() + ")", foo);
//Log.i("@@@@@@@@@", "rows deleted: " + numrows);
@@ -1271,48 +1295,26 @@ public class MediaScanner
pruneDeadThumbnailFiles();
// allow GC to clean up
- mPlayLists = null;
- mMediaProvider = null;
+ mPlayLists.clear();
}
private void releaseResources() {
// release the DrmManagerClient resources
if (mDrmManagerClient != null) {
- mDrmManagerClient.release();
+ mDrmManagerClient.close();
mDrmManagerClient = null;
}
}
- private void initialize(String volumeName) {
- mMediaProvider = mContext.getContentResolver().acquireProvider("media");
-
- mAudioUri = Audio.Media.getContentUri(volumeName);
- mVideoUri = Video.Media.getContentUri(volumeName);
- mImagesUri = Images.Media.getContentUri(volumeName);
- mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
- mFilesUri = Files.getContentUri(volumeName);
- mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
-
- if (!volumeName.equals("internal")) {
- // we only support playlists on external media
- mProcessPlaylists = true;
- mProcessGenres = true;
- mPlaylistsUri = Playlists.getContentUri(volumeName);
-
- mCaseInsensitivePaths = true;
- }
- }
-
- public void scanDirectories(String[] directories, String volumeName) {
+ public void scanDirectories(String[] directories) {
try {
long start = System.currentTimeMillis();
- initialize(volumeName);
prescan(null, true);
long prescan = System.currentTimeMillis();
if (ENABLE_BULK_INSERTS) {
// create MediaInserter for bulk inserts
- mMediaInserter = new MediaInserter(mMediaProvider, mPackageName, 500);
+ mMediaInserter = new MediaInserter(mMediaProvider, 500);
}
for (int i = 0; i < directories.length; i++) {
@@ -1349,9 +1351,8 @@ public class MediaScanner
}
// this function is used to scan a single file
- public Uri scanSingleFile(String path, String volumeName, String mimeType) {
+ public Uri scanSingleFile(String path, String mimeType) {
try {
- initialize(volumeName);
prescan(path, true);
File file = new File(path);
@@ -1464,8 +1465,7 @@ public class MediaScanner
return isNoMediaFile(path);
}
- public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
- initialize(volumeName);
+ public void scanMtpFile(String path, int objectHandle, int format) {
MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
File file = new File(path);
@@ -1481,7 +1481,7 @@ public class MediaScanner
values.put(Files.FileColumns.DATE_MODIFIED, lastModifiedSeconds);
try {
String[] whereArgs = new String[] { Integer.toString(objectHandle) };
- mMediaProvider.update(mPackageName, Files.getMtpObjectsUri(volumeName), values,
+ mMediaProvider.update(Files.getMtpObjectsUri(mVolumeName), values,
"_id=?", whereArgs);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in scanMtpFile", e);
@@ -1498,7 +1498,7 @@ public class MediaScanner
FileEntry entry = makeEntryFor(path);
if (entry != null) {
- fileList = mMediaProvider.query(mPackageName, mFilesUri,
+ fileList = mMediaProvider.query(mFilesUri,
FILES_PRESCAN_PROJECTION, null, null, null, null);
processPlayList(entry, fileList);
}
@@ -1529,7 +1529,7 @@ public class MediaScanner
try {
where = Files.FileColumns.DATA + "=?";
selectionArgs = new String[] { path };
- c = mMediaProvider.query(mPackageName, mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
+ c = mMediaProvider.query(mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
where, selectionArgs, null, null);
if (c.moveToFirst()) {
long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
@@ -1641,7 +1641,7 @@ public class MediaScanner
values.clear();
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index));
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(entry.bestmatchid));
- mMediaProvider.insert(mPackageName, playlistUri, values);
+ mMediaProvider.insert(playlistUri, values);
index++;
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.processCachedPlaylist()", e);
@@ -1806,16 +1806,16 @@ public class MediaScanner
if (rowId == 0) {
values.put(MediaStore.Audio.Playlists.DATA, path);
- uri = mMediaProvider.insert(mPackageName, mPlaylistsUri, values);
+ uri = mMediaProvider.insert(mPlaylistsUri, values);
rowId = ContentUris.parseId(uri);
membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
} else {
uri = ContentUris.withAppendedId(mPlaylistsUri, rowId);
- mMediaProvider.update(mPackageName, uri, values, null, null);
+ mMediaProvider.update(uri, values, null, null);
// delete members of existing playlist
membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
- mMediaProvider.delete(mPackageName, membersUri, null, null);
+ mMediaProvider.delete(membersUri, null, null);
}
String playListDirectory = path.substring(0, lastSlash + 1);
@@ -1837,7 +1837,7 @@ public class MediaScanner
try {
// use the files uri and projection because we need the format column,
// but restrict the query to just audio files
- fileList = mMediaProvider.query(mPackageName, mFilesUri, FILES_PRESCAN_PROJECTION,
+ fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
"media_type=2", null, null, null);
while (iterator.hasNext()) {
FileEntry entry = iterator.next();
@@ -1856,7 +1856,7 @@ public class MediaScanner
private native void processDirectory(String path, MediaScannerClient client);
private native void processFile(String path, String mimeType, MediaScannerClient client);
- public native void setLocale(String locale);
+ private native void setLocale(String locale);
public native byte[] extractAlbumArt(FileDescriptor fd);
@@ -1864,19 +1864,22 @@ public class MediaScanner
private native final void native_setup();
private native final void native_finalize();
- /**
- * Releases resources associated with this MediaScanner object.
- * It is considered good practice to call this method when
- * one is done using the MediaScanner object. After this method
- * is called, the MediaScanner object can no longer be used.
- */
- public void release() {
- native_finalize();
+ @Override
+ public void close() {
+ mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
+ mMediaProvider.close();
+ native_finalize();
+ }
}
@Override
- protected void finalize() {
- mContext.getContentResolver().releaseProvider(mMediaProvider);
- native_finalize();
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
+ }
}
}
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 3541fba7f3b1..bc96e2ea8989 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -17,9 +17,9 @@
package android.mtp;
import android.content.BroadcastReceiver;
-import android.content.Context;
+import android.content.ContentProviderClient;
import android.content.ContentValues;
-import android.content.IContentProvider;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
@@ -37,23 +37,30 @@ import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
+import dalvik.system.CloseGuard;
+
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* {@hide}
*/
-public class MtpDatabase {
-
+public class MtpDatabase implements AutoCloseable {
private static final String TAG = "MtpDatabase";
private final Context mContext;
private final String mPackageName;
- private final IContentProvider mMediaProvider;
+ private final ContentProviderClient mMediaProvider;
private final String mVolumeName;
private final Uri mObjectsUri;
+ private final MediaScanner mMediaScanner;
+
+ private final AtomicBoolean mClosed = new AtomicBoolean();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
// path to primary storage
private final String mMediaStoragePath;
// if not null, restrict all queries to these subdirectories
@@ -120,7 +127,6 @@ public class MtpDatabase {
private static final String STORAGE_FORMAT_PARENT_WHERE = STORAGE_FORMAT_WHERE + " AND "
+ Files.FileColumns.PARENT + "=?";
- private final MediaScanner mMediaScanner;
private MtpServer mServer;
// read from native code
@@ -156,11 +162,12 @@ public class MtpDatabase {
mContext = context;
mPackageName = context.getPackageName();
- mMediaProvider = context.getContentResolver().acquireProvider("media");
+ mMediaProvider = context.getContentResolver()
+ .acquireContentProviderClient(MediaStore.AUTHORITY);
mVolumeName = volumeName;
mMediaStoragePath = storagePath;
mObjectsUri = Files.getMtpObjectsUri(volumeName);
- mMediaScanner = new MediaScanner(context);
+ mMediaScanner = new MediaScanner(context, mVolumeName);
mSubDirectories = subDirectories;
if (subDirectories != null) {
@@ -187,20 +194,9 @@ public class MtpDatabase {
}
}
- // Set locale to MediaScanner.
- Locale locale = context.getResources().getConfiguration().locale;
- if (locale != null) {
- String language = locale.getLanguage();
- String country = locale.getCountry();
- if (language != null) {
- if (country != null) {
- mMediaScanner.setLocale(language + "_" + country);
- } else {
- mMediaScanner.setLocale(language);
- }
- }
- }
initDeviceProperties(context);
+
+ mCloseGuard.open("close");
}
public void setServer(MtpServer server) {
@@ -221,9 +217,20 @@ public class MtpDatabase {
}
@Override
+ public void close() {
+ mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
+ mMediaScanner.close();
+ mMediaProvider.close();
+ native_finalize();
+ }
+ }
+
+ @Override
protected void finalize() throws Throwable {
try {
- native_finalize();
+ mCloseGuard.warnIfOpen();
+ close();
} finally {
super.finalize();
}
@@ -334,7 +341,7 @@ public class MtpDatabase {
if (path != null) {
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, PATH_WHERE,
+ c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE,
new String[] { path }, null, null);
if (c != null && c.getCount() > 0) {
Log.w(TAG, "file already exists in beginSendObject: " + path);
@@ -359,7 +366,7 @@ public class MtpDatabase {
values.put(Files.FileColumns.DATE_MODIFIED, modified);
try {
- Uri uri = mMediaProvider.insert(mPackageName, mObjectsUri, values);
+ Uri uri = mMediaProvider.insert(mObjectsUri, values);
if (uri != null) {
return Integer.parseInt(uri.getPathSegments().get(2));
} else {
@@ -394,13 +401,13 @@ public class MtpDatabase {
values.put(Files.FileColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
values.put(MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, handle);
try {
- Uri uri = mMediaProvider.insert(mPackageName,
+ Uri uri = mMediaProvider.insert(
Audio.Playlists.EXTERNAL_CONTENT_URI, values);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in endSendObject", e);
}
} else {
- mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
+ mMediaScanner.scanMtpFile(path, handle, format);
}
} else {
deleteFile(handle);
@@ -503,7 +510,7 @@ public class MtpDatabase {
}
}
- return mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, where,
+ return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where,
whereArgs, null, null);
}
@@ -721,7 +728,7 @@ public class MtpDatabase {
propertyGroup = mPropertyGroupsByFormat.get(format);
if (propertyGroup == null) {
int[] propertyList = getSupportedObjectProperties(format);
- propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
+ propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
mVolumeName, propertyList);
mPropertyGroupsByFormat.put(new Integer(format), propertyGroup);
}
@@ -729,7 +736,7 @@ public class MtpDatabase {
propertyGroup = mPropertyGroupsByProperty.get(property);
if (propertyGroup == null) {
int[] propertyList = new int[] { (int)property };
- propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
+ propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
mVolumeName, propertyList);
mPropertyGroupsByProperty.put(new Integer((int)property), propertyGroup);
}
@@ -745,7 +752,7 @@ public class MtpDatabase {
String path = null;
String[] whereArgs = new String[] { Integer.toString(handle) };
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_PROJECTION, ID_WHERE,
+ c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE,
whereArgs, null, null);
if (c != null && c.moveToNext()) {
path = c.getString(1);
@@ -788,7 +795,7 @@ public class MtpDatabase {
try {
// note - we are relying on a special case in MediaProvider.update() to update
// the paths for all children in the case where this is a directory.
- updated = mMediaProvider.update(mPackageName, mObjectsUri, values, ID_WHERE, whereArgs);
+ updated = mMediaProvider.update(mObjectsUri, values, ID_WHERE, whereArgs);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in mMediaProvider.update", e);
}
@@ -805,7 +812,7 @@ public class MtpDatabase {
if (oldFile.getName().startsWith(".") && !newPath.startsWith(".")) {
// directory was unhidden
try {
- mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, newPath, null);
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, newPath, null);
} catch (RemoteException e) {
Log.e(TAG, "failed to unhide/rescan for " + newPath);
}
@@ -815,7 +822,7 @@ public class MtpDatabase {
if (oldFile.getName().toLowerCase(Locale.US).equals(".nomedia")
&& !newPath.toLowerCase(Locale.US).equals(".nomedia")) {
try {
- mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
} catch (RemoteException e) {
Log.e(TAG, "failed to unhide/rescan for " + newPath);
}
@@ -886,7 +893,7 @@ public class MtpDatabase {
char[] outName, long[] outCreatedModified) {
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, OBJECT_INFO_PROJECTION,
+ c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
outStorageFormatParent[0] = c.getInt(1);
@@ -933,7 +940,7 @@ public class MtpDatabase {
}
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
+ c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
String path = c.getString(1);
@@ -960,7 +967,7 @@ public class MtpDatabase {
private int getObjectFormat(int handle) {
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, FORMAT_PROJECTION,
+ c = mMediaProvider.query(mObjectsUri, FORMAT_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
return c.getInt(1);
@@ -984,7 +991,7 @@ public class MtpDatabase {
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
+ c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
// don't convert to media path here, since we will be matching
@@ -1007,7 +1014,7 @@ public class MtpDatabase {
if (format == MtpConstants.FORMAT_ASSOCIATION) {
// recursive case - delete all children first
Uri uri = Files.getMtpObjectsUri(mVolumeName);
- int count = mMediaProvider.delete(mPackageName, uri,
+ int count = mMediaProvider.delete(uri,
// the 'like' makes it use the index, the 'lower()' makes it correct
// when the path contains sqlite wildcard characters
"_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
@@ -1015,12 +1022,12 @@ public class MtpDatabase {
}
Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
- if (mMediaProvider.delete(mPackageName, uri, null, null) > 0) {
+ if (mMediaProvider.delete(uri, null, null) > 0) {
if (format != MtpConstants.FORMAT_ASSOCIATION
&& path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
try {
String parentPath = path.substring(0, path.lastIndexOf("/"));
- mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, parentPath, null);
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, parentPath, null);
} catch (RemoteException e) {
Log.e(TAG, "failed to unhide/rescan for " + path);
}
@@ -1043,7 +1050,7 @@ public class MtpDatabase {
Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, uri, ID_PROJECTION, null, null, null, null);
+ c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null, null);
if (c == null) {
return null;
}
@@ -1077,7 +1084,7 @@ public class MtpDatabase {
valuesList[i] = values;
}
try {
- if (mMediaProvider.bulkInsert(mPackageName, uri, valuesList) > 0) {
+ if (mMediaProvider.bulkInsert(uri, valuesList) > 0) {
return MtpConstants.RESPONSE_OK;
}
} catch (RemoteException e) {
diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java
index c80adfa80fc9..dea300838385 100644
--- a/media/java/android/mtp/MtpPropertyGroup.java
+++ b/media/java/android/mtp/MtpPropertyGroup.java
@@ -16,7 +16,7 @@
package android.mtp;
-import android.content.IContentProvider;
+import android.content.ContentProviderClient;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
@@ -48,8 +48,7 @@ class MtpPropertyGroup {
}
private final MtpDatabase mDatabase;
- private final IContentProvider mProvider;
- private final String mPackageName;
+ private final ContentProviderClient mProvider;
private final String mVolumeName;
private final Uri mUri;
@@ -65,13 +64,12 @@ class MtpPropertyGroup {
private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND " + FORMAT_WHERE;
// constructs a property group for a list of properties
- public MtpPropertyGroup(MtpDatabase database, IContentProvider provider, String packageName,
- String volume, int[] properties) {
+ public MtpPropertyGroup(MtpDatabase database, ContentProviderClient provider, String volumeName,
+ int[] properties) {
mDatabase = database;
mProvider = provider;
- mPackageName = packageName;
- mVolumeName = volume;
- mUri = Files.getMtpObjectsUri(volume);
+ mVolumeName = volumeName;
+ mUri = Files.getMtpObjectsUri(volumeName);
int count = properties.length;
ArrayList<String> columns = new ArrayList<String>(count);
@@ -201,7 +199,7 @@ class MtpPropertyGroup {
Cursor c = null;
try {
// for now we are only reading properties from the "objects" table
- c = mProvider.query(mPackageName, mUri,
+ c = mProvider.query(mUri,
new String [] { Files.FileColumns._ID, column },
ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
@@ -221,7 +219,7 @@ class MtpPropertyGroup {
private String queryAudio(int id, String column) {
Cursor c = null;
try {
- c = mProvider.query(mPackageName, Audio.Media.getContentUri(mVolumeName),
+ c = mProvider.query(Audio.Media.getContentUri(mVolumeName),
new String [] { Files.FileColumns._ID, column },
ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
@@ -242,7 +240,7 @@ class MtpPropertyGroup {
Cursor c = null;
try {
Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
- c = mProvider.query(mPackageName, uri,
+ c = mProvider.query(uri,
new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
null, null, null, null);
if (c != null && c.moveToNext()) {
@@ -264,7 +262,7 @@ class MtpPropertyGroup {
Cursor c = null;
try {
// for now we are only reading properties from the "objects" table
- c = mProvider.query(mPackageName, mUri,
+ c = mProvider.query(mUri,
new String [] { Files.FileColumns._ID, column },
ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
@@ -335,7 +333,7 @@ class MtpPropertyGroup {
try {
// don't query if not necessary
if (depth > 0 || handle == 0xFFFFFFFF || mColumns.length > 1) {
- c = mProvider.query(mPackageName, mUri, mColumns, where, whereArgs, null, null);
+ c = mProvider.query(mUri, mColumns, where, whereArgs, null, null);
if (c == null) {
return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
index 05df014ad611..06efa906af04 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
@@ -16,6 +16,7 @@
package com.android.mediaframeworktest.unit;
+import android.content.ContentProviderClient;
import android.content.ContentValues;
import android.content.IContentProvider;
import android.media.MediaInserter;
@@ -81,8 +82,9 @@ public class MediaInserterTest extends InstrumentationTestCase {
protected void setUp() throws Exception {
super.setUp();
mMockProvider = EasyMock.createMock(IContentProvider.class);
- mMediaInserter = new MediaInserter(mMockProvider,
- mPackageName, TEST_BUFFER_SIZE);
+ final ContentProviderClient client = new ContentProviderClient(
+ getInstrumentation().getContext().getContentResolver(), mMockProvider, true);
+ mMediaInserter = new MediaInserter(client, TEST_BUFFER_SIZE);
mPackageName = getInstrumentation().getContext().getPackageName();
mFilesCounter = 0;
mAudioCounter = 0;
diff --git a/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml b/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
index ac20aedbfb0d..23688aec9ace 100644
--- a/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
@@ -18,10 +18,10 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="backup_confirm_title" msgid="827563724209303345">"完全备份"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"完全还原"</string>
- <string name="backup_confirm_text" msgid="1878021282758896593">"系统请求将所有数据完整备份至已连接的桌面计算机。允许此操作吗?\n\n如果您本人未要求备份,请阻止该操作。"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"系统请求将所有数据完整备份至已连接的桌面设备。允许此操作吗?\n\n如果您本人未要求备份,请阻止该操作。"</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"备份我的数据"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"不备份"</string>
- <string name="restore_confirm_text" msgid="7499866728030461776">"系统请求从连接的桌面计算机完整还原所有数据。允许此操作吗?\n\n如果您本人未要求还原,请阻止该操作。该操作会覆盖设备上当前的所有数据!"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"系统请求从连接的桌面设备完整还原所有数据。允许此操作吗?\n\n如果您本人未要求还原,请阻止该操作。该操作会覆盖设备上当前的所有数据!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"恢复我的数据"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"不恢复"</string>
<string name="current_password_text" msgid="8268189555578298067">"请在下方输入您的当前备份密码:"</string>
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png
deleted file mode 100644
index 2b21c12d671d..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index ed3ee454dfa2..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index 1a3ebc47fb4d..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index 3086a6923f2d..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index b86f0f7322db..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 9d0988da305e..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index 6c3136030d6f..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 1450ff03d7d7..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index 4ad54bb63c97..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 7f7c6361c34b..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png
deleted file mode 100644
index d867847e9174..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index 545976765809..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 0cbd992aaad9..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index db4670259ff3..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index b9f7af5754d5..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 1218c2f7b432..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 46d755f212ef..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index 933570bb7469..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 30cea25f1fc2..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png
deleted file mode 100644
index 67b60ded5656..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 65e42aa4a196..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png
deleted file mode 100644
index ac27eea8de76..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index a4add51490af..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index a9a7f2014284..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index 26beb794a792..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index ed9cab7294de..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 451d2873279e..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index 7bc02c948618..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index de39cd461c02..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index c3eb8456549e..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 97f6e5071dee..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png
deleted file mode 100644
index b2f043f8a81d..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index 483d7fb4d184..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 2941b8a70135..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index d3ac07264dc5..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index a43f9022a4bc..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index c572cd1cbbf2..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 7ae671ba1c7a..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index a5ebd513292b..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 89ac4340bcda..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png
deleted file mode 100644
index 855c44b329d8..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 1de8292c0721..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png
deleted file mode 100644
index 4203d35614c1..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index 41558f251fd6..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index e190c4d4207e..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index fabc8c3505e6..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index d8ba6e0be330..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 1b5111a577a4..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index e7b7460dd8c5..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 3183bfca62da..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index 9a4e844f5ff2..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 96d5721866c7..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png
deleted file mode 100644
index 23a130236996..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index b0811f18ebbe..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 5f1f53761805..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index 8083584eb8d2..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index 898e26ae0092..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 2e9c66721413..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 56951c3cad10..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index 08ed9f0888e9..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index cd64e56b4c42..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png
deleted file mode 100644
index 0bc40deb6a75..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 00b8a8b719d8..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png
deleted file mode 100644
index 60f59f532abd..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index 6006b1207e3c..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index 7926188aa0fd..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index e65d74c2a008..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index 7d32801f79d4..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index d528708242f5..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index 274c52468599..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 6053b0a65213..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index 78ee13b3ca7e..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index dcf9cc265354..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png
deleted file mode 100644
index 74fbbbc5de9b..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index 11a219afc3f6..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 9a461c96f785..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index 9a67956b6288..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index 853aa8c0ccbc..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 84ae9aef1760..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 111439e86b03..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index b876f86d7f3c..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 7cf656a5bf0b..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png
deleted file mode 100644
index acc3d7b29af0..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 52367749f8d4..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png
deleted file mode 100644
index d2dd494d2718..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index 4f935bf59b26..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index 7499cbc6d24e..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index ca129289f408..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index c4afa37bc362..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 0b0aa040736c..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index ebd0535a884d..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 29cdbb7ad7df..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index ca349b659fe5..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 02249d2058da..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png
deleted file mode 100644
index 469b911bc1ee..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index ef479c3c897e..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 3168d6f78e95..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index 9bb4d66d9493..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index 88ba9ad5daff..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 5fe18da00879..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 1d05f6f58ad0..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index c2308fe0253f..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 9a173bef611d..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png
deleted file mode 100644
index a564f5a76db0..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index c7daa2a6fcaf..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_album.xml b/packages/DocumentsUI/res/drawable/ic_doc_album.xml
index e7965e621b05..1ce3f023dfb7 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_album.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_album.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_album_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10,-4.48 10,-10S17.52 2 12 2zm0 14.5c-2.49 0,-4.5,-2.01,-4.5,-4.5S9.51 7.5 12 7.5s4.5 2.01 4.5 4.5,-2.01 4.5,-4.5 4.5zm0,-5.5c-.55 0,-1 .45,-1 1s.45 1 1 1 1,-.45 1,-1,-.45,-1,-1,-1z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_apk.xml b/packages/DocumentsUI/res/drawable/ic_doc_apk.xml
index 4f8f06e86bb7..197445ef598d 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_apk.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_apk.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_apk_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5V19h1c.55 0 1,-.45 1,-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0,-1.5.67,-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5v-7c0,-.83,-.67,-1.5,-1.5,-1.5zm-4.97,-5.84l1.3,-1.3c.2,-.2.2,-.51 0,-.71,-.2,-.2,-.51,-.2,-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0,-1.86.23,-2.66.63L7.85.15c-.2,-.2,-.51,-.2,-.71 0,-.2.2,-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0,-1.99,-.97,-3.75,-2.47,-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
index cf18b4f0e2f6..454eea3bbad9 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_audio_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFDB4437"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zM7.2 18c-.66 0,-1.2,-.54,-1.2,-1.2V12c0,-3.31 2.69,-6 6,-6s6 2.69 6 6v4.8c0 .66,-.54 1.2,-1.2 1.2H14v-4h2v-2c0,-2.21,-1.79,-4,-4,-4s-4 1.79,-4 4v2h2v4H7.2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml b/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml
index c28ed4fe44df..b99baf6f4cd3 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_certificate_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M17.81 4.47c-.08 0,-.16,-.02,-.23,-.06C15.66 3.42 14 3 12.01 3c-1.98 0,-3.86.47,-5.57 1.41,-.24.13,-.54.04,-.68,-.2,-.13,-.24,-.04,-.55.2,-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67,-.09.18,-.26.28,-.44.28zM3.5 9.72c-.1 0,-.2,-.03,-.29,-.09,-.23,-.16,-.28,-.47,-.12,-.7.99,-1.4 2.25,-2.5 3.75,-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54,-.12.7,-.23.16,-.54.11,-.7,-.12,-.9,-1.26,-2.04,-2.25,-3.39,-2.94,-2.87,-1.47,-6.54,-1.47,-9.4.01,-1.36.7,-2.5 1.7,-3.4 2.96,-.08.14,-.23.21,-.39.21zm6.25 12.07c-.13 0,-.26,-.05,-.35,-.15,-.87,-.87,-1.34,-1.43,-2.01,-2.64,-.69,-1.23,-1.05,-2.73,-1.05,-4.34 0,-2.97 2.54,-5.39 5.66,-5.39s5.66 2.42 5.66 5.39c0 .28,-.22.5,-.5.5s-.5,-.22,-.5,-.5c0,-2.42,-2.09,-4.39,-4.66,-4.39,-2.57 0,-4.66 1.97,-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71,-.11.1,-.24.15,-.37.15zm7.17,-1.85c-1.19 0,-2.24,-.3,-3.1,-.89,-1.49,-1.01,-2.38,-2.65,-2.38,-4.39 0,-.28.22,-.5.5,-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64,-.03 1.04,-.1.27,-.05.53.13.58.41.05.27,-.13.53,-.41.58,-.57.11,-1.07.12,-1.21.12zM14.91 22c-.04 0,-.09,-.01,-.13,-.02,-1.59,-.44,-2.63,-1.03,-3.72,-2.1,-1.4,-1.39,-2.17,-3.24,-2.17,-5.22 0,-1.62 1.38,-2.94 3.08,-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08,-.87 2.08,-1.94c0,-3.77,-3.25,-6.83,-7.25,-6.83,-2.84 0,-5.44 1.58,-6.61 4.03,-.39.81,-.59 1.76,-.59 2.8 0 .78.07 2.01.67 3.61.1.26,-.03.55,-.29.64,-.26.1,-.55,-.04,-.64,-.29,-.49,-1.31,-.73,-2.61,-.73,-3.96 0,-1.2.23,-2.29.68,-3.24 1.33,-2.79 4.28,-4.6 7.51,-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62,-1.38 2.94,-3.08 2.94s-3.08,-1.32,-3.08,-2.94c0,-1.07,-.93,-1.94,-2.08,-1.94s-2.08.87,-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61,-.05.23,-.26.38,-.47.38z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_codes.xml b/packages/DocumentsUI/res/drawable/ic_doc_codes.xml
index 0de721a90002..ea1c464890e7 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_codes.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_codes.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_codes_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M9.4 16.6L4.8 12l4.6,-4.6L8 6l-6 6 6 6 1.4,-1.4zm5.2 0l4.6,-4.6,-4.6,-4.6L16 6l6 6,-6 6,-1.4,-1.4z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml b/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml
index a49cfa42438c..e0eb669af33a 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_compressed_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-5 6h-2v2h2v2h-2v-2h-2V9h2V7h-2V5h2v2h2v2zm0 8h-2v-2h-2v-2h2v2h2v2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_contact.xml b/packages/DocumentsUI/res/drawable/ic_doc_contact.xml
index bf550cbf0780..a77cb6ba1152 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_contact.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_contact.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_doc_contact_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M19 3H5c-1.11 0,-2 .89,-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.11,-.9,-2,-2,-2zm-7 3c1.65 0 3 1.35 3 3 0 1.66,-1.35 3,-3 3s-3,-1.34,-3,-3c0,-1.65 1.35,-3 3,-3zm6 12H6v-1c0,-2 4,-3.1 6,-3.1s6 1.1 6 3.1v1z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_document.xml b/packages/DocumentsUI/res/drawable/ic_doc_document.xml
new file mode 100644
index 000000000000..29251ad799f0
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_doc_document.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF4883F3"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-1.99 6H7V7h10.01v2zm0 4H7v-2h10.01v2zm-3 4H7v-2h7.01v2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_event.xml b/packages/DocumentsUI/res/drawable/ic_doc_event.xml
index 25cf0f35c7f9..113f079c8670 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_event.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_event.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_doc_event_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0,-1.99.9,-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2h-1V1h-2zm3 18H5V8h14v11z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_excel.xml b/packages/DocumentsUI/res/drawable/ic_doc_excel.xml
index 33547250e755..3ed27e1f7f62 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_excel.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_excel.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_excel_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF16A765"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-2.8 14h-2L12 13.2 9.8 17h-2l3.2,-5,-3.2,-5h2l2.2 3.8L14.2 7h2L13 12l3.2 5z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_folder.xml b/packages/DocumentsUI/res/drawable/ic_doc_folder.xml
index 73de60e99ade..dcbce010810e 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_folder.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_folder.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_folder_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ 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_doc_font.xml b/packages/DocumentsUI/res/drawable/ic_doc_font.xml
index c74cb9ca07e6..4c13d71e47d0 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_font.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_font.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_font_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M9.93 13.5h4.14L12 7.98zM20 2H4c-1.1 0,-2 .9,-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V4c0,-1.1,-.9,-2,-2,-2zm-4.05 16.5l-1.14,-3H9.17l-1.12 3H5.96l5.11,-13h1.86l5.11 13h-2.09z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_generic.xml b/packages/DocumentsUI/res/drawable/ic_doc_generic.xml
index a4ee29d6db5b..006dfba4a3bb 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_generic.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_generic.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_doc_generic_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M6 2c-1.1 0,-1.99.9,-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2,-.9 2,-2V8l-6,-6H6zm7 7V3.5L18.5 9H13z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_image.xml b/packages/DocumentsUI/res/drawable/ic_doc_image.xml
index 9d4c3591a2b7..23953f71fd5e 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_image.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_image.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_image_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFDB4437"
+ android:pathData="M21 19V5c0,-1.1,-.9,-2,-2,-2H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5,-4.5z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml b/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml
index 5c3749892833..b2d01938c480 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_pdf_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFDB4437"
+ android:pathData="M7 11.5h1v-1H7v1zM19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-9.5 8.5c0 .83,-.67 1.5,-1.5 1.5H7v2H5.5V9H8c.83 0 1.5.67 1.5 1.5v1zm10,-1H17v1h1.5V13H17v2h-1.5V9h4v1.5zm-5 3c0 .83,-.67 1.5,-1.5 1.5h-2.5V9H13c.83 0 1.5.67 1.5 1.5v3zm-2.5 0h1v-3h-1v3z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml b/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml
index f0a6c3935eec..aa5bfc818692 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_powerpoint_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFF7537"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zM9.8 13.4V17H8V7h4.3c1.53 0 2.15.3 2.8.89.65.59.9 1.37.9 2.34 0 1.02,-.26 1.8,-.9 2.35s-1.3.82,-2.8.82H9.8zm0,-1.4V8.4h2.3c.66 0 1.17.25 1.5.6.33.35.5.72.5 1.25 0 .55,-.18.95,-.5 1.25,-.32.31,-.7.5,-1.38.5H9.8z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml b/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml
index a14f86601753..7937bc12aa3b 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_presentation_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFF4B400"
+ android:pathData="M19 3H5c-1.1 0,-1.99.9,-1.99 2v14c0 1.1.89 2 1.99 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm0 13H5V8h14v8z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml b/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml
index 40f25152af6b..1663c0a1ae1b 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.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_doc_spreadsheet_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF16A765"
+ android:pathData="M19 3H5c-1.1 0,-1.99.9,-1.99 2L3 8v11c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm0 8h-8v8H9v-8H5V9h4V5h2v4h8v2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_text.xml b/packages/DocumentsUI/res/drawable/ic_doc_text.xml
index ffa9e70b16e9..7fc04e811b1c 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_text.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_text.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_doc_text_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M14 2H6c-1.1 0,-1.99.9,-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2,-.9 2,-2V8l-6,-6zm2 16H8v-2h8v2zm0,-4H8v-2h8v2zm-3,-5V3.5L18.5 9H13z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_video.xml b/packages/DocumentsUI/res/drawable/ic_doc_video.xml
index 2d048c2ffb93..ad4dae89ccdc 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_video.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_video.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_doc_video_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFDB4437"
+ android:pathData="M18 4l2 4h-3l-2,-4h-2l2 4h-3l-2,-4H8l2 4H7L5 4H4c-1.1 0,-1.99.9,-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V4h-4z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_word.xml b/packages/DocumentsUI/res/drawable/ic_doc_word.xml
index afcc533ecf55..7a3a0ec9b5e0 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_word.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_word.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_word_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF4883F3"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-3.5 14H14l-2,-7.5,-2 7.5H8.5L6.1 7h1.7l1.54 7.51L11.3 7h1.4l1.97 7.51L16.2 7h1.7l-2.4 10z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml b/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml
deleted file mode 100644
index 27cfa81dd847..000000000000
--- a/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_root_sdcard_alpha"
- android:tint="?android:attr/colorControlNormal" />
diff --git a/packages/SystemUI/res/drawable/docked_divider_handle.xml b/packages/DocumentsUI/res/drawable/ic_root_smartphone.xml
index 84c0343185ac..3021b16371ad 100644
--- a/packages/SystemUI/res/drawable/docked_divider_handle.xml
+++ b/packages/DocumentsUI/res/drawable/ic_root_smartphone.xml
@@ -1,7 +1,7 @@
<!--
Copyright (C) 2015 The Android Open Source Project
- Licensed under the Apache License, Version 2 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -13,10 +13,12 @@ Copyright (C) 2015 The Android Open Source Project
See the License for the specific language governing permissions and
limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <size android:height="@dimen/docked_divider_handle_height"
- android:width="@dimen/docked_divider_handle_width" />
- <corners android:radius="1dp" />
- <solid android:color="@color/docked_divider_handle" />
-</shape> \ No newline at end of file
+<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="#FF000000"
+ android:pathData="M17 1.01L7 1c-1.1 0,-2 .9,-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2,-.9 2,-2V3c0,-1.1,-.9,-1.99,-2,-1.99zM17 19H7V5h10v14z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/layout/item_dir_grid.xml b/packages/DocumentsUI/res/layout/item_dir_grid.xml
new file mode 100644
index 000000000000..c17b4c88d8a1
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_dir_grid.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/grid_item_margin"
+ android:background="@color/item_doc_background"
+ android:elevation="5dp"
+ android:focusable="true">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:paddingLeft="12dp"
+ android:paddingRight="12dp">
+
+ <ImageView
+ android:src="@drawable/ic_doc_folder"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="8dp"
+ android:scaleType="centerInside"
+ android:contentDescription="@null"/>
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="middle"
+ android:textAlignment="viewStart"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="@*android:color/primary_text_default_material_light" />
+
+ </LinearLayout>
+
+ <!-- An overlay that draws the item border when it is focused. -->
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:contentDescription="@null"
+ android:background="@drawable/item_doc_grid_border"
+ android:duplicateParentState="true" />
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index dcd5cfd16ce5..3c796bd6e776 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -19,6 +19,7 @@
android:layout_height="wrap_content"
android:layout_margin="@dimen/grid_item_margin"
android:background="@color/item_doc_background"
+ android:elevation="5dp"
android:focusable="true">
<!-- Main item thumbnail. Comprised of two overlapping images, the
@@ -39,9 +40,10 @@
<com.android.documentsui.GridItemThumbnail
android:id="@+id/icon_mime"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scaleType="centerInside"
+ android:layout_width="@dimen/icon_size"
+ android:layout_height="@dimen/icon_size"
+ android:layout_gravity="center"
+ android:scaleType="fitCenter"
android:contentDescription="@null" />
</FrameLayout>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 2d8be1bf6900..51cb77443741 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -26,7 +26,7 @@
<string name="menu_list" msgid="7279285939892417279">"Приказ на список"</string>
<string name="menu_sort" msgid="7677740407158414452">"Подреди по"</string>
<string name="menu_search" msgid="3816712084502856974">"Пребарај"</string>
- <string name="menu_settings" msgid="6008033148948428823">"Подесувања"</string>
+ <string name="menu_settings" msgid="6008033148948428823">"Поставки"</string>
<string name="menu_open" msgid="432922957274920903">"Отвори"</string>
<string name="menu_save" msgid="2394743337684426338">"Зачувај"</string>
<string name="menu_share" msgid="3075149983979628146">"Сподели"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index b522e0a00916..c303e0ca04a7 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -97,8 +97,8 @@
<string name="copy_failure_alert_content" msgid="3715575000297709082">"Faili hizi hazikunakiliwa: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="move_failure_alert_content" msgid="7151140279020481180">"Faili hizi hazikuhamishwa: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
- <item quantity="other">Alinakili faili <xliff:g id="COUNT_1">%1$d</xliff:g> kwenye ubaoklipu.</item>
- <item quantity="one">Alinakili faili <xliff:g id="COUNT_0">%1$d</xliff:g> kwenye ubaoklipu.</item>
+ <item quantity="other">Alinakili faili <xliff:g id="COUNT_1">%1$d</xliff:g> kwenye ubao wa kunakili.</item>
+ <item quantity="one">Alinakili faili <xliff:g id="COUNT_0">%1$d</xliff:g> kwenye ubao wa kunakili.</item>
</plurals>
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Haiwezi kubandika faili zilizochaguliwa katika eneo hili."</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/dimens.xml b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
index 83ceb556499f..2488fa26d544 100644
--- a/packages/DocumentsUI/res/values-sw720dp/dimens.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
@@ -18,5 +18,4 @@
<dimen name="grid_padding_horiz">16dp</dimen>
<dimen name="grid_padding_vert">16dp</dimen>
- <dimen name="grid_item_margin">8dp</dimen>
</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index a2eff3a734fd..a2416674f5de 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -810,11 +810,19 @@ public abstract class BaseActivity extends Activity {
* search currently.
*/
boolean cancelSearch() {
+ boolean collapsed = false;
+ boolean closed = false;
+
if (mActionBar.hasExpandedActionView()) {
mActionBar.collapseActionView();
- return true;
+ collapsed = true;
}
- return false;
+
+ if (isExpanded() || isSearching()) {
+ onClose();
+ closed = true;
+ }
+ return collapsed || closed;
}
boolean isSearching() {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 4eacee5bdaa9..6719b238326a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -114,11 +114,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
if (userMode != State.MODE_UNKNOWN) {
result.mode = userMode;
} else {
- if ((mDoc.flags & Document.FLAG_DIR_PREFERS_GRID) != 0) {
- result.mode = State.MODE_GRID;
- } else {
- result.mode = State.MODE_LIST;
- }
+ result.mode = State.MODE_GRID;
}
if (mUserSortOrder != State.SORT_ORDER_UNKNOWN) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index dd8ccf9d4df4..e308f3f35651 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -89,53 +89,51 @@ public class FilesActivity extends BaseActivity {
RootsFragment.show(getFragmentManager(), null);
+ final Intent intent = getIntent();
+ final Uri uri = intent.getData();
+
if (mState.restored) {
- if (DEBUG) Log.d(TAG, "Restored instance for uri: " + getIntent().getData());
+ if (DEBUG) Log.d(TAG, "Stack already resolved for uri: " + intent.getData());
onCurrentDirectoryChanged(ANIM_NONE);
- } else {
- Intent intent = getIntent();
- Uri uri = intent.getData();
-
- if (DEBUG) Log.d(TAG, "Creating new instance for uri: " + uri);
+ } 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
// loading or restoring the stack.
- if (!mState.stack.isEmpty()) {
- if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
- // When restoring from a stack, if a URI is present, it should only ever
- // be a launch URI. Launch URIs support sensible activity management, but
- // don't specify a real content target.
- checkState(uri == null || LauncherActivity.isLaunchUri(uri));
- onCurrentDirectoryChanged(ANIM_NONE);
- } 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(uri).executeOnExecutor(
- ProviderExecutor.forAuthority(uri.getAuthority()));
- } else {
- if (DEBUG) Log.d(TAG, "Launching into Home directory.");
- // If all else fails, try to load "Home" directory.
- uri = DocumentsContract.buildHomeUri();
- new RestoreRootTask(uri).executeOnExecutor(
- ProviderExecutor.forAuthority(uri.getAuthority()));
- }
+ //
+ // When restoring from a stack, if a URI is present, it should only ever
+ // be a launch URI. 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 || LauncherActivity.isLaunchUri(uri));
+ onCurrentDirectoryChanged(ANIM_NONE);
+ } 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(uri).executeOnExecutor(
+ ProviderExecutor.forAuthority(uri.getAuthority()));
+ } 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(homeUri).executeOnExecutor(
+ ProviderExecutor.forAuthority(homeUri.getAuthority()));
+ }
- // TODO: Ensure we're handling CopyService errors correctly across all activities.
- // Show a failure dialog if there was a failed operation.
- final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0);
- final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE,
- CopyService.TRANSFER_MODE_COPY);
- if (failure != 0) {
- final ArrayList<DocumentInfo> failedSrcList =
- intent.getParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST);
- FailureDialogFragment.show(
- getFragmentManager(),
- failure,
- failedSrcList,
- mState.stack,
- transferMode);
- }
+ final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0);
+ final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE,
+ CopyService.TRANSFER_MODE_COPY);
+ // DialogFragment takes care of restoring the dialog on configuration change.
+ // Only show it manually for the first time (icicle is null).
+ if (icicle == null && failure != 0) {
+ final ArrayList<DocumentInfo> failedSrcList =
+ intent.getParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST);
+ FailureDialogFragment.show(
+ getFragmentManager(),
+ failure,
+ failedSrcList,
+ mState.stack,
+ transferMode);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index a1213d210b50..c28fae85cb8b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -159,8 +159,8 @@ public class IconUtils {
add("application/vnd.sun.xml.calc.template", icon);
add("application/x-kspread", icon);
- // Text
- icon = R.drawable.ic_doc_text;
+ // Document
+ icon = R.drawable.ic_doc_document;
add("application/vnd.oasis.opendocument.text", icon);
add("application/vnd.oasis.opendocument.text-master", icon);
add("application/vnd.oasis.opendocument.text-template", icon);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index c81d4fbe0fb0..46372c00f872 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -36,7 +36,7 @@ public class State implements android.os.Parcelable {
/** Explicit user choice */
public int userMode = MODE_UNKNOWN;
/** Derived after loader */
- public int derivedMode = MODE_LIST;
+ public int derivedMode = MODE_GRID;
/** Explicit user choice */
public int userSortOrder = SORT_ORDER_UNKNOWN;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 035ae77cc5e5..9617582a1f3b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -53,6 +53,7 @@ import android.provider.DocumentsContract.Document;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
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;
@@ -99,18 +100,17 @@ 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.google.common.collect.Lists;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Set;
/**
* Display the documents inside a single directory.
*/
-public class DirectoryFragment extends Fragment {
+public class DirectoryFragment extends Fragment implements DocumentsAdapter.Environment {
public static final int TYPE_NORMAL = 1;
public static final int TYPE_SEARCH = 2;
@@ -126,7 +126,7 @@ public class DirectoryFragment extends Fragment {
private static final String TAG = "DirectoryFragment";
private static final int LOADER_ID = 42;
- private static final boolean DEBUG_ENABLE_DND = true;
+ static final boolean DEBUG_ENABLE_DND = true;
private static final String EXTRA_TYPE = "type";
private static final String EXTRA_ROOT = "root";
@@ -289,7 +289,11 @@ public class DirectoryFragment extends Fragment {
final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
- mAdapter = new DocumentsAdapter();
+ mIconHelper = new IconHelper(context, state.derivedMode);
+
+ mAdapter = new SectionBreakDocumentsAdapterWrapper(
+ this, new ModelBackedDocumentsAdapter(this, mIconHelper));
+
mRecView.setAdapter(mAdapter);
GestureDetector.SimpleOnGestureListener listener =
@@ -328,12 +332,13 @@ public class DirectoryFragment extends Fragment {
// into the selection manager.
mSelectionManager = new MultiSelectManager(
mRecView,
+ mAdapter,
state.allowMultiple
? MultiSelectManager.MODE_MULTIPLE
: MultiSelectManager.MODE_SINGLE);
mSelectionManager.addCallback(new SelectionModeListener());
- mModel = new Model(context, mAdapter);
+ mModel = new Model(context);
mModel.addUpdateListener(mAdapter);
mModel.addUpdateListener(mModelUpdateListener);
@@ -343,8 +348,6 @@ public class DirectoryFragment extends Fragment {
mTuner = FragmentTuner.pick(state);
mClipper = new DocumentClipper(context);
- mIconHelper = new IconHelper(context, state.derivedMode);
-
boolean hideGridTitles;
if (mType == TYPE_RECENT_OPEN) {
// Hide titles when showing recents for picking images/videos
@@ -574,7 +577,10 @@ public class DirectoryFragment extends Fragment {
case MODE_GRID:
if (mGridLayout == null) {
mGridLayout = new GridLayoutManager(getContext(), mColumnCount);
- mGridLayout.setSpanSizeLookup(mAdapter.createSpanSizeLookup());
+ SpanSizeLookup lookup = mAdapter.createSpanSizeLookup();
+ if (lookup != null) {
+ mGridLayout.setSpanSizeLookup(lookup);
+ }
}
layout = mGridLayout;
break;
@@ -609,6 +615,11 @@ public class DirectoryFragment extends Fragment {
return columnCount;
}
+ @Override
+ public int getColumnCount() {
+ return mColumnCount;
+ }
+
/**
* Manages the integration between our ActionMode and MultiSelectManager, initiating
* ActionMode when there is a selection, canceling it when there is no selection,
@@ -893,10 +904,34 @@ public class DirectoryFragment extends Fragment {
}.execute(selected);
}
- private State getDisplayState() {
+ @Override
+ public void initDocumentHolder(DocumentHolder holder) {
+ holder.addClickListener(mItemClickListener);
+ holder.addOnKeyListener(mSelectionManager);
+ }
+
+ @Override
+ public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {
+ if (DEBUG_ENABLE_DND) {
+ setupDragAndDropOnDocumentView(holder.itemView, cursor);
+ }
+ }
+
+ @Override
+ public State getDisplayState() {
return ((BaseActivity) getActivity()).getDisplayState();
}
+ @Override
+ public Model getModel() {
+ return mModel;
+ }
+
+ @Override
+ public boolean isDocumentEnabled(String docMimeType, int docFlags) {
+ return mTuner.isDocumentEnabled(docMimeType, docFlags);
+ }
+
void showEmptyView() {
mEmptyView.setVisibility(View.VISIBLE);
mRecView.setVisibility(View.GONE);
@@ -920,228 +955,6 @@ public class DirectoryFragment extends Fragment {
mRecView.setVisibility(View.VISIBLE);
}
- final class DocumentsAdapter
- extends RecyclerView.Adapter<DocumentHolder>
- implements Model.UpdateListener {
-
- private static final String TAG = "DocumentsAdapter";
- public static final int ITEM_TYPE_LAYOUT_DIVIDER = 0;
- public static final int ITEM_TYPE_DOCUMENT = 1;
- public static final int ITEM_TYPE_DIRECTORY = 2;
-
- /**
- * An ordered list of model IDs. This is the data structure that determines what shows up in
- * the UI, and where.
- */
- private List<String> mModelIds = new ArrayList<>();
-
- // The list is divided into two segments - directories, and everything else. Record the
- // position where the transition happens.
- private int mDividerPosition;
-
- public GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
- return new GridLayoutManager.SpanSizeLookup() {
- @Override
- public int getSpanSize(int position) {
- // Make layout whitespace span the grid. This has the effect of breaking
- // grid rows whenever layout whitespace is encountered.
- if (getItemViewType(position) == ITEM_TYPE_LAYOUT_DIVIDER) {
- return mColumnCount;
- } else {
- return 1;
- }
- }
- };
- }
-
- @Override
- public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- if (viewType == ITEM_TYPE_LAYOUT_DIVIDER) {
- return new EmptyDocumentHolder(getContext());
- };
-
- DocumentHolder holder = null;
- final State state = getDisplayState();
- switch (state.derivedMode) {
- case MODE_GRID:
- holder = new GridDocumentHolder(getContext(), parent, mIconHelper, viewType);
- break;
- case MODE_LIST:
- holder = new ListDocumentHolder(getContext(), parent, mIconHelper);
- break;
- case MODE_UNKNOWN:
- default:
- throw new IllegalStateException("Unsupported layout mode.");
- }
-
- holder.addClickListener(mItemClickListener);
- holder.addOnKeyListener(mSelectionManager);
- return holder;
- }
-
- /**
- * Deal with selection changed events by using a custom ItemAnimator that just changes the
- * background color. This works around focus issues (otherwise items lose focus when their
- * selection state changes) but also optimizes change animations for selection.
- */
- @Override
- public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
- if (holder.getItemViewType() == ITEM_TYPE_LAYOUT_DIVIDER) {
- // Whitespace items are hidden elements with no data to bind.
- return;
- }
-
- final View itemView = holder.itemView;
-
- if (payload.contains(MultiSelectManager.SELECTION_CHANGED_MARKER)) {
- final boolean selected = isSelected(mModelIds.get(position));
- itemView.setActivated(selected);
- return;
- } else {
- onBindViewHolder(holder, position);
- }
- }
-
- @Override
- public void onBindViewHolder(DocumentHolder holder, int position) {
- if (holder.getItemViewType() == ITEM_TYPE_LAYOUT_DIVIDER) {
- // Whitespace items are hidden elements with no data to bind.
- return;
- }
-
- String modelId = mModelIds.get(position);
- Cursor cursor = mModel.getItem(modelId);
- holder.bind(cursor, modelId, getDisplayState());
-
- final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
- final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
-
- holder.setSelected(isSelected(modelId));
- holder.setEnabled(mTuner.isDocumentEnabled(docMimeType, docFlags));
- if (DEBUG_ENABLE_DND) {
- setupDragAndDropOnDocumentView(holder.itemView, cursor);
- }
- }
-
- @Override
- public int getItemCount() {
- return mModelIds.size();
- }
-
- @Override
- public void onModelUpdate(Model model) {
- mModelIds = Lists.newArrayList(model.getModelIds());
- mDividerPosition = 0;
-
- // Walk down the list of IDs till we encounter something that's not a directory, and
- // insert a whitespace element - this introduces a visual break in the grid between
- // folders and documents.
- // TODO: This code makes assumptions about the model, namely, that it performs a
- // bucketed sort where directories will always be ordered before other files. CBB.
- for (int i = 0; i < mModelIds.size(); ++i) {
- final String mimeType = getCursorString(
- model.getItem(mModelIds.get(i)), Document.COLUMN_MIME_TYPE);
- if (!Document.MIME_TYPE_DIR.equals(mimeType)) {
- mDividerPosition = i;
- break;
- }
- }
-
- mModelIds.add(mDividerPosition, null);
- }
-
- @Override
- public void onModelUpdateFailed(Exception e) {
- if (DEBUG) Log.d(TAG, "onModelUpdateFailed called ");
- mModelIds.clear();
- }
-
- /**
- * @return The model ID of the item at the given adapter position.
- */
- public String getModelId(int adapterPosition) {
- return mModelIds.get(adapterPosition);
- }
-
- /**
- * Hides a set of items from the associated RecyclerView.
- *
- * @param ids The Model IDs of the items to hide.
- * @return A SparseArray that maps the hidden IDs to their old positions. This can be used
- * to {@link #unhide} the items if necessary.
- */
- public SparseArray<String> hide(String... ids) {
- Set<String> toHide = Sets.newHashSet(ids);
-
- // Proceed backwards through the list of items, because each removal causes the
- // positions of all subsequent items to change.
- SparseArray<String> hiddenItems = new SparseArray<>();
- for (int i = mModelIds.size() - 1; i >= 0; --i) {
- String id = mModelIds.get(i);
- if (toHide.contains(id)) {
- hiddenItems.put(i, mModelIds.remove(i));
- notifyItemRemoved(i);
- }
- }
-
- return hiddenItems;
- }
-
- /**
- * Unhides a set of previously hidden items.
- *
- * @param ids A sparse array of IDs from a previous call to {@link #hide}.
- */
- public void unhide(SparseArray<String> ids) {
- // Proceed backwards through the list of items, because each addition causes the
- // positions of all subsequent items to change.
- for (int i = ids.size() - 1; i >= 0; --i) {
- int pos = ids.keyAt(i);
- String id = ids.get(pos);
- mModelIds.add(pos, id);
- notifyItemInserted(pos);
- }
- }
-
- /**
- * Returns a list of model IDs of items currently in the adapter. Excludes items that are
- * currently hidden (see {@link #hide(String...)}).
- *
- * @return A list of Model IDs.
- */
- public List<String> getModelIds() {
- return mModelIds;
- }
-
- @Override
- public int getItemViewType(int position) {
- if (position < mDividerPosition) {
- return ITEM_TYPE_DIRECTORY;
- } else if (position == mDividerPosition) {
- return ITEM_TYPE_LAYOUT_DIVIDER;
- } else {
- return ITEM_TYPE_DOCUMENT;
- }
- }
-
- /**
- * Triggers item-change notifications by stable ID. Passing an unrecognized ID will result
- * in a warning in logcat, but no other error.
- *
- * @param id
- * @param selectionChangedMarker
- */
- public void notifyItemChanged(String id, String selectionChangedMarker) {
- int position = mModelIds.indexOf(id);
-
- if (position >= 0) {
- notifyItemChanged(position, selectionChangedMarker);
- } else {
- Log.w(TAG, "Item change notification received for unknown item: " + id);
- }
- }
- }
-
private String findCommonMimeType(List<String> mimeTypes) {
String[] commonType = mimeTypes.get(0).split("/");
if (commonType.length != 2) {
@@ -1492,7 +1305,8 @@ public class DirectoryFragment extends Fragment {
abstract void onDocumentsReady(List<DocumentInfo> docs);
}
- boolean isSelected(String modelId) {
+ @Override
+ public boolean isSelected(String modelId) {
return mSelectionManager.getSelection().contains(modelId);
}
@@ -1508,7 +1322,7 @@ public class DirectoryFragment extends Fragment {
}
}
- private class ModelUpdateListener implements Model.UpdateListener {
+ private final class ModelUpdateListener implements Model.UpdateListener {
@Override
public void onModelUpdate(Model model) {
if (model.info != null || model.error != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
index a01021f8750e..9ac905711ba2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
@@ -40,16 +40,15 @@ public abstract class DocumentHolder
final int mDefaultItemColor;
final boolean mAlwaysShowSummary;
final Context mContext;
- final IconHelper mIconHelper;
private ListDocumentHolder.ClickListener mClickListener;
private View.OnKeyListener mKeyListener;
- public DocumentHolder(Context context, ViewGroup parent, int layout, IconHelper iconHelper) {
- this(context, inflateLayout(context, parent, layout), iconHelper);
+ public DocumentHolder(Context context, ViewGroup parent, int layout) {
+ this(context, inflateLayout(context, parent, layout));
}
- public DocumentHolder(Context context, View item, IconHelper iconHelper) {
+ public DocumentHolder(Context context, View item) {
super(item);
itemView.setOnKeyListener(this);
@@ -59,8 +58,6 @@ public abstract class DocumentHolder
mDefaultItemColor = context.getColor(R.color.item_doc_background);
mSelectedItemColor = context.getColor(R.color.item_doc_background_selected);
mAlwaysShowSummary = context.getResources().getBoolean(R.bool.always_show_summary);
-
- mIconHelper = iconHelper;
}
/**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
new file mode 100644
index 000000000000..43c2f6386347
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
@@ -0,0 +1,117 @@
+/*
+ * 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.dirlist;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.DocumentsContract.Document;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.SparseArray;
+
+import com.android.documentsui.State;
+
+import java.nio.channels.UnsupportedAddressTypeException;
+import java.util.List;
+
+/**
+ * DocumentsAdapter provides glue between a directory Model, and RecylcerView. We've
+ * abstracted this a bit in order to decompose some specialized support
+ * for adding dummy layout objects (@see SectionBreakDocumentsAdapter). Handling of the
+ * dummy layout objects was error prone when interspersed with the core mode / adapter code.
+ *
+ * @see ModelBackedDocumentsAdapter
+ * @see SectionBreakDocumentsAdapter
+ */
+abstract class DocumentsAdapter
+ extends RecyclerView.Adapter<DocumentHolder>
+ implements Model.UpdateListener {
+
+ // Payloads for notifyItemChange to distinguish between selection and other events.
+ static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
+
+ /**
+ * Returns a list of model IDs of items currently in the adapter. Excludes items that are
+ * currently hidden (see {@link #hide(String...)}).
+ *
+ * @return A list of Model IDs.
+ */
+ abstract List<String> getModelIds();
+
+ /**
+ * Triggers item-change notifications by stable ID (as opposed to position).
+ * Passing an unrecognized ID will result in a warning in logcat, but no other error.
+ */
+ abstract void onItemSelectionChanged(String id);
+
+ /**
+ * @return The model ID of the item at the given adapter position.
+ */
+ abstract String getModelId(int position);
+
+ /**
+ * Hides a set of items from the associated RecyclerView.
+ *
+ * @param ids The Model IDs of the items to hide.
+ * @return A SparseArray that maps the hidden IDs to their old positions. This can be used
+ * to {@link #unhide} the items if necessary.
+ */
+ abstract public SparseArray<String> hide(String... ids);
+
+ /**
+ * Unhides a set of previously hidden items.
+ *
+ * @param ids A sparse array of IDs from a previous call to {@link #hide}.
+ */
+ abstract void unhide(SparseArray<String> ids);
+
+ /**
+ * Returns a class that yields the span size for a particular element. This is
+ * primarily useful in {@link SectionBreakDocumentsAdapterWrapper} where
+ * we adjust sizes.
+ */
+ GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
+ throw new UnsupportedAddressTypeException();
+ }
+
+ static boolean isDirectory(Cursor cursor) {
+ final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ return Document.MIME_TYPE_DIR.equals(mimeType);
+ }
+
+ boolean isDirectory(Model model, int position) {
+ String modelId = getModelIds().get(position);
+ Cursor cursor = model.getItem(modelId);
+ return isDirectory(cursor);
+ }
+
+ /**
+ * Environmental access for View adapter implementations.
+ */
+ interface Environment {
+ Context getContext();
+ int getColumnCount();
+ State getDisplayState();
+ boolean isSelected(String id);
+ Model getModel();
+ boolean isDocumentEnabled(String mimeType, int flags);
+ void initDocumentHolder(DocumentHolder holder);
+ void onBindDocumentHolder(DocumentHolder holder, Cursor cursor);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java
index 0bdf53065284..ab67a5b6cec9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java
@@ -18,14 +18,18 @@ package com.android.documentsui.dirlist;
import android.content.Context;
import android.database.Cursor;
-import android.view.View;
+import android.widget.Space;
+import com.android.documentsui.R;
import com.android.documentsui.State;
final class EmptyDocumentHolder extends DocumentHolder {
public EmptyDocumentHolder(Context context) {
- super(context, new View(context), null);
- itemView.setVisibility(View.GONE);
+ super(context, new Space(context));
+
+ // Per UX spec, this puts a bigger gap between the folders and documents in the grid.
+ final int gridMargin = context.getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
+ itemView.setMinimumHeight(gridMargin * 2);
}
public void bind(Cursor cursor, String modelId, State state) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
new file mode 100644
index 000000000000..11ff263cabd8
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
@@ -0,0 +1,53 @@
+/*
+ * 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.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;
+import android.provider.DocumentsContract.Document;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.documentsui.R;
+import com.android.documentsui.State;
+
+final class GridDirectoryHolder extends DocumentHolder {
+ final TextView mTitle;
+ public GridDirectoryHolder(Context context, ViewGroup parent) {
+ super(context, parent, R.layout.item_dir_grid);
+
+ mTitle = (TextView) itemView.findViewById(android.R.id.title);
+ }
+
+ /**
+ * Bind this view to the given document for display.
+ * @param cursor Pointing to the item to be bound.
+ * @param modelId The model ID of the item.
+ * @param state Current display state.
+ */
+ public void bind(Cursor cursor, String modelId, State state) {
+ checkNotNull(cursor, "Cursor cannot be null.");
+
+ this.modelId = modelId;
+
+ final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+ mTitle.setText(docDisplayName);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
index 43256c398c46..5f34ac3c037a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
@@ -32,6 +32,7 @@ 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;
@@ -40,9 +41,25 @@ import com.android.documentsui.State;
final class GridDocumentHolder extends DocumentHolder {
private static boolean mHideTitles;
- public GridDocumentHolder(
- Context context, ViewGroup parent, IconHelper thumbnailLoader, int viewType) {
- super(context, parent, R.layout.item_doc_grid, thumbnailLoader);
+ final TextView mTitle;
+ final TextView mDate;
+ final TextView mSize;
+ final ImageView mIconMimeLg;
+ final ImageView mIconMimeSm;
+ final ImageView mIconThumb;
+ final IconHelper mIconHelper;
+
+
+ public GridDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper) {
+ super(context, parent, R.layout.item_doc_grid);
+
+ mTitle = (TextView) itemView.findViewById(android.R.id.title);
+ mDate = (TextView) itemView.findViewById(R.id.date);
+ mSize = (TextView) itemView.findViewById(R.id.size);
+ mIconMimeLg = (ImageView) itemView.findViewById(R.id.icon_mime);
+ mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
+ mIconMimeSm = (ImageView) itemView.findViewById(android.R.id.icon1);
+ mIconHelper = iconHelper;
}
/**
@@ -65,40 +82,36 @@ final class GridDocumentHolder extends DocumentHolder {
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
- final TextView title = (TextView) itemView.findViewById(android.R.id.title);
- final TextView date = (TextView) itemView.findViewById(R.id.date);
- final TextView size = (TextView) itemView.findViewById(R.id.size);
- final ImageView iconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
- final ImageView iconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
+ mIconHelper.stopLoading(mIconThumb);
- mIconHelper.stopLoading(iconThumb);
+ mIconMimeLg.animate().cancel();
+ mIconMimeLg.setAlpha(1f);
+ mIconThumb.animate().cancel();
+ mIconThumb.setAlpha(0f);
- iconMime.animate().cancel();
- iconMime.setAlpha(1f);
- iconThumb.animate().cancel();
- iconThumb.setAlpha(0f);
+ mIconMimeSm.setImageDrawable(IconUtils.loadMimeIcon(mContext, docMimeType));
final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
- mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, iconThumb, iconMime);
+ mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMimeLg);
if (mHideTitles) {
- title.setVisibility(View.GONE);
+ mTitle.setVisibility(View.GONE);
} else {
- title.setText(docDisplayName);
- title.setVisibility(View.VISIBLE);
+ mTitle.setText(docDisplayName);
+ mTitle.setVisibility(View.VISIBLE);
}
if (docLastModified == -1) {
- date.setText(null);
+ mDate.setText(null);
} else {
- date.setText(Shared.formatTime(mContext, docLastModified));
+ mDate.setText(Shared.formatTime(mContext, docLastModified));
}
if (!state.showSize || Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
- size.setVisibility(View.GONE);
+ mSize.setVisibility(View.GONE);
} else {
- size.setVisibility(View.VISIBLE);
- size.setText(Formatter.formatFileSize(mContext, docSize));
+ mSize.setVisibility(View.VISIBLE);
+ mSize.setText(Formatter.formatFileSize(mContext, docSize));
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
index b46a0e5afcdd..c22e91d58c32 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
@@ -38,16 +38,27 @@ import com.android.documentsui.Shared;
import com.android.documentsui.State;
final class ListDocumentHolder extends DocumentHolder {
+ final TextView mTitle;
+ final TextView mSummary;
+ final TextView mDate;
+ final TextView mSize;
final ImageView mIconMime;
final ImageView mIconThumb;
final ImageView mIcon1;
+ final IconHelper mIconHelper;
- public ListDocumentHolder(Context context, ViewGroup parent, IconHelper thumbnailLoader) {
- super(context, parent, R.layout.item_doc_list, thumbnailLoader);
+ public ListDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper) {
+ super(context, parent, R.layout.item_doc_list);
+ mTitle = (TextView) itemView.findViewById(android.R.id.title);
+ mSummary = (TextView) itemView.findViewById(android.R.id.summary);
+ mDate = (TextView) itemView.findViewById(R.id.date);
+ mSize = (TextView) itemView.findViewById(R.id.size);
mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
mIcon1 = (ImageView) itemView.findViewById(android.R.id.icon1);
+
+ mIconHelper = iconHelper;
}
/**
@@ -72,11 +83,6 @@ final class ListDocumentHolder extends DocumentHolder {
final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
- final TextView title = (TextView) itemView.findViewById(android.R.id.title);
- final TextView summary = (TextView) itemView.findViewById(android.R.id.summary);
- final TextView date = (TextView) itemView.findViewById(R.id.date);
- final TextView size = (TextView) itemView.findViewById(R.id.size);
-
mIconHelper.stopLoading(mIconThumb);
mIconMime.animate().cancel();
@@ -85,27 +91,27 @@ final class ListDocumentHolder extends DocumentHolder {
final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMime);
- title.setText(docDisplayName);
- title.setVisibility(View.VISIBLE);
+ mTitle.setText(docDisplayName);
+ mTitle.setVisibility(View.VISIBLE);
if (docSummary != null) {
- summary.setText(docSummary);
- summary.setVisibility(View.VISIBLE);
+ mSummary.setText(docSummary);
+ mSummary.setVisibility(View.VISIBLE);
} else {
- summary.setVisibility(View.INVISIBLE);
+ mSummary.setVisibility(View.INVISIBLE);
}
if (docLastModified == -1) {
- date.setText(null);
+ mDate.setText(null);
} else {
- date.setText(Shared.formatTime(mContext, docLastModified));
+ mDate.setText(Shared.formatTime(mContext, docLastModified));
}
if (!state.showSize || Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
- size.setVisibility(View.GONE);
+ mSize.setVisibility(View.GONE);
} else {
- size.setVisibility(View.VISIBLE);
- size.setText(Formatter.formatFileSize(mContext, docSize));
+ mSize.setVisibility(View.VISIBLE);
+ mSize.setText(Formatter.formatFileSize(mContext, docSize));
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
index bea38c64ae68..f2bade588f23 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -35,7 +35,6 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
-import android.support.v7.widget.RecyclerView;
import android.util.Log;
import com.android.documentsui.BaseActivity.SiblingProvider;
@@ -74,7 +73,7 @@ public class Model implements SiblingProvider {
@Nullable String info;
@Nullable String error;
- Model(Context context, RecyclerView.Adapter<?> viewAdapter) {
+ Model(Context context) {
mContext = context;
}
@@ -87,8 +86,19 @@ public class Model implements SiblingProvider {
private static String createModelId(Cursor c) {
// TODO: Maybe more efficient to use just the document ID, in cases where there is only one
// authority (which should be the majority of cases).
- return getCursorString(c, RootCursorWrapper.COLUMN_AUTHORITY) +
- "|" + getCursorString(c, Document.COLUMN_DOCUMENT_ID);
+ return createModelId(
+ getCursorString(c, RootCursorWrapper.COLUMN_AUTHORITY),
+ getCursorString(c, Document.COLUMN_DOCUMENT_ID));
+ }
+
+ /**
+ * Generates a Model ID for a cursor entry that refers to a document. The Model ID is a unique
+ * string that can be used to identify the document referred to by the cursor.
+ *
+ * @param c A cursor that refers to a document.
+ */
+ static String createModelId(String authority, String docId) {
+ return authority + "|" + docId;
}
private void notifyUpdateListeners() {
@@ -404,8 +414,14 @@ public class Model implements SiblingProvider {
@Override
protected Void doInBackground(Selection... selected) {
- List<DocumentInfo> toDelete = getDocuments(selected[0]);
- mHadTrouble = false;
+ List<DocumentInfo> toDelete = null;
+ try {
+ toDelete = getDocuments(selected[0]);
+ } catch (NullPointerException e) {
+ Log.w(TAG, "Failed to retrieve documents for delete.");
+ mHadTrouble = true;
+ return null;
+ }
for (DocumentInfo doc : toDelete) {
if (!doc.isDeleteSupported()) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
new file mode 100644
index 000000000000..68756a36fb1c
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -0,0 +1,230 @@
+/*
+ * 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.dirlist;
+
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.MODE_GRID;
+import static com.android.documentsui.State.MODE_LIST;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.database.Cursor;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import com.android.documentsui.State;
+
+import com.google.common.collect.Sets;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Adapts from dirlist.Model to something RecyclerView understands.
+ */
+final class ModelBackedDocumentsAdapter extends DocumentsAdapter {
+
+ private static final String TAG = "ModelBackedDocumentsAdapter";
+ public static final int ITEM_TYPE_DOCUMENT = 1;
+ public static final int ITEM_TYPE_DIRECTORY = 2;
+
+ // Provides access to information needed when creating and view holders. This
+ // isn't an ideal pattern (more transitive dependency stuff) but good enough for now.
+ private final Environment mEnv;
+ private final IconHelper mIconHelper; // a transitive dependency of the holders.
+
+ /**
+ * An ordered list of model IDs. This is the data structure that determines what shows up in
+ * the UI, and where.
+ */
+ private List<String> mModelIds = new ArrayList<>();
+
+ // List of files that have been deleted. Some transient directory updates
+ // may happen while files are being deleted. During this time we don't
+ // want once-hidden files to be re-shown. We only remove
+ // items from this list when we get a model update where the model
+ // does not contain a corresponding id. This ensures hidden entries
+ // don't momentarily re-appear if we get intermediate updates from
+ // the file system.
+ private Set<String> mHiddenIds = new HashSet<>();
+
+ public ModelBackedDocumentsAdapter(Environment env, IconHelper iconHelper) {
+ mEnv = env;
+ mIconHelper = iconHelper;
+ }
+
+ @Override
+ public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ DocumentHolder holder = null;
+ final State state = mEnv.getDisplayState();
+ switch (state.derivedMode) {
+ case MODE_GRID:
+ switch (viewType) {
+ case ITEM_TYPE_DIRECTORY:
+ holder = new GridDirectoryHolder(mEnv.getContext(), parent);
+ break;
+ case ITEM_TYPE_DOCUMENT:
+ holder = new GridDocumentHolder(mEnv.getContext(), parent, mIconHelper);
+ break;
+ default:
+ throw new IllegalStateException("Unsupported layout type.");
+ }
+ break;
+ case MODE_LIST:
+ holder = new ListDocumentHolder(mEnv.getContext(), parent, mIconHelper);
+ break;
+ case MODE_UNKNOWN:
+ default:
+ throw new IllegalStateException("Unsupported layout mode.");
+ }
+
+ mEnv.initDocumentHolder(holder);
+ return holder;
+ }
+
+ @Override
+ public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
+ if (payload.contains(SELECTION_CHANGED_MARKER)) {
+ final boolean selected = mEnv.isSelected(mModelIds.get(position));
+ holder.setSelected(selected);
+ } else {
+ onBindViewHolder(holder, position);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(DocumentHolder holder, int position) {
+ String modelId = mModelIds.get(position);
+ Cursor cursor = mEnv.getModel().getItem(modelId);
+ holder.bind(cursor, modelId, mEnv.getDisplayState());
+
+ final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+
+ holder.setSelected(mEnv.isSelected(modelId));
+ holder.setEnabled(mEnv.isDocumentEnabled(docMimeType, docFlags));
+
+ mEnv.onBindDocumentHolder(holder, cursor);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mModelIds.size();
+ }
+
+ @Override
+ public void onModelUpdate(Model model) {
+ if (DEBUG && mHiddenIds.size() > 0) {
+ Log.d(TAG, "Updating model with hidden ids: " + mHiddenIds);
+ }
+
+ List<String> modelIds = model.getModelIds();
+ mModelIds = new ArrayList<>(modelIds.size());
+ for (String id : modelIds) {
+ if (!mHiddenIds.contains(id)) {
+ mModelIds.add(id);
+ } else {
+ if (DEBUG) Log.d(TAG, "Omitting hidden id from model during update: " + id);
+ }
+ }
+
+ // Finally remove any hidden ids that aren't present in the model.
+ // This assumes that model updates represent a complete set of files.
+ mHiddenIds.retainAll(mModelIds);
+ }
+
+ @Override
+ public void onModelUpdateFailed(Exception e) {
+ Log.w(TAG, "Model update failed.", e);
+ mModelIds.clear();
+ }
+
+ @Override
+ public String getModelId(int adapterPosition) {
+ return mModelIds.get(adapterPosition);
+ }
+
+ @Override
+ public SparseArray<String> hide(String... ids) {
+ if (DEBUG) Log.d(TAG, "Hiding ids: " + ids);
+ Set<String> toHide = Sets.newHashSet(ids);
+
+ // Proceed backwards through the list of items, because each removal causes the
+ // positions of all subsequent items to change.
+ SparseArray<String> hiddenItems = new SparseArray<>();
+ for (int i = mModelIds.size() - 1; i >= 0; --i) {
+ String id = mModelIds.get(i);
+ if (toHide.contains(id)) {
+ mHiddenIds.add(id);
+ hiddenItems.put(i, mModelIds.remove(i));
+ notifyItemRemoved(i);
+ }
+ }
+
+ return hiddenItems;
+ }
+
+ @Override
+ public void unhide(SparseArray<String> ids) {
+ if (DEBUG) Log.d(TAG, "Un-iding ids: " + ids);
+
+ // An ArrayList can shrink at runtime...and in fact
+ // it does when we clear it completely.
+ // This means we can't call add(pos, id) without
+ // first checking the list size.
+ List<String> oldIds = mModelIds;
+ mModelIds = new ArrayList<>(oldIds.size() + ids.size());
+ mModelIds.addAll(oldIds);
+
+ // Finally insert the unhidden items.
+ for (int i = 0; i < ids.size(); i++) {
+ int pos = ids.keyAt(i);
+ String id = ids.get(pos);
+ mHiddenIds.remove(id);
+ mModelIds.add(pos, id);
+ notifyItemInserted(pos);
+ }
+ }
+
+ @Override
+ public List<String> getModelIds() {
+ return mModelIds;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return isDirectory(mEnv.getModel(), position)
+ ? ITEM_TYPE_DIRECTORY
+ : ITEM_TYPE_DOCUMENT;
+ }
+
+ @Override
+ public void onItemSelectionChanged(String id) {
+ int position = mModelIds.indexOf(id);
+
+ if (position >= 0) {
+ notifyItemChanged(position, SELECTION_CHANGED_MARKER);
+ } else {
+ Log.w(TAG, "Item change notification received for unknown item: " + id);
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index 26eac26ce96b..5f317ffb29e6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -68,24 +68,23 @@ public final class MultiSelectManager implements View.OnKeyListener {
private final Selection mSelection = new Selection();
- private Range mRanger;
- private SelectionEnvironment mEnvironment;
-
+ private final SelectionEnvironment mEnvironment;
+ private final DocumentsAdapter mAdapter;
private final List<MultiSelectManager.Callback> mCallbacks = new ArrayList<>(1);
+ private Range mRanger;
private boolean mSingleSelect;
- // Payloads for notifyItemChange to distinguish between selection and other events.
- public static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
-
@Nullable private BandController mBandManager;
+
/**
* @param recyclerView
* @param mode Selection mode
*/
- public MultiSelectManager(final RecyclerView recyclerView, int mode) {
- this(new RuntimeSelectionEnvironment(recyclerView), mode);
+ public MultiSelectManager(
+ final RecyclerView recyclerView, DocumentsAdapter adapter, int mode) {
+ this(new RuntimeSelectionEnvironment(recyclerView), adapter, mode);
if (mode == MODE_MULTIPLE) {
mBandManager = new BandController();
@@ -136,11 +135,12 @@ public final class MultiSelectManager implements View.OnKeyListener {
* @hide
*/
@VisibleForTesting
- MultiSelectManager(SelectionEnvironment environment, int mode) {
+ MultiSelectManager(SelectionEnvironment environment, DocumentsAdapter adapter, int mode) {
mEnvironment = checkNotNull(environment, "'environment' cannot be null.");
+ mAdapter = checkNotNull(adapter, "'adapter' cannot be null.");
mSingleSelect = mode == MODE_SINGLE;
- mEnvironment.registerDataObserver(
+ mAdapter.registerAdapterDataObserver(
new RecyclerView.AdapterDataObserver() {
private List<String> mModelIds;
@@ -149,7 +149,7 @@ public final class MultiSelectManager implements View.OnKeyListener {
public void onChanged() {
// TODO: This is causing b/22765812
mSelection.clear();
- mModelIds = mEnvironment.getModelIds();
+ mModelIds = mAdapter.getModelIds();
}
@Override
@@ -339,7 +339,10 @@ public final class MultiSelectManager implements View.OnKeyListener {
if (DEBUG) Log.d(TAG, "Ignoring toggle for element with no position.");
return;
}
- toggleSelection(mEnvironment.getModelIdFromAdapterPosition(position));
+ String id = mAdapter.getModelId(position);
+ if (id != null) {
+ toggleSelection(id);
+ }
}
/**
@@ -348,6 +351,7 @@ public final class MultiSelectManager implements View.OnKeyListener {
* @param modelId
*/
public void toggleSelection(String modelId) {
+ checkNotNull(modelId);
boolean changed = false;
if (mSelection.contains(modelId)) {
changed = attemptDeselect(modelId);
@@ -383,7 +387,11 @@ public final class MultiSelectManager implements View.OnKeyListener {
* @param position
*/
void setSelectionRangeBegin(int position) {
- if (mSelection.contains(mEnvironment.getModelIdFromAdapterPosition(position))) {
+ if (position == RecyclerView.NO_POSITION) {
+ return;
+ }
+
+ if (mSelection.contains(mAdapter.getModelId(position))) {
mRanger = new Range(position);
}
}
@@ -400,7 +408,11 @@ public final class MultiSelectManager implements View.OnKeyListener {
private void updateRange(int begin, int end, boolean selected) {
checkState(end >= begin);
for (int i = begin; i <= end; i++) {
- String id = mEnvironment.getModelIdFromAdapterPosition(i);
+ String id = mAdapter.getModelId(i);
+ if (id == null) {
+ continue;
+ }
+
if (selected) {
boolean canSelect = notifyBeforeItemStateChange(id, true);
if (canSelect) {
@@ -432,6 +444,7 @@ public final class MultiSelectManager implements View.OnKeyListener {
* @return True if the update was applied.
*/
private boolean attemptDeselect(String id) {
+ checkArgument(id != null);
if (notifyBeforeItemStateChange(id, false)) {
mSelection.remove(id);
notifyItemStateChanged(id, false);
@@ -458,11 +471,12 @@ public final class MultiSelectManager implements View.OnKeyListener {
* (identified by {@code position}) changes.
*/
private void notifyItemStateChanged(String id, boolean selected) {
+ checkArgument(id != null);
int lastListener = mCallbacks.size() - 1;
for (int i = lastListener; i > -1; i--) {
mCallbacks.get(i).onItemStateChanged(id, selected);
}
- mEnvironment.notifyItemChanged(id);
+ mAdapter.onItemSelectionChanged(id);
}
/**
@@ -609,7 +623,7 @@ public final class MultiSelectManager implements View.OnKeyListener {
* @param id
* @return true if the position is currently selected.
*/
- public boolean contains(String id) {
+ public boolean contains(@Nullable String id) {
return mTotalSelection.contains(id);
}
@@ -800,11 +814,6 @@ public final class MultiSelectManager implements View.OnKeyListener {
int getChildCount();
int getVisibleChildCount();
void focusItem(int position);
- String getModelIdFromAdapterPosition(int position);
- int getItemCount();
- List<String> getModelIds();
- void notifyItemChanged(String id);
- void registerDataObserver(RecyclerView.AdapterDataObserver observer);
}
/** Recycler view facade implementation backed by good ol' RecyclerView. */
@@ -814,11 +823,9 @@ public final class MultiSelectManager implements View.OnKeyListener {
private final Drawable mBand;
private boolean mIsOverlayShown = false;
- private DirectoryFragment.DocumentsAdapter mAdapter;
- RuntimeSelectionEnvironment(RecyclerView rv) {
- mView = rv;
- mAdapter = (DirectoryFragment.DocumentsAdapter) rv.getAdapter();
+ RuntimeSelectionEnvironment(RecyclerView view) {
+ mView = view;
mBand = mView.getContext().getTheme().getDrawable(R.drawable.band_select_overlay);
}
@@ -837,11 +844,6 @@ public final class MultiSelectManager implements View.OnKeyListener {
}
@Override
- public String getModelIdFromAdapterPosition(int position) {
- return mAdapter.getModelId(position);
- }
-
- @Override
public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
mView.addOnScrollListener(listener);
}
@@ -943,40 +945,31 @@ public final class MultiSelectManager implements View.OnKeyListener {
if (vh != null) {
vh.itemView.requestFocus();
} else {
- // Don't smooth scroll; that taxes the system unnecessarily and makes the scroll
- // handling logic below more complicated. See b/24865658.
- mView.scrollToPosition(pos);
+ mView.smoothScrollToPosition(pos);
// Set a one-time listener to request focus when the scroll has completed.
mView.addOnScrollListener(
new RecyclerView.OnScrollListener() {
@Override
- public void onScrolled(RecyclerView view, int dx, int dy) {
- view.findViewHolderForAdapterPosition(pos).itemView.requestFocus();
- view.removeOnScrollListener(this);
+ 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);
+ }
}
});
}
}
-
- @Override
- public void notifyItemChanged(String id) {
- mAdapter.notifyItemChanged(id, SELECTION_CHANGED_MARKER);
- }
-
- @Override
- public int getItemCount() {
- return mAdapter.getItemCount();
- }
-
- @Override
- public void registerDataObserver(RecyclerView.AdapterDataObserver observer) {
- mAdapter.registerAdapterDataObserver(observer);
- }
-
- @Override
- public List<String> getModelIds() {
- return mAdapter.getModelIds();
- }
}
public interface Callback {
@@ -1033,7 +1026,7 @@ public final class MultiSelectManager implements View.OnKeyListener {
mModelBuilder = new Runnable() {
@Override
public void run() {
- mModel = new GridModel(mEnvironment);
+ mModel = new GridModel(mEnvironment, mAdapter);
mModel.addOnSelectionChangedListener(BandController.this);
}
};
@@ -1084,7 +1077,7 @@ public final class MultiSelectManager implements View.OnKeyListener {
return !isActive()
&& e.isMouseEvent() // a mouse
&& e.isActionDown() // the initial button press
- && mEnvironment.getItemCount() > 0
+ && mAdapter.getItemCount() > 0
&& e.getItemPosition() == RecyclerView.NO_ID; // in empty space
}
@@ -1160,13 +1153,15 @@ public final class MultiSelectManager implements View.OnKeyListener {
mSelection.applyProvisionalSelection();
mModel.endSelection();
int firstSelected = mModel.getPositionNearestOrigin();
- if (!mSelection.contains(mEnvironment.getModelIdFromAdapterPosition(firstSelected))) {
- Log.w(TAG, "First selected by band is NOT in selection!");
- // Sadly this is really happening. Need to figure out what's going on.
- } else if (firstSelected != NOT_SET) {
- // TODO: firstSelected should really be lastSelected, we want to anchor the item
- // where the mouse-up occurred.
- setSelectionRangeBegin(firstSelected);
+ if (firstSelected != NOT_SET) {
+ if (mSelection.contains(mAdapter.getModelId(firstSelected))) {
+ // TODO: firstSelected should really be lastSelected, we want to anchor the item
+ // where the mouse-up occurred.
+ setSelectionRangeBegin(firstSelected);
+ } else {
+ // TODO: Check if this is really happening.
+ Log.w(TAG, "First selected by band is NOT in selection!");
+ }
}
mModel = null;
@@ -1321,6 +1316,8 @@ public final class MultiSelectManager implements View.OnKeyListener {
private static final int LOWER_RIGHT = LOWER | RIGHT;
private final SelectionEnvironment mHelper;
+ private final DocumentsAdapter mAdapter;
+
private final List<OnSelectionChangedListener> mOnSelectionChangedListeners =
new ArrayList<>();
@@ -1358,8 +1355,9 @@ public final class MultiSelectManager implements View.OnKeyListener {
// should expand from when Shift+click is used.
private int mPositionNearestOrigin = NOT_SET;
- GridModel(SelectionEnvironment helper) {
+ GridModel(SelectionEnvironment helper, DocumentsAdapter adapter) {
mHelper = helper;
+ mAdapter = adapter;
mHelper.addOnScrollListener(this);
}
@@ -1558,18 +1556,22 @@ public final class MultiSelectManager implements View.OnKeyListener {
for (int column = columnStartIndex; column <= columnEndIndex; column++) {
SparseIntArray items = mColumns.get(mColumnBounds.get(column).lowerLimit);
for (int row = rowStartIndex; row <= rowEndIndex; row++) {
- int position = items.get(items.keyAt(row));
- String id = mHelper.getModelIdFromAdapterPosition(position);
- if (id != null) {
- // The adapter inserts items for UI layout purposes that aren't associated
- // with files. Those will have a null model ID. Don't select them.
- mSelection.add(id);
- }
- if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex,
- row, rowStartIndex, rowEndIndex)) {
- // If this is the position nearest the origin, record it now so that it
- // can be returned by endSelection() later.
- mPositionNearestOrigin = position;
+ // The default return value for SparseIntArray.get is 0, which is a valid
+ // position. Use a sentry value to prevent erroneously selecting item 0.
+ int position = items.get(items.keyAt(row), NOT_SET);
+ if (position != NOT_SET) {
+ String id = mAdapter.getModelId(position);
+ if (id != null) {
+ // The adapter inserts items for UI layout purposes that aren't associated
+ // with files. Those will have a null model ID. Don't select them.
+ mSelection.add(id);
+ }
+ if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex,
+ row, rowStartIndex, rowEndIndex)) {
+ // If this is the position nearest the origin, record it now so that it
+ // can be returned by endSelection() later.
+ mPositionNearestOrigin = position;
+ }
}
}
}
@@ -1967,7 +1969,7 @@ public final class MultiSelectManager implements View.OnKeyListener {
if (keyCode == KeyEvent.KEYCODE_MOVE_HOME) {
position = 0;
} else if (keyCode == KeyEvent.KEYCODE_MOVE_END) {
- position = mEnvironment.getItemCount() - 1;
+ position = mAdapter.getItemCount() - 1;
} else {
// Find a navigation target based on the arrow key that the user pressed. Ignore
// navigation targets that aren't items in the recycler view.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
new file mode 100644
index 000000000000..b4782f035e11
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
@@ -0,0 +1,217 @@
+/*
+ * 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.dirlist;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView.AdapterDataObserver;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import java.util.List;
+
+/**
+ * Adapter wrapper that inserts a sort of line break item between directories and regular files.
+ * Only needs to be used in GRID mode...at this time.
+ */
+final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter {
+
+ private static final String TAG = "SectionBreakDocumentsAdapterWrapper";
+ private static final int ITEM_TYPE_SECTION_BREAK = Integer.MAX_VALUE;
+
+ private final Environment mEnv;
+ private final DocumentsAdapter mDelegate;
+
+ private int mBreakPosition = -1;
+
+ SectionBreakDocumentsAdapterWrapper(Environment environment, DocumentsAdapter delegate) {
+ mEnv = environment;
+ mDelegate = delegate;
+
+ // Relay events published by our delegate to our listeners (presumably RecyclerView)
+ // with adjusted positions.
+ mDelegate.registerAdapterDataObserver(new EventRelay());
+ }
+
+ public GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
+ return new GridLayoutManager.SpanSizeLookup() {
+ @Override
+ public int getSpanSize(int position) {
+ // Make layout whitespace span the grid. This has the effect of breaking
+ // grid rows whenever layout whitespace is encountered.
+ if (getItemViewType(position) == ITEM_TYPE_SECTION_BREAK) {
+ return mEnv.getColumnCount();
+ } else {
+ return 1;
+ }
+ }
+ };
+ }
+
+ @Override
+ public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ if (viewType == ITEM_TYPE_SECTION_BREAK) {
+ return new EmptyDocumentHolder(mEnv.getContext());
+ } else {
+ return mDelegate.createViewHolder(parent, viewType);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(DocumentHolder holder, int p, List<Object> payload) {
+ if (holder.getItemViewType() != ITEM_TYPE_SECTION_BREAK) {
+ mDelegate.onBindViewHolder(holder, toDelegatePosition(p), payload);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(DocumentHolder holder, int p) {
+ if (holder.getItemViewType() != ITEM_TYPE_SECTION_BREAK) {
+ mDelegate.onBindViewHolder(holder, toDelegatePosition(p));
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return mBreakPosition == -1
+ ? mDelegate.getItemCount()
+ : mDelegate.getItemCount() + 1;
+ }
+
+ @Override
+ public void onModelUpdate(Model model) {
+ mDelegate.onModelUpdate(model);
+ mBreakPosition = -1;
+
+ // Walk down the list of IDs till we encounter something that's not a directory, and
+ // insert a whitespace element - this introduces a visual break in the grid between
+ // folders and documents.
+ // TODO: This code makes assumptions about the model, namely, that it performs a
+ // bucketed sort where directories will always be ordered before other files. CBB.
+ List<String> modelIds = mDelegate.getModelIds();
+ for (int i = 0; i < modelIds.size(); i++) {
+ if (!isDirectory(model, i)) {
+ mBreakPosition = i;
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onModelUpdateFailed(Exception e) {
+ mDelegate.onModelUpdateFailed(e);
+ }
+
+ @Override
+ public int getItemViewType(int p) {
+ if (p == mBreakPosition) {
+ return ITEM_TYPE_SECTION_BREAK;
+ } else {
+ return mDelegate.getItemViewType(toDelegatePosition(p));
+ }
+ }
+
+ /**
+ * Returns the position of an item in the delegate, adjusting
+ * values that are greater than the break position.
+ *
+ * @param p Position within the view
+ * @return Position within the delegate
+ */
+ private int toDelegatePosition(int p) {
+ return (mBreakPosition != -1 && p > mBreakPosition) ? p - 1 : p;
+ }
+
+ /**
+ * Returns the position of an item in the view, adjusting
+ * values that are greater than the break position.
+ *
+ * @param p Position within the delegate
+ * @return Position within the view
+ */
+ private int toViewPosition(int p) {
+ // If position is greater than or equal to the break, increase by one.
+ return (mBreakPosition != -1 && p >= mBreakPosition) ? p + 1 : p;
+ }
+
+ @Override
+ public SparseArray<String> hide(String... ids) {
+ // NOTE: We hear about these changes and adjust break position
+ // in our AdapterDataObserver.
+ return mDelegate.hide(ids);
+ }
+
+ @Override
+ void unhide(SparseArray<String> ids) {
+ // NOTE: We hear about these changes and adjust break position
+ // in our AdapterDataObserver.
+ mDelegate.unhide(ids);
+ }
+
+ @Override
+ List<String> getModelIds() {
+ return mDelegate.getModelIds();
+ }
+
+ @Override
+ String getModelId(int p) {
+ return (p == mBreakPosition) ? null : mDelegate.getModelId(toDelegatePosition(p));
+ }
+
+ @Override
+ public void onItemSelectionChanged(String id) {
+ mDelegate.onItemSelectionChanged(id);
+ }
+
+ // Listener we add to our delegate. This allows us to relay events published
+ // by the delegate to our listeners (presumably RecyclerView) with adjusted positions.
+ private final class EventRelay extends AdapterDataObserver {
+ public void onChanged() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void onItemRangeChanged(int positionStart, int itemCount) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
+ checkArgument(itemCount == 1);
+ notifyItemRangeChanged(toViewPosition(positionStart), itemCount, payload);
+ }
+
+ public void onItemRangeInserted(int positionStart, int itemCount) {
+ checkArgument(itemCount == 1);
+ if (positionStart < mBreakPosition) {
+ mBreakPosition++;
+ }
+ notifyItemRangeInserted(toViewPosition(positionStart), itemCount);
+ }
+
+ public void onItemRangeRemoved(int positionStart, int itemCount) {
+ checkArgument(itemCount == 1);
+ if (positionStart < mBreakPosition) {
+ mBreakPosition--;
+ }
+ notifyItemRangeRemoved(toViewPosition(positionStart), itemCount);
+ }
+
+ public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 4caa891fa24e..12c0b8fcd228 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -174,7 +174,7 @@ public class RootInfo implements Durable, Parcelable {
derivedIcon = R.drawable.ic_root_home;
derivedType = TYPE_LOCAL;
} else if (isExternalStorage()) {
- derivedIcon = R.drawable.ic_root_sdcard;
+ derivedIcon = R.drawable.ic_root_smartphone;
derivedType = TYPE_LOCAL;
} else if (isDownloads()) {
derivedIcon = R.drawable.ic_root_download;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
new file mode 100644
index 000000000000..5ce1823d6a21
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.dirlist;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.support.v7.widget.RecyclerView;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import com.android.documentsui.State;
+
+import java.util.List;
+
+@SmallTest
+public class ModelBackedDocumentsAdapterTest extends AndroidTestCase {
+
+ private static final String AUTHORITY = "test_authority";
+ private static final String[] NAMES = new String[] {
+ "4",
+ "foo",
+ "1",
+ "bar",
+ "*(Ljifl;a",
+ "0",
+ "baz",
+ "2",
+ "3",
+ "%$%VD"
+ };
+
+ private TestModel mModel;
+ private ModelBackedDocumentsAdapter mAdapter;
+
+ public void setUp() {
+
+ final Context testContext = TestContext.createStorageTestContext(getContext(), AUTHORITY);
+ mModel = new TestModel(testContext, AUTHORITY);
+ mModel.update(NAMES);
+
+ DocumentsAdapter.Environment env = new TestEnvironment(testContext);
+
+ mAdapter = new ModelBackedDocumentsAdapter(
+ env, new IconHelper(testContext, State.MODE_GRID));
+ mAdapter.onModelUpdate(mModel);
+ }
+
+ // Tests that the item count is correct.
+ public void testItemCount() {
+ assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
+ }
+
+ // Tests that the item count is correct.
+ public void testHide_ItemCount() {
+ List<String> ids = mModel.getModelIds();
+ mAdapter.hide(ids.get(0), ids.get(1));
+ assertEquals(mModel.getItemCount() - 2, mAdapter.getItemCount());
+ }
+
+ // Tests that the items can be hidden and unhidden.
+ public void testUnhide_ItemCount() {
+ List<String> ids = mModel.getModelIds();
+ SparseArray<String> hidden = mAdapter.hide(ids.toArray(new String[ids.size()]));
+ mAdapter.unhide(hidden);
+ assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
+ }
+
+ // Tests that the items can be hidden and unhidden.
+ public void testUnhide_PreservesOrder() {
+ List<String> ids = mModel.getModelIds();
+ SparseArray<String> hidden = mAdapter.hide(
+ ids.get(0), ids.get(1), ids.get(5), ids.get(9));
+ mAdapter.unhide(hidden);
+
+ // Finally ensure the restored items are in the original order
+ // by checking them against the model.
+ for (int i = 0; i < mAdapter.getItemCount(); i++) {
+ assertEquals(mModel.idForPosition(i), mAdapter.getModelId(i));
+ }
+ }
+
+ private final class TestEnvironment implements DocumentsAdapter.Environment {
+ private final Context testContext;
+
+ private TestEnvironment(Context testContext) {
+ this.testContext = testContext;
+ }
+
+ @Override
+ public boolean isSelected(String id) {
+ return false;
+ }
+
+ @Override
+ public boolean isDocumentEnabled(String mimeType, int flags) {
+ return true;
+ }
+
+ @Override
+ public void initDocumentHolder(DocumentHolder holder) {}
+
+ @Override
+ public Model getModel() {
+ return mModel;
+ }
+
+ @Override
+ public State getDisplayState() {
+ return null;
+ }
+
+ @Override
+ public Context getContext() {
+ return testContext;
+ }
+
+ @Override
+ public int getColumnCount() {
+ return 4;
+ }
+
+ @Override
+ public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {}
+ }
+
+ private static class DummyListener implements Model.UpdateListener {
+ public void onModelUpdate(Model model) {}
+ public void onModelUpdateFailed(Exception e) {}
+ }
+
+ private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ public int getItemCount() { return 0; }
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return null;
+ }
+ }
+}
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 121eb41c4c2a..bed7c9c9a253 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
@@ -21,16 +21,10 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.database.Cursor;
import android.database.MatrixCursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
-import android.support.v7.widget.RecyclerView;
import android.test.AndroidTestCase;
-import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.SmallTest;
-import android.view.ViewGroup;
import com.android.documentsui.DirectoryResult;
import com.android.documentsui.RootCursorWrapper;
@@ -49,6 +43,7 @@ public class ModelTest extends AndroidTestCase {
private static final int ITEM_COUNT = 10;
private static final String AUTHORITY = "test_authority";
+
private static final String[] COLUMNS = new String[]{
RootCursorWrapper.COLUMN_AUTHORITY,
Document.COLUMN_DOCUMENT_ID,
@@ -57,23 +52,24 @@ public class ModelTest extends AndroidTestCase {
Document.COLUMN_SIZE,
Document.COLUMN_MIME_TYPE
};
- private static Cursor cursor;
+ private static final String[] NAMES = new String[] {
+ "4",
+ "foo",
+ "1",
+ "bar",
+ "*(Ljifl;a",
+ "0",
+ "baz",
+ "2",
+ "3",
+ "%$%VD"
+ };
+
+ private Cursor cursor;
private Context context;
private Model model;
private TestContentProvider provider;
- private static final String[] NAMES = new String[] {
- "4",
- "foo",
- "1",
- "bar",
- "*(Ljifl;a",
- "0",
- "baz",
- "2",
- "3",
- "%$%VD"
- };
public void setUp() {
setupTestContext();
@@ -97,7 +93,7 @@ public class ModelTest extends AndroidTestCase {
r.cursor = cursor;
// Instantiate the model with a dummy view adapter and listener that (for now) do nothing.
- model = new Model(context, new DummyAdapter());
+ model = new Model(context);
model.addUpdateListener(new DummyListener());
model.update(r);
}
@@ -326,32 +322,4 @@ public class ModelTest extends AndroidTestCase {
public void onModelUpdate(Model model) {}
public void onModelUpdateFailed(Exception e) {}
}
-
- private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
- public int getItemCount() { return 0; }
- public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return null;
- }
- }
-
- private static class TestContentProvider extends MockContentProvider {
- List<Uri> mDeleted = new ArrayList<>();
-
- @Override
- public Bundle call(String method, String arg, Bundle extras) {
- // Intercept and log delete method calls.
- if (DocumentsContract.METHOD_DELETE_DOCUMENT.equals(method)) {
- final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
- mDeleted.add(documentUri);
- return new Bundle();
- } else {
- return super.call(method, arg, extras);
- }
- }
-
- public void assertWasDeleted(DocumentInfo doc) {
- assertTrue(mDeleted.contains(doc.derivedUri));
- }
- }
}
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 59891350838e..e06199efbc3b 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
@@ -23,6 +23,7 @@ import android.util.SparseBooleanArray;
import com.android.documentsui.TestInputEvent;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+
import com.google.common.collect.Lists;
import java.util.ArrayList;
@@ -44,11 +45,13 @@ public class MultiSelectManagerTest extends AndroidTestCase {
private MultiSelectManager mManager;
private TestCallback mCallback;
private TestSelectionEnvironment mEnv;
+ private TestDocumentsAdapter mAdapter;
public void setUp() throws Exception {
mCallback = new TestCallback();
mEnv = new TestSelectionEnvironment(items);
- mManager = new MultiSelectManager(mEnv, MultiSelectManager.MODE_MULTIPLE);
+ mAdapter = new TestDocumentsAdapter(items);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_MULTIPLE);
mManager.addCallback(mCallback);
}
@@ -164,7 +167,7 @@ public class MultiSelectManagerTest extends AndroidTestCase {
}
public void testSingleSelectMode() {
- mManager = new MultiSelectManager(mEnv, MultiSelectManager.MODE_SINGLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
mManager.addCallback(mCallback);
longPress(20);
tap(13);
@@ -172,7 +175,7 @@ public class MultiSelectManagerTest extends AndroidTestCase {
}
public void testSingleSelectMode_ShiftTap() {
- mManager = new MultiSelectManager(mEnv, MultiSelectManager.MODE_SINGLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
mManager.addCallback(mCallback);
longPress(13);
shiftTap(20);
@@ -180,7 +183,7 @@ public class MultiSelectManagerTest extends AndroidTestCase {
}
public void testSingleSelectMode_ShiftDoesNotExtendSelection() {
- mManager = new MultiSelectManager(mEnv, MultiSelectManager.MODE_SINGLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
mManager.addCallback(mCallback);
longPress(20);
keyToPosition(22, true);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
index 3d6923fbc984..5c04db9d513e 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
@@ -20,7 +20,6 @@ import static com.android.documentsui.dirlist.MultiSelectManager.GridModel.NOT_S
import android.graphics.Point;
import android.graphics.Rect;
-import android.support.v7.widget.RecyclerView.AdapterDataObserver;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -28,7 +27,7 @@ import android.view.View;
import com.android.documentsui.dirlist.MultiSelectManager.GridModel;
-import java.util.List;
+import java.util.ArrayList;
import java.util.Set;
@SmallTest
@@ -38,15 +37,28 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
private static final int CHILD_VIEW_EDGE_PX = 100;
private static final int VIEWPORT_HEIGHT = 500;
- private static GridModel model;
- private static TestEnvironment env;
- private static Set<String> lastSelection;
- private static int viewWidth;
+ private GridModel model;
+ private TestEnvironment env;
+ private TestDocumentsAdapter adapter;
+ private Set<String> lastSelection;
+ private int viewWidth;
- private static void setUp(int numChildren, int numColumns) {
+ private void initData(final int numChildren, int numColumns) {
env = new TestEnvironment(numChildren, numColumns);
+ adapter = new TestDocumentsAdapter(new ArrayList<String>()) {
+ @Override
+ public String getModelId(int position) {
+ return Integer.toString(position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return numChildren;
+ }
+ };
+
viewWidth = VIEW_PADDING_PX + numColumns * (VIEW_PADDING_PX + CHILD_VIEW_EDGE_PX);
- model = new GridModel(env);
+ model = new GridModel(env, adapter);
model.addOnSelectionChangedListener(
new GridModel.OnSelectionChangedListener() {
@Override
@@ -64,7 +76,7 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
}
public void testSelectionLeftOfItems() {
- setUp(20, 5);
+ initData(20, 5);
model.startSelection(new Point(0, 10));
model.resizeSelection(new Point(1, 11));
assertSelected();
@@ -72,7 +84,7 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
}
public void testSelectionRightOfItems() {
- setUp(20, 4);
+ initData(20, 4);
model.startSelection(new Point(viewWidth - 1, 10));
model.resizeSelection(new Point(viewWidth - 2, 11));
assertSelected();
@@ -80,7 +92,7 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
}
public void testSelectionAboveItems() {
- setUp(20, 4);
+ initData(20, 4);
model.startSelection(new Point(10, 0));
model.resizeSelection(new Point(11, 1));
assertSelected();
@@ -88,7 +100,7 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
}
public void testSelectionBelowItems() {
- setUp(5, 4);
+ initData(5, 4);
model.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
model.resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
assertSelected();
@@ -96,7 +108,7 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
}
public void testVerticalSelectionBetweenItems() {
- setUp(20, 4);
+ initData(20, 4);
model.startSelection(new Point(106, 0));
model.resizeSelection(new Point(107, 200));
assertSelected();
@@ -104,7 +116,7 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
}
public void testHorizontalSelectionBetweenItems() {
- setUp(20, 4);
+ initData(20, 4);
model.startSelection(new Point(0, 105));
model.resizeSelection(new Point(200, 106));
assertSelected();
@@ -112,7 +124,7 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
}
public void testGrowingAndShrinkingSelection() {
- setUp(20, 4);
+ initData(20, 4);
model.startSelection(new Point(0, 0));
model.resizeSelection(new Point(5, 5));
assertSelected(0);
@@ -142,7 +154,7 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
}
public void testSelectionMovingAroundOrigin() {
- setUp(16, 4);
+ initData(16, 4);
model.startSelection(new Point(210, 210));
model.resizeSelection(new Point(viewWidth - 1, 0));
assertSelected(2, 3, 6, 7);
@@ -156,7 +168,7 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
}
public void testScrollingBandSelect() {
- setUp(40, 4);
+ initData(40, 4);
model.startSelection(new Point(0, 0));
model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
assertSelected(0, 4, 8, 12, 16);
@@ -173,14 +185,14 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
assertEquals(0, model.getPositionNearestOrigin());
}
- private static void assertSelected(int... selectedPositions) {
+ private void assertSelected(int... selectedPositions) {
assertEquals(selectedPositions.length, lastSelection.size());
for (int position : selectedPositions) {
assertTrue(lastSelection.contains(Integer.toString(position)));
}
}
- private static void scroll(int dy) {
+ private void scroll(int dy) {
assertTrue(env.verticalOffset + VIEWPORT_HEIGHT + dy <= env.getTotalHeight());
env.verticalOffset += dy;
model.onScrolled(null, 0, dy);
@@ -322,30 +334,5 @@ public class MultiSelectManager_GridModelTest extends AndroidTestCase {
public void focusItem(int i) {
throw new UnsupportedOperationException();
}
-
- @Override
- public String getModelIdFromAdapterPosition(int position) {
- return Integer.toString(position);
- }
-
- @Override
- public int getItemCount() {
- return mNumChildren;
- }
-
- @Override
- public List<String> getModelIds() {
- return null;
- }
-
- @Override
- public void notifyItemChanged(String id) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void registerDataObserver(AdapterDataObserver observer) {
- throw new UnsupportedOperationException();
- }
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.java
new file mode 100644
index 000000000000..c8d424f10eae
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.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.dirlist;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.test.mock.MockContentProvider;
+
+import com.android.documentsui.model.DocumentInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A very simple test double for ContentProvider. Useful in this package only.
+ */
+class TestContentProvider extends MockContentProvider {
+ List<Uri> mDeleted = new ArrayList<>();
+
+ @Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ // Intercept and log delete method calls.
+ if (DocumentsContract.METHOD_DELETE_DOCUMENT.equals(method)) {
+ final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
+ mDeleted.add(documentUri);
+ return new Bundle();
+ } else {
+ return super.call(method, arg, extras);
+ }
+ }
+
+ public void assertWasDeleted(DocumentInfo doc) {
+ ModelTest.assertTrue(mDeleted.contains(doc.derivedUri));
+ }
+} \ No newline at end of file
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java
new file mode 100644
index 000000000000..714062d5007c
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java
@@ -0,0 +1,41 @@
+/*
+ * 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.dirlist;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.test.mock.MockContentResolver;
+
+public final class TestContext {
+
+ /**
+ * Returns a Context configured with test provider for authority.
+ */
+ static Context createStorageTestContext(Context context, String authority) {
+ final MockContentResolver testResolver = new MockContentResolver();
+ TestContentProvider provider = new TestContentProvider();
+ testResolver.addProvider(authority, provider);
+
+ return new ContextWrapper(context) {
+ @Override
+ public ContentResolver getContentResolver() {
+ return testResolver;
+ }
+ };
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
new file mode 100644
index 000000000000..267f47d80d3f
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
@@ -0,0 +1,82 @@
+/*
+ * 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.dirlist;
+
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A skeletal {@link DocumentsAdapter} test double.
+ */
+public class TestDocumentsAdapter extends DocumentsAdapter {
+
+ List<String> mModelIds = new ArrayList<>();
+
+ public TestDocumentsAdapter(List<String> modelIds) {
+ mModelIds = modelIds;
+ }
+
+ @Override
+ public void onModelUpdate(Model model) {
+ }
+
+ @Override
+ public void onModelUpdateFailed(Exception e) {
+ }
+
+ @Override
+ List<String> getModelIds() {
+ return mModelIds;
+ }
+
+ @Override
+ void onItemSelectionChanged(String id) {
+ }
+
+ @Override
+ String getModelId(int position) {
+ return mModelIds.get(position);
+ }
+
+ @Override
+ public SparseArray<String> hide(String... ids) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ void unhide(SparseArray<String> ids) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onBindViewHolder(DocumentHolder holder, int position) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getItemCount() {
+ return mModelIds.size();
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
new file mode 100644
index 000000000000..3a537a6f5ea3
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
@@ -0,0 +1,86 @@
+/*
+ * 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.dirlist;
+
+import android.content.Context;
+import android.database.MatrixCursor;
+import android.provider.DocumentsContract.Document;
+
+import com.android.documentsui.DirectoryResult;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+
+import java.util.Random;
+import java.util.Set;
+
+public class TestModel extends Model {
+
+ private static final String[] COLUMNS = new String[]{
+ RootCursorWrapper.COLUMN_AUTHORITY,
+ Document.COLUMN_DOCUMENT_ID,
+ Document.COLUMN_FLAGS,
+ Document.COLUMN_DISPLAY_NAME,
+ Document.COLUMN_SIZE,
+ Document.COLUMN_MIME_TYPE
+ };
+
+ private final String mAuthority;
+ private Set<String> mDeleted;
+
+ /**
+ * Creates a new context. context must be configured with provider for authority.
+ * @see TestContext#createStorageTestContext(Context, String).
+ */
+ public TestModel(Context context, String authority) {
+ super(context);
+ mAuthority = authority;
+ }
+
+ void update(String... names) {
+ Random rand = new Random();
+
+ MatrixCursor c = new MatrixCursor(COLUMNS);
+ for (int i = 0; i < names.length; i++) {
+ MatrixCursor.RowBuilder row = c.newRow();
+ row.add(RootCursorWrapper.COLUMN_AUTHORITY, mAuthority);
+ row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+ row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_DELETE);
+ // Generate random document names and sizes. This forces the model's internal sort code
+ // to actually do something.
+ row.add(Document.COLUMN_DISPLAY_NAME, names[i]);
+ row.add(Document.COLUMN_SIZE, rand.nextInt());
+ }
+
+ DirectoryResult r = new DirectoryResult();
+ r.cursor = c;
+ update(r);
+ }
+
+ // Note that model id includes authority qualifier and is distinct
+ // WRT documentId because of this.
+ String idForPosition(int p) {
+ return createModelId(mAuthority, Integer.toString(p));
+ }
+
+ @Override
+ public void delete(Selection selected, DeletionListener listener) {
+ for (String id : selected.getAll()) {
+ mDeleted.add(id);
+ }
+ listener.onCompletion();
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
index fc85f2b2962e..c4cfd3a06104 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
@@ -18,7 +18,6 @@ package com.android.documentsui.dirlist;
import android.graphics.Point;
import android.graphics.Rect;
-import android.support.v7.widget.RecyclerView.AdapterDataObserver;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.view.View;
@@ -28,10 +27,7 @@ import java.util.List;
public class TestSelectionEnvironment implements SelectionEnvironment {
- private List<String> mItems;
-
public TestSelectionEnvironment(List<String> items) {
- mItems = items;
}
@Override
@@ -114,27 +110,4 @@ public class TestSelectionEnvironment implements SelectionEnvironment {
@Override
public void focusItem(int position) {
}
-
- @Override
- public String getModelIdFromAdapterPosition(int position) {
- return mItems.get(position);
- }
-
- @Override
- public int getItemCount() {
- return mItems.size();
- }
-
- @Override
- public List<String> getModelIds() {
- return null;
- }
-
- @Override
- public void notifyItemChanged(String id) {
- }
-
- @Override
- public void registerDataObserver(AdapterDataObserver observer) {
- }
}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index bc09f3a75d54..c6e55314770a 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -579,6 +579,10 @@ public class ExternalStorageProvider extends DocumentsProvider {
public AssetFileDescriptor openDocumentThumbnail(
String documentId, Point sizeHint, CancellationSignal signal)
throws FileNotFoundException {
+ if (mArchiveHelper.isArchivedDocument(documentId)) {
+ return mArchiveHelper.openDocumentThumbnail(documentId, sizeHint, signal);
+ }
+
final File file = getFileForDocId(documentId);
return DocumentsContract.openImageThumbnail(file);
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 57a68ba7c9ee..3573536b37e6 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -245,7 +245,6 @@ public class MtpDocumentsProvider extends DocumentsProvider {
void closeDevice(int deviceId) throws IOException, InterruptedException {
synchronized (mDeviceListLock) {
closeDeviceInternal(deviceId);
- mDatabase.removeDeviceRows(deviceId);
}
mRootScanner.resume();
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
index ed617e71aeb2..5e95e4f88386 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
@@ -61,8 +61,9 @@ public class MtpManagerTest extends InstrumentationTestCase {
@Override
public Boolean call() throws IOException {
try {
- mManager.readEvent(mUsbDevice.getDeviceId(), signal);
- return false;
+ while (true) {
+ mManager.readEvent(mUsbDevice.getDeviceId(), signal);
+ }
} catch (OperationCanceledException exception) {
return true;
}
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 5a6f1d1f1a31..af9d25196bec 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -17,9 +17,7 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.printspooler"
- android:versionName="1"
- android:versionCode="1">
+ package="com.android.printspooler">
<!-- Allows an application to call APIs that give it access to all print jobs
on the device. Usually an app can access only the print jobs it created. -->
@@ -40,6 +38,8 @@
<uses-permission android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<application
android:allowClearUserData="true"
diff --git a/packages/PrintSpooler/res/drawable/ic_info.xml b/packages/PrintSpooler/res/drawable/ic_info.xml
new file mode 100644
index 000000000000..2ecd1c79d23e
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/ic_info.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"
+ android:fillColor="#757575"/>
+</vector> \ No newline at end of file
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
index 4381a7a32647..e0efbc42a627 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
@@ -62,7 +62,7 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:visibility="gone"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?android:attr/textColorSecondary"
android:duplicateParentState="true">
</TextView>
diff --git a/packages/PrintSpooler/res/layout/printer_list_item.xml b/packages/PrintSpooler/res/layout/printer_list_item.xml
index 7bc144aee156..50f44c21656c 100644
--- a/packages/PrintSpooler/res/layout/printer_list_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_list_item.xml
@@ -38,6 +38,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
+ android:layout_weight="1"
android:duplicateParentState="true">
<TextView
@@ -62,10 +63,20 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:visibility="gone"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?android:attr/textColorSecondary"
android:duplicateParentState="true">
</TextView>
</LinearLayout>
+ <ImageView
+ android:id="@+id/more_info"
+ android:layout_width="24dip"
+ android:layout_height="24dip"
+ android:layout_gravity="center_vertical"
+ android:contentDescription="@string/printer_info_desc"
+ android:src="@drawable/ic_info"
+ android:visibility="gone">
+ </ImageView>
+
</LinearLayout>
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index f263af7ece2d..0f34e9ec92f0 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> drukkers gevind</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> drukker gevind</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Meer inligting oor hierdie drukker"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Kies drukdiens"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Soek tans vir drukkers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Geen drukdienste is geaktiveer nie"</string>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index a93e0a96eceb..a6e1abfd753b 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ተገኝተዋል</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ተገኝተዋል</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ተጨማሪ የዚህ አታሚ መረጃ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"የህትመት አገልግሎት ይምረጡ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"አታሚዎችን በመፈለግ ላይ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ምንም የህትመት አገልግሎቶች አልነቁም"</string>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index c9a6a395d636..0291b7d9670c 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -63,6 +63,8 @@
<item quantity="other">تم العثور على <xliff:g id="COUNT_1">%1$s</xliff:g> من الطابعات</item>
<item quantity="one">تم العثور على طابعة واحدة (<xliff:g id="COUNT_0">%1$s</xliff:g>)</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"مزيد من المعلومات حول هذه الطابعة"</string>
<string name="choose_print_service" msgid="3740309762324459694">"اختر خدمة طباعة"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"البحث عن طابعات"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"لم يتم تمكين أي خدمات طباعة"</string>
diff --git a/packages/PrintSpooler/res/values-az-rAZ/strings.xml b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
index 5aeb7bb6d299..e1627936ecdb 100644
--- a/packages/PrintSpooler/res/values-az-rAZ/strings.xml
+++ b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printer tapıldı</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer tapıldı</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Bu printer haqqında daha ətraflı məlumat"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Çap xidmətini seçin"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printer axtarılır"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Heç bir çap xidməti aktiv edilməyib"</string>
diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
index 748471842b58..d6e439cdf642 100644
--- a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
+++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
@@ -60,6 +60,8 @@
<item quantity="few">Pronađena su <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
<item quantity="other">Pronađeno je <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Još informacija o ovom štampaču"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Izaberite uslugu štampanja"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Pretraga štampača"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nijedna usluga štampanja nije omogućena"</string>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 93feea512fb1..c23935437aae 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Намерени са <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
<item quantity="one">Намерен е <xliff:g id="COUNT_0">%1$s</xliff:g> принтер</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Още информация за този принтер"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Избиране на услуга за отпечатване"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Търсене на принтери"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Няма активирани услуги за отпечатване"</string>
diff --git a/packages/PrintSpooler/res/values-bn-rBD/strings.xml b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
index 0eed9aae9548..17a1a3541796 100644
--- a/packages/PrintSpooler/res/values-bn-rBD/strings.xml
+++ b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পাওয়া গেছে</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পাওয়া গেছে</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"এই মুদ্রকটির বিষয়ে আরো তথ্য"</string>
<string name="choose_print_service" msgid="3740309762324459694">"মুদ্রণ পরিষেবা চয়ন করুন"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"মুদ্রকগুলি অনুসন্ধান করা হচ্ছে"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"মুদ্রণ পরিষেবা সক্ষম নেই"</string>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index 03d3060968db..25512067ce87 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">S\'han trobat <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item>
<item quantity="one">S\'ha trobat <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Més informació sobre aquesta impressora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Selecció del servei d\'impressió"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Cerca d\'impressores"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No hi ha cap servei d\'impressió activat"</string>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 414abf9fc798..0bb48f8e199e 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -61,6 +61,8 @@
<item quantity="other">Nalezené tiskárny: <xliff:g id="COUNT_1">%1$s</xliff:g></item>
<item quantity="one">Nalezené tiskárny: <xliff:g id="COUNT_0">%1$s</xliff:g></item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Další informace o této tiskárně"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Zvolte službu tisku"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Vyhledávání tiskáren"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nejsou aktivovány žádné tiskové služby"</string>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 893c991a8316..a9d042b5c51a 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one">Der blev fundet <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
<item quantity="other">Der blev fundet <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Flere oplysninger om denne printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Vælg udskriftstjeneste"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Søger efter printere"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ingen udskrivningstjenester er aktiveret"</string>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index f6f53eaaf8d1..4eb5d6a94d5a 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> Drucker gefunden</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> Drucker gefunden</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Weitere Informationen über diesen Drucker"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Druckdienst auswählen"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Suche nach Druckern"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Keine Druckdienste aktiviert"</string>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 10ddf6251346..cd35785b528c 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Βρέθηκαν <xliff:g id="COUNT_1">%1$s</xliff:g> εκτυπωτές</item>
<item quantity="one">Βρέθηκε <xliff:g id="COUNT_0">%1$s</xliff:g> εκτυπωτής</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Περισσότερες πληροφορίες σχετικά με αυτόν τον εκτυπωτή"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Επιλέξτε υπηρεσία εκτύπωσης"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Αναζήτηση για εκτυπωτές"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Δεν έχουν ενεργοποιηθεί υπηρεσίες εκτύπωσης"</string>
diff --git a/packages/PrintSpooler/res/values-en-rAU/strings.xml b/packages/PrintSpooler/res/values-en-rAU/strings.xml
index a540ac5b4e1f..753d9dfc5bd8 100644
--- a/packages/PrintSpooler/res/values-en-rAU/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rAU/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer found</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index a540ac5b4e1f..753d9dfc5bd8 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer found</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index a540ac5b4e1f..753d9dfc5bd8 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer found</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index 8929aa81d7e1..1a0d5d85cec8 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Se encontraron <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras.</item>
<item quantity="one">Se encontró <xliff:g id="COUNT_0">%1$s</xliff:g> impresora.</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Más información sobre esta impresora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Elegir servicio de impresión"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No hay servicios de impresión habilitados"</string>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index 7cfd92abbed1..eac568d4bdfd 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Se han encontrado <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
<item quantity="one">Se ha encontrado <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Más información sobre esta impresora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Seleccionar servicio de impresión"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No hay servicios de impresión habilitados"</string>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index ee93bcfc5c25..2cde25886420 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Leiti <xliff:g id="COUNT_1">%1$s</xliff:g> printerit</item>
<item quantity="one">Leiti <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Lisateave selle printeri kohta"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Prinditeenuse valimine"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printerite otsimine"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ühtegi printimisteenust pole lubatud"</string>
diff --git a/packages/PrintSpooler/res/values-eu-rES/strings.xml b/packages/PrintSpooler/res/values-eu-rES/strings.xml
index 882e8885183a..96a3273f47ad 100644
--- a/packages/PrintSpooler/res/values-eu-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-eu-rES/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> inprimagailu aurkitu dira</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> inprimagailu aurkitu da</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Informazio gehiago inprimagailuari buruz"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Aukeratu inprimatze-zerbitzua"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Inprimagailuak bilatzen"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ez dago gaituta inprimatzeko zerbitzurik"</string>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 10743e731855..fdc39892836f 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر یافت شد</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر یافت شد</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"اطلاعات بیشتر درباره چاپگر"</string>
<string name="choose_print_service" msgid="3740309762324459694">"انتخاب سرویس چاپ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"درحال جستجوی چاپگرها"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"هیچ خدمات چاپی فعال نیست"</string>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index ee35c41d4e6e..926739398cc7 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> tulostinta löydetty</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> tulostin löydetty</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Lisätietoja tästä tulostimesta"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Valitse tulostuspalvelu"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Etsitään tulostimia"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ei käytössä olevia tulostuspalveluita"</string>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index eb9944186081..bfb4862f249d 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvées</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Plus d\'information sur cette imprimante"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Sélectionner le service d\'impression"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes en cours..."</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Aucun service d\'impression activé"</string>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index c0eecfbd9198..de55e29a2140 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes trouvées</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Plus d\'informations sur cette imprimante"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Sélectionner le service d\'impression"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes en cours"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Aucun service d\'impression activé"</string>
diff --git a/packages/PrintSpooler/res/values-gl-rES/strings.xml b/packages/PrintSpooler/res/values-gl-rES/strings.xml
index b4a1ec668eef..dc66084e7894 100644
--- a/packages/PrintSpooler/res/values-gl-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-gl-rES/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Encontráronse <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
<item quantity="one">Encontrouse <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Máis información sobre esta impresora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Escoller servizo de impresión"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Busca de impresoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Non hai servizos de impresión activados"</string>
diff --git a/packages/PrintSpooler/res/values-gu-rIN/strings.xml b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
index 8f779530f829..d05a3929ffbb 100644
--- a/packages/PrintSpooler/res/values-gu-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> પ્રિન્ટર્સ મળ્યાં</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> પ્રિન્ટર્સ મળ્યાં</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"આ પ્રિન્ટર વિશે વધુ માહિતી"</string>
<string name="choose_print_service" msgid="3740309762324459694">"પ્રિન્ટ સેવા પસંદ કરો"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"પ્રિન્ટર્સ માટે શોધી રહ્યું છે"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"કોઈ છાપ સેવાઓ સક્ષમ કરેલ નથી"</string>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 4c11323e8dfa..8051900aaeee 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर मिले</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर मिले</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"इस प्रिंटर के बारे में अधिक जानकारी"</string>
<string name="choose_print_service" msgid="3740309762324459694">"प्रिंट सेवा चुनें"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर खोज रहा है"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"कोई भी प्रिंट सेवा सक्षम नहीं है"</string>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 4cec3baf7a8d..4dab4cc90e1e 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -60,6 +60,8 @@
<item quantity="few">Pronađena su <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
<item quantity="other">Pronađeno je <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Više informacija o ovom pisaču"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Odaberite uslugu ispisa"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Traženje pisača"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nije omogućena nijedna usluga ispisa"</string>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index ac1ba6eebe64..1a56ee73f707 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> nyomtató észlelve</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> nyomtató észlelve</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"További információ erről a nyomtatóról"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Nyomtatási szolgáltatás kiválasztása"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Nyomtatók keresése"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nincs engedélyezett nyomtatási szolgáltatás"</string>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index dda674548085..7b99dcfac642 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one">Գտնվել է <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ</item>
<item quantity="other">Գտնվել է <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Հավելյալ տեղեկություններ այս տպիչի մասին"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Ընտրեք տպելու ծառայությունը"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Տպիչների որոնում"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ակտիվացված տպման ծառայություններ չկան"</string>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index b203e2b2a6de..a9912722ecb0 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printer ditemukan</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer ditemukan</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Informasi selengkapnya tentang printer ini"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Pilih layanan cetak"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Mencari printer"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Tidak ada layanan cetak yang aktif"</string>
diff --git a/packages/PrintSpooler/res/values-is-rIS/strings.xml b/packages/PrintSpooler/res/values-is-rIS/strings.xml
index 6dfdabc78f5e..e93f7023f5ea 100644
--- a/packages/PrintSpooler/res/values-is-rIS/strings.xml
+++ b/packages/PrintSpooler/res/values-is-rIS/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> prentari fannst</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> prentarar fundust</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Frekari upplýsingar um þennan prentara"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Veldu prentþjónustu"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Leitar að prentara"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Engin prentþjónusta er virk"</string>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index fd5473a2c281..ffba3533a7fa 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> stampanti trovate</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> stampante trovata</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Ulteriori informazioni su questa stampante"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Scegli servizio di stampa"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Ricerca di stampanti"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Non è stato attivato alcun servizio di stampa"</string>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index dd062a35501c..2ac109303cc0 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -61,6 +61,8 @@
<item quantity="other">נמצאו <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
<item quantity="one">נמצאה מדפסת <xliff:g id="COUNT_0">%1$s</xliff:g></item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"מידע נוסף על מדפסת זו"</string>
<string name="choose_print_service" msgid="3740309762324459694">"בחר שירות הדפסה"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"מחפש מדפסות"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"לא הופעלו שירותי הדפסה"</string>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index 23e480953f8f..2c3c24de413d 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>台のプリンタが見つかりました</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>台のプリンタが見つかりました</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"このプリンタの詳細"</string>
<string name="choose_print_service" msgid="3740309762324459694">"印刷サービスの選択"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"プリンタの検索中"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"使用できる印刷サービスがありません"</string>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index 9f86f052d480..2b0285dc0c06 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> პრინტერი ნაპოვნია</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> პრინტერი ნაპოვნია</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> — <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"დამატებითი ინფორმაცია ამ პრინტერის შესახებ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"აირჩიეთ ბეჭდვის სერვისი"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"მიმდინარეობს პრინტერების ძიება"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ბეჭდვის სერვისები გააქტიურებული არ არის"</string>
diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
index 05c300edc92b..fc099c9772d0 100644
--- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
+++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> принтер табылды</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> принтер табылды</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Осы принтер туралы қосымша ақпарат"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Принтер қызметін таңдау"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Принтерлерді іздеу"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Басып шығару қызметтері қосылмаған"</string>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index 0861e59a9d97..b51091e803a8 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">រកឃើញម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_1">%1$s</xliff:g></item>
<item quantity="one">រកឃើញម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_0">%1$s</xliff:g></item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ព័ត៌មានបន្ថែមអំពីម៉ាស៊ីបោះពុម្ពនេះ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"ជ្រើស​សេវា​បោះពុម្ព"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ស្វែងរក​ម៉ាស៊ីន​បោះពុម្ព"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"គ្មានការបើកដំណើរការសេវាបោះពុម្ពទេ"</string>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index 71b098d830c9..5d5dee86654c 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್‌ಗಳು ಪತ್ತೆಯಾಗಿವೆ</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್‌ಗಳು ಪತ್ತೆಯಾಗಿವೆ</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ಈ ಪ್ರಿಂಟರ್ ಬಗ್ಗೆ ಇನ್ನಷ್ಟು ಮಾಹಿತಿ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"ಮುದ್ರಣ ಸೇವೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ಪ್ರಿಂಟರ್‌‌ಗಳಿಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ಯಾವುದೇ ಮುದ್ರಣ ಸೇವೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿಲ್ಲ"</string>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index 451ab58fcc35..98617e7841ee 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">프린터 <xliff:g id="COUNT_1">%1$s</xliff:g>대 검색됨</item>
<item quantity="one">프린터 <xliff:g id="COUNT_0">%1$s</xliff:g>대 검색됨</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"이 프린터에 대한 정보 더보기"</string>
<string name="choose_print_service" msgid="3740309762324459694">"인쇄 서비스 선택"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"프린터 검색 중"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"사용 가능한 프린트 서비스 없음"</string>
diff --git a/packages/PrintSpooler/res/values-ky-rKG/strings.xml b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
index 98da08cd316e..2a11ff86508b 100644
--- a/packages/PrintSpooler/res/values-ky-rKG/strings.xml
+++ b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> принтер табылды</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> принтер табылды</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Бул принтер жөнүндө көбүрөөк маалымат"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Принтер кызматын тандоо"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Принтерлер изделүүдө"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Принтер-кызматтары иштетилген эмес"</string>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index 2029fdfd6fbf..788e5aaaf036 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ເຄື່ອງ​ພິມ​ຖືກ​ພົບ​ແລ້ວ</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ເຄື່ອງ​ພິມ​ຖືກ​ພົບ​ແລ້ວ</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບເຄື່ອງພິມນີ້"</string>
<string name="choose_print_service" msgid="3740309762324459694">"ເລືອກບໍລິການການພິມ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ກຳລັງຊອກຫາເຄື່ອງພິມ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ບໍ່​ມີ​ການ​ບໍ​ລິ​ການ​ພິມ​ເປີດ​ໃຊ້​ງານ​ໄວ້"</string>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 972abb5922e0..1826e8ee283e 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -61,6 +61,8 @@
<item quantity="many">Rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvo</item>
<item quantity="other">Rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvų</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"„<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g>“ – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Daugiau informacijos apie šį spausdintuvą"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Pasirinkite spausdinimo paslaugą"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Ieškoma spausdintuvų"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Neįgalinta jokių spausdinimo paslaugų"</string>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index f565b2318407..5c17efe402ff 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -60,6 +60,8 @@
<item quantity="one">Atrasts <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Atrasti <xliff:g id="COUNT_1">%1$s</xliff:g> printeri</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> — <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Plašāka informācija par šo printeri"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Izvēlieties drukāšanas pakalpojumu"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printeru meklēšana"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nav iespējots neviens drukas pakalpojums"</string>
diff --git a/packages/PrintSpooler/res/values-mk-rMK/strings.xml b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
index f5c06d1845c7..ebc1181f0d46 100644
--- a/packages/PrintSpooler/res/values-mk-rMK/strings.xml
+++ b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one">Пронајдени се <xliff:g id="COUNT_1">%1$s</xliff:g> печатач</item>
<item quantity="other">Пронајдени се <xliff:g id="COUNT_1">%1$s</xliff:g> печатачи</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Повеќе информации за овој печатач"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Избери услуга печатење"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Пребарување печатачи"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Нема овозможени услуги за печатење"</string>
diff --git a/packages/PrintSpooler/res/values-ml-rIN/strings.xml b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
index 2d45ce5a29e0..c08a3d417744 100644
--- a/packages/PrintSpooler/res/values-ml-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> പ്രിന്ററുകൾ കണ്ടെത്തി</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> പ്രിന്റർ കണ്ടെത്തി</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ഈ പ്രിന്ററിനെ കുറിച്ചുള്ള കൂടുതൽ വിവരങ്ങൾ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"പ്രിന്റ് സേവനം തിരഞ്ഞെടുക്കുക"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"പ്രിന്ററുകൾക്കായി തിരയുന്നു"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"പ്രിന്റ് സേവനങ്ങളൊന്നും പ്രവർത്തനക്ഷമാക്കിയിട്ടില്ല"</string>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index f2c7b73f79d2..dcef28f0a4e8 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> хэвлэгч олдсон байна</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> хэвлэгч олдсон байна</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Энэ хэвлэгчийн талаарх дэлгэрэнгүй мэдээлэл"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Хэвлэх үйлчилгээг сонгох"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Принтер хайж байна"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Хэвлэх үйлчилгээг идэвхжүүлээгүй"</string>
diff --git a/packages/PrintSpooler/res/values-mr-rIN/strings.xml b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
index 1c079dc63bf4..384f0ded5386 100644
--- a/packages/PrintSpooler/res/values-mr-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर आढळला</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर आढळले</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"या प्रिंटर विषयी अधिक माहिती"</string>
<string name="choose_print_service" msgid="3740309762324459694">"मुद्रण सेवा निवडा"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर शोधत आहे"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"कोणत्याही मुद्रण सेवा सक्षम केलेल्या नाहीत"</string>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index d6b5ea708814..19a6e765751d 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> pencetak ditemui</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> pencetak ditemui</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Maklumat lanjut tentang pencetak ini"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Pilih perkhidmatan cetak"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Mencari pencetak"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Perkhidmatan cetak tidak didayakan"</string>
diff --git a/packages/PrintSpooler/res/values-my-rMM/strings.xml b/packages/PrintSpooler/res/values-my-rMM/strings.xml
index c3dc4902ea0a..d3c0672b88e0 100644
--- a/packages/PrintSpooler/res/values-my-rMM/strings.xml
+++ b/packages/PrintSpooler/res/values-my-rMM/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> စာထုတ်စက်များ တွေ့ရှိပါသည်</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>စာထုတ်စက် တွေ့ရှိပါသည်</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ဤပရင်တာ အကြောင်း ပိုမိုလေ့လာပါ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"စာထုတ်ရန် ဝန်ဆောင်မှုကို ရွေးချယ်ပါ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"စာထုတ်စက်များကို ရှာနေပါသည်"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ပုံနှိပ်ထုတ်ယူရေး ဝန်ဆောင်မှုများ ဖွင့်မထားပါ"</string>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index 945bbea59e04..c34e7bce0404 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> skrivere ble funnet</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> skriver ble funnet</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mer informasjon om denne printeren"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Velg utskriftstjeneste"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Søker etter skrivere"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ingen utskriftstjenester er slått på"</string>
diff --git a/packages/PrintSpooler/res/values-ne-rNP/strings.xml b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
index 45bcc95ad5b3..d1959d9c6393 100644
--- a/packages/PrintSpooler/res/values-ne-rNP/strings.xml
+++ b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिन्टरहरू भेटिए</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> प्रिन्टर भेटियो</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"यस प्रिन्टरको बारेमा थप जानकारी"</string>
<string name="choose_print_service" msgid="3740309762324459694">"प्रिन्ट सेवा छनौट गर्नुहोस्"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिन्टरहरू खोज्दै"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"कुनै पनि मुद्रण सेवाहरू सक्रिय छैनन्"</string>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 76c86564d6f3..5df3298fd1aa 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers gevonden</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer gevonden</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Meer informatie over deze printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Afdrukservice kiezen"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printers zoeken"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Geen afdrukservices ingeschakeld"</string>
diff --git a/packages/PrintSpooler/res/values-pa-rIN/strings.xml b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
index 45fa460765b8..57e9969d4e7d 100644
--- a/packages/PrintSpooler/res/values-pa-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> ਪ੍ਰਿੰਟਰ ਮਿਲੇ</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ਪ੍ਰਿੰਟਰ ਮਿਲੇ</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ਇਸ ਪ੍ਰਿੰਟਰ ਬਾਰੇ ਹੋਰ ਜਾਣਕਾਰੀ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"ਪ੍ਰਿੰਟ ਸੇਵਾ ਚੁਣੋ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ਪ੍ਰਿੰਟਰ ਖੋਜ ਰਿਹਾ ਹੈ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ਪ੍ਰਿੰਟ ਸੇਵਾਵਾਂ ਯੋਗ ਨਹੀਂ ਬਣਾਈਆਂ ਗਈਆਂ"</string>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index df3ee92460e2..4439acb5d7bd 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -61,6 +61,8 @@
<item quantity="other">Znaleziono <xliff:g id="COUNT_1">%1$s</xliff:g> drukarki</item>
<item quantity="one">Znaleziono <xliff:g id="COUNT_0">%1$s</xliff:g> drukarkę</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Więcej informacji o tej drukarce"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Wybierz usługę drukowania"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Szukanie drukarek"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Brak włączonych usług drukowania"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
index 90da72b235bc..63bb8686b725 100644
--- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mais informações sobre essa impressora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Selecione o serviço de impressão"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Procurando impressoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 99bbd81254b9..d364ef44442c 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mais informações acerca desta impressora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Escolher o serviço de impressão"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"A procurar impressoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 90da72b235bc..63bb8686b725 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mais informações sobre essa impressora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Selecione o serviço de impressão"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Procurando impressoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index 4cfb8ab2818d..51dfe7a6dc8d 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -60,6 +60,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> de imprimante găsite</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> imprimantă găsită</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mai multe informații despre această imprimantă"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Alegeți serviciul de printare"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Se caută imprimante"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Niciun serviciu de printare activat"</string>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index fb493306d5f6..6ba1046f1ddb 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -61,6 +61,8 @@
<item quantity="many">Найдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтеров</item>
<item quantity="other">Найдены <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Подробные сведения о принтере"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Выберите службу печати"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Поиск принтеров…"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Службы печати недоступны"</string>
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index fb6f145053e2..4908ea554263 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one">මුද්‍රණ යන්ත්‍ර <xliff:g id="COUNT_1">%1$s</xliff:g> ක් සොයා ගන්නා ලදි</item>
<item quantity="other">මුද්‍රණ යන්ත්‍ර <xliff:g id="COUNT_1">%1$s</xliff:g> ක් සොයා ගන්නා ලදි</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"මෙම මුද්‍රණ යන්ත්‍රය ගැන තවත් තොරතුරු"</string>
<string name="choose_print_service" msgid="3740309762324459694">"මුද්‍රණ සේවාව තෝරන්න"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"මුද්‍රණ යන්ත්‍ර සොයමින්"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"මුද්‍රණ සේවා සබල නැත"</string>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 605237b092b7..418363dfe4ff 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -61,6 +61,8 @@
<item quantity="other">Našlo sa <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarní</item>
<item quantity="one">Našla sa <xliff:g id="COUNT_0">%1$s</xliff:g> tlačiareň</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Ďalšie informácie o tejto tlačiarni"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Výber tlačovej služby"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Vyhľadávanie tlačiarní"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Žiadne tlačové služby nie sú aktivované"</string>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index 48d2e1dbc8b3..e2be161d5292 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -61,6 +61,8 @@
<item quantity="few"><xliff:g id="COUNT_1">%1$s</xliff:g> najdeni tiskalniki</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> najdenih tiskalnikov</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Več informacij o tem tiskalniku"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Izberite tiskalno storitev"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Iskanje tiskalnikov"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ni omogočenih tiskalnih storitev"</string>
diff --git a/packages/PrintSpooler/res/values-sq-rAL/strings.xml b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
index 5ba72ff6e033..d5ebf3266dfe 100644
--- a/packages/PrintSpooler/res/values-sq-rAL/strings.xml
+++ b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">U gjetën <xliff:g id="COUNT_1">%1$s</xliff:g> printerë</item>
<item quantity="one">U gjet <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Më shumë informacione mbi këtë printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Zgjidh shërbimin e printimit"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Po kërkon për printerë"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nuk ka shërbime printimi të aktivizuara"</string>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index 7a04b8d24efd..166e5dd07d4e 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -60,6 +60,8 @@
<item quantity="few">Пронађена су <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
<item quantity="other">Пронађено је <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Још информација о овом штампачу"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Изаберите услугу штампања"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Претрага штампача"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ниједна услуга штампања није омогућена"</string>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index ec4ad30b5896..033d58359684 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> skrivare hittades</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> skrivare hittades</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mer information om den här skrivaren"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Välj utskriftstjänst"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Söker efter skrivare"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Inga utskriftstjänster har aktiverats"</string>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index eed33560fb24..0e2dcdd109d2 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Printa <xliff:g id="COUNT_1">%1$s</xliff:g> zimepatikana</item>
<item quantity="one">Printa <xliff:g id="COUNT_0">%1$s</xliff:g> imepatikana</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Maelezo zaidi kuhusu printa hii"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Chagua huduma ya printa"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Inatafuta printa"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Huduma za kuchapisha hazijawashwa"</string>
diff --git a/packages/PrintSpooler/res/values-ta-rIN/strings.xml b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
index a9879c3756dc..2e90d382e7f2 100644
--- a/packages/PrintSpooler/res/values-ta-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> பிரிண்டர்கள் உள்ளன</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> பிரிண்டர் உள்ளது</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"இந்தப் பிரிண்டர் பற்றிய கூடுதல் தகவல்"</string>
<string name="choose_print_service" msgid="3740309762324459694">"அச்சுப் பொறியைத் தேர்வுசெய்யவும்"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"அச்சுப்பொறிகளைத் தேடுகிறது"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"அச்சுப் பொறிகள் இல்லை"</string>
diff --git a/packages/PrintSpooler/res/values-te-rIN/strings.xml b/packages/PrintSpooler/res/values-te-rIN/strings.xml
index 909cb9041762..6bdbd5c84139 100644
--- a/packages/PrintSpooler/res/values-te-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-te-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ప్రింటర్‌లు కనుగొనబడ్డాయి</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ప్రింటర్ కనుగొనబడింది</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ఈ ప్రింటర్ గురించి మరింత సమాచారం"</string>
<string name="choose_print_service" msgid="3740309762324459694">"ముద్రణ సేవను ఎంచుకోండి"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ప్రింటర్‌ల కోసం శోధిస్తోంది"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ముద్రణ సేవలు ఏవీ ప్రారంభించలేదు"</string>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index c33a759bef80..a581357dbcf7 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">พบเครื่องพิมพ์ <xliff:g id="COUNT_1">%1$s</xliff:g> เครื่อง</item>
<item quantity="one">พบเครื่องพิมพ์ <xliff:g id="COUNT_0">%1$s</xliff:g> เครื่อง</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ข้อมูลเพิ่มเติมเกี่ยวกับเครื่องพิมพ์นี้"</string>
<string name="choose_print_service" msgid="3740309762324459694">"เลือกบริการพิมพ์"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"กำลังค้นหาเครื่องพิมพ์"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ไม่ได้เปิดใช้บริการพิมพ์"</string>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index 545bda4bb52a..325ce8cb4983 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> nakitang printer</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> na nakitang printer</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Higit pang impormasyon tungkol sa printer na ito"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Pumili ng serbisyo ng pag-print"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Naghahanap ng mga printer"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Walang mga naka-enable na serbisyo sa pag-print"</string>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index a13f2dfdff22..d945979b8fe0 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> yazıcı bulundu</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> yazıcı bulundu</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Bu yazıcıyla ilgili daha fazla bilgi"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Yazdırma hizmetini seçin"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Yazıcılar aranıyor"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Etkin yazıcı hizmeti yok"</string>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index def21ab6cc1d..ffdfde068aed 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -61,6 +61,8 @@
<item quantity="many">Знайдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтерів</item>
<item quantity="other">Знайдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтерів</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Докладніше про цей принтер"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Вибрати службу друку"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Пошук принтерів"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Немає служб друку"</string>
diff --git a/packages/PrintSpooler/res/values-ur-rPK/strings.xml b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
index c031abab3694..72a6ab9f3c58 100644
--- a/packages/PrintSpooler/res/values-ur-rPK/strings.xml
+++ b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> پرنٹرز ملے</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> پرنٹر ملا</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"اس پرنٹر کے بارے میں مزید معلومات"</string>
<string name="choose_print_service" msgid="3740309762324459694">"پرنٹ سروس منتخب کریں"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"پرنٹرز تلاش کر رہا ہے"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"کوئی پرنٹ سروس فعال نہیں"</string>
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index 59dcca95575b..c7b4263e557b 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ta printer topildi</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ta printer topildi</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Printer haqida batafsil ma’lumot"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Chop etish xizmatini tanlang"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printerlar qidirilmoqda"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Hech qaysi chop etish xizmati yoqilmagan"</string>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index 0167823fab7b..771d57c8a342 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Đã tìm thấy <xliff:g id="COUNT_1">%1$s</xliff:g> máy in</item>
<item quantity="one">Đã tìm thấy <xliff:g id="COUNT_0">%1$s</xliff:g> máy in</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Thông tin khác về máy in này"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Chọn dịch vụ in"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Đang tìm kiếm máy in"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Chưa kích hoạt dịch vụ in nào"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index a74e99452307..bea91d7c2f2a 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 台打印机</item>
<item quantity="one">找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台打印机</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"关于此打印机的更多信息"</string>
<string name="choose_print_service" msgid="3740309762324459694">"选择打印服务"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜索打印机"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"未启用任何打印服务"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 35643f3702f8..4fbef0dbee32 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">已找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 部打印機</item>
<item quantity="one">已找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 部打印機</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"此打印機詳情"</string>
<string name="choose_print_service" msgid="3740309762324459694">"選擇列印服務"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜尋打印機"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"沒有已啟用的列印服務"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 40c44ff2d91c..2fdcaacb5d11 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 台印表機</item>
<item quantity="one">找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台印表機</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"查看這台印表機的詳細資訊"</string>
<string name="choose_print_service" msgid="3740309762324459694">"選擇列印服務"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜尋印表機"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"未啟用任何列印服務"</string>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index e0f6f341a7f2..92595aaba1d5 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> amaphrinta atholakele</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> amaphrinta atholakele</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Olunye ulwazi mayelana nale phrinta"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Khetha isevisi yephrinta"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Isesha amaphrinta"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Amasevisi ephrinta akavuliwe."</string>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 6d8178844fba..97a7bffe9bf3 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -144,6 +144,12 @@
<item quantity="other"><xliff:g id="count" example="2">%1$s</xliff:g> printers found</item>
</plurals>
+ <!-- Template for an extended description of a printer. [CHAR LIMIT=50] -->
+ <string name="printer_extended_description_template"><xliff:g id="print_service_label" example="Canon Print Service">%1$s</xliff:g> - <xliff:g id="printer_description" example="Printer under the stairs">%2$s</xliff:g></string>
+
+ <!-- Description of printer info icon. [CHAR LIMIT=50] -->
+ <string name="printer_info_desc">More information about this printer</string>
+
<!-- Add printer dialog -->
<!-- Title for the alert dialog for selecting a print service. [CHAR LIMIT=50] -->
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/CustomPrinterIconCache.java b/packages/PrintSpooler/src/com/android/printspooler/model/CustomPrinterIconCache.java
new file mode 100644
index 000000000000..72742686e736
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/CustomPrinterIconCache.java
@@ -0,0 +1,165 @@
+/*
+ * 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.printspooler.model;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.drawable.Icon;
+import android.print.PrinterId;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * A fixed size cache for custom printer icons. Old icons get removed with a last recently used
+ * policy.
+ */
+public class CustomPrinterIconCache {
+
+ private final static String LOG_TAG = "CustomPrinterIconCache";
+
+ /** Maximum number of icons in the cache */
+ private final static int MAX_SIZE = 1024;
+
+ /** Directory used to persist state and icons */
+ private final File mCacheDirectory;
+
+ /**
+ * Create a new icon cache.
+ */
+ public CustomPrinterIconCache(@NonNull File cacheDirectory) {
+ mCacheDirectory = new File(cacheDirectory, "icons");
+ if (!mCacheDirectory.exists()) {
+ mCacheDirectory.mkdir();
+ }
+ }
+
+ /**
+ * Return the file name to be used for the icon of a printer
+ *
+ * @param printerId the id of the printer
+ *
+ * @return The file to be used for the icon of the printer
+ */
+ private @Nullable File getIconFileName(@NonNull PrinterId printerId) {
+ StringBuffer sb = new StringBuffer(printerId.getServiceName().getPackageName());
+ sb.append("-");
+
+ try {
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ md.update(
+ (printerId.getServiceName().getClassName() + ":" + printerId.getLocalId())
+ .getBytes("UTF-16"));
+ sb.append(String.format("%#040x", new java.math.BigInteger(1, md.digest())));
+ } catch (UnsupportedEncodingException|NoSuchAlgorithmException e) {
+ Log.e(LOG_TAG, "Could not compute custom printer icon file name", e);
+ return null;
+ }
+
+ return new File(mCacheDirectory, sb.toString());
+ }
+
+ /**
+ * Get the {@link Icon} to be used as a custom icon for the printer. If not available request
+ * the icon to be loaded.
+ *
+ * @param printerId the printer the icon belongs to
+ * @return the {@link Icon} if already available or null if icon is not loaded yet
+ */
+ public synchronized @Nullable Icon getIcon(@NonNull PrinterId printerId) {
+ Icon icon;
+
+ File iconFile = getIconFileName(printerId);
+ if (iconFile != null && iconFile.exists()) {
+ try (FileInputStream is = new FileInputStream(iconFile)) {
+ icon = Icon.createFromStream(is);
+ } catch (IOException e) {
+ icon = null;
+ Log.e(LOG_TAG, "Could not read icon from " + iconFile, e);
+ }
+
+ // Touch file so that it is the not likely to be removed
+ iconFile.setLastModified(System.currentTimeMillis());
+ } else {
+ icon = null;
+ }
+
+ return icon;
+ }
+
+ /**
+ * Remove old icons so that only between numFilesToKeep and twice as many icons are left.
+ *
+ * @param numFilesToKeep the number of icons to keep
+ */
+ public void removeOldFiles(int numFilesToKeep) {
+ File files[] = mCacheDirectory.listFiles();
+
+ // To reduce the number of shrink operations, let the cache grow to twice the max size
+ if (files.length > numFilesToKeep * 2) {
+ SortedMap<Long, File> sortedFiles = new TreeMap<>();
+
+ for (File f : files) {
+ sortedFiles.put(f.lastModified(), f);
+ }
+
+ while (sortedFiles.size() > numFilesToKeep) {
+ sortedFiles.remove(sortedFiles.firstKey());
+ }
+ }
+ }
+
+ /**
+ * Handle that a custom icon for a printer was loaded
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ */
+ public synchronized void onCustomPrinterIconLoaded(@NonNull PrinterId printerId,
+ @Nullable Icon icon) {
+ File iconFile = getIconFileName(printerId);
+
+ if (iconFile == null) {
+ return;
+ }
+
+ try (FileOutputStream os = new FileOutputStream(iconFile)) {
+ icon.writeToStream(os);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Could not write icon for " + printerId + " to storage", e);
+ }
+
+ removeOldFiles(MAX_SIZE);
+ }
+
+ /**
+ * Clear all persisted and non-persisted state from this cache.
+ */
+ public synchronized void clear() {
+ for (File f : mCacheDirectory.listFiles()) {
+ f.delete();
+ }
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index 82fd51233ef2..3dc5d7eccdf6 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -158,11 +158,14 @@ final class NotificationController {
builder.addAction(secondAction);
}
- if (printJob.getState() == PrintJobInfo.STATE_STARTED) {
+ if (printJob.getState() == PrintJobInfo.STATE_STARTED
+ || printJob.getState() == PrintJobInfo.STATE_QUEUED) {
float progress = printJob.getProgress();
if (progress >= 0) {
- builder.setProgress(Integer.MAX_VALUE, (int)(Integer.MAX_VALUE * progress),
+ builder.setProgress(Integer.MAX_VALUE, (int) (Integer.MAX_VALUE * progress),
false);
+ } else {
+ builder.setProgress(Integer.MAX_VALUE, 0, true);
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index ea6281df21ad..ac97ad04e96b 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -116,6 +116,7 @@ public final class PageContentRepository {
});
return;
}
+ mCloseGuard.close();
mState = STATE_DESTROYED;
if (DEBUG) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
index 90eef83192fe..496a0b09b905 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
@@ -23,6 +23,7 @@ import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.graphics.drawable.Icon;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
@@ -109,6 +110,9 @@ public final class PrintSpoolerService extends Service {
private NotificationController mNotificationController;
+ /** Cache for custom printer icons loaded from the print service */
+ private CustomPrinterIconCache mCustomIconCache;
+
public static PrintSpoolerService peekInstance() {
synchronized (sLock) {
return sInstance;
@@ -123,6 +127,7 @@ public final class PrintSpoolerService extends Service {
mPersistanceManager = new PersistenceManager();
mNotificationController = new NotificationController(PrintSpoolerService.this);
+ mCustomIconCache = new CustomPrinterIconCache(getCacheDir());
synchronized (mLock) {
mPersistanceManager.readStateLocked();
@@ -135,6 +140,11 @@ public final class PrintSpoolerService extends Service {
}
@Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
public IBinder onBind(Intent intent) {
return new PrintSpooler();
}
@@ -703,6 +713,37 @@ public final class PrintSpoolerService extends Service {
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
}
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) {
+ mCustomIconCache.onCustomPrinterIconLoaded(printerId, icon);
+ }
+
+ /**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @return the custom icon to be used for the printer or null if the icon is
+ * not yet available
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public Icon getCustomPrinterIcon(PrinterId printerId) {
+ return mCustomIconCache.getIcon(printerId);
+ }
+
+ /**
+ * Clear the custom printer icon cache.
+ */
+ public void clearCustomPrinterIconCache() {
+ mCustomIconCache.clear();
+ }
+
private final class PersistenceManager {
private static final String PERSIST_FILE_NAME = "print_spooler_state.xml";
@@ -1262,7 +1303,7 @@ public final class PrintSpoolerService extends Service {
}
private void expect(XmlPullParser parser, int type, String tag)
- throws IOException, XmlPullParserException {
+ throws XmlPullParserException {
if (!accept(parser, type, tag)) {
throw new XmlPullParserException("Exepected event: " + type
+ " and tag: " + tag + " but got event: " + parser.getEventType()
@@ -1279,7 +1320,7 @@ public final class PrintSpoolerService extends Service {
}
private boolean accept(XmlPullParser parser, int type, String tag)
- throws IOException, XmlPullParserException {
+ throws XmlPullParserException {
if (parser.getEventType() != type) {
return false;
}
@@ -1395,5 +1436,38 @@ public final class PrintSpoolerService extends Service {
public PrintSpoolerService getService() {
return PrintSpoolerService.this;
}
+
+ @Override
+ public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon,
+ IPrintSpoolerCallbacks callbacks, int sequence)
+ throws RemoteException {
+ try {
+ PrintSpoolerService.this.onCustomPrinterIconLoaded(printerId, icon);
+ } finally {
+ callbacks.onCustomPrinterIconCached(sequence);
+ }
+ }
+
+ @Override
+ public void getCustomPrinterIcon(PrinterId printerId, IPrintSpoolerCallbacks callbacks,
+ int sequence) throws RemoteException {
+ Icon icon = null;
+ try {
+ icon = PrintSpoolerService.this.getCustomPrinterIcon(printerId);
+ } finally {
+ callbacks.onGetCustomPrinterIconResult(icon, sequence);
+ }
+ }
+
+ @Override
+ public void clearCustomPrinterIconCache(IPrintSpoolerCallbacks callbacks,
+ int sequence) throws RemoteException {
+ try {
+ PrintSpoolerService.this.clearCustomPrinterIconCache();
+ } finally {
+ callbacks.customPrinterIconCacheCleared(sequence);
+ }
+ }
+
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 1b6e9ce2db37..ea11ae40aea8 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -870,7 +870,7 @@ public final class RemotePrintDocument {
private final MutexFileProvider mFileProvider;
private final IWriteResultCallback mRemoteResultCallback;
- private final CommandDoneCallback mDoneCallback;
+ private final CommandDoneCallback mWriteDoneCallback;
private final Context mContext;
private final Handler mHandler;
@@ -885,7 +885,7 @@ public final class RemotePrintDocument {
mPageCount = pageCount;
mPages = Arrays.copyOf(pages, pages.length);
mFileProvider = fileProvider;
- mDoneCallback = callback;
+ mWriteDoneCallback = callback;
}
@Override
@@ -997,7 +997,7 @@ public final class RemotePrintDocument {
mCancellation = null;
// Done.
- mDoneCallback.onDone();
+ mWriteDoneCallback.onDone();
}
private void handleOnWriteFailed(CharSequence error, int sequence) {
@@ -1015,7 +1015,7 @@ public final class RemotePrintDocument {
mCancellation = null;
// Done.
- mDoneCallback.onDone();
+ mWriteDoneCallback.onDone();
}
private void handleOnWriteCanceled(int sequence) {
@@ -1033,7 +1033,7 @@ public final class RemotePrintDocument {
mCancellation = null;
// Done.
- mDoneCallback.onDone();
+ mWriteDoneCallback.onDone();
}
private final class WriteHandler extends Handler {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 80c28e00500b..5525774cb2f3 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -20,23 +20,33 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Loader;
import android.content.pm.ServiceInfo;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationRequest;
import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.SystemClock;
import android.print.PrintManager;
import android.print.PrinterDiscoverySession;
import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
+import libcore.io.IoUtils;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -49,18 +59,19 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
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.Objects;
import java.util.Set;
-import libcore.io.IoUtils;
-
/**
* This class is responsible for loading printers by doing discovery
* and merging the discovered printers with the previously used ones.
*/
-public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
+public final class FusedPrintersProvider extends Loader<List<PrinterInfo>>
+ implements LocationListener {
private static final String LOG_TAG = "FusedPrintersProvider";
private static final boolean DEBUG = false;
@@ -70,10 +81,22 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
private static final int MAX_FAVORITE_PRINTER_COUNT = 4;
+ /** Interval of location updated in ms */
+ private static final int LOCATION_UPDATE_MS = 30 * 1000;
+
+ /** Maximum acceptable age of the location in ms */
+ private static final int MAX_LOCATION_AGE_MS = 10 * 60 * 1000;
+
+ /** The worst accuracy that is considered usable in m */
+ private static final int MIN_LOCATION_ACCURACY = 50;
+
+ /** Maximum distance where a printer is still considered "near" */
+ private static final int MAX_PRINTER_DISTANCE = MIN_LOCATION_ACCURACY * 2;
+
private final List<PrinterInfo> mPrinters =
new ArrayList<>();
- private final List<PrinterInfo> mFavoritePrinters =
+ private final List<Pair<PrinterInfo, Location>> mFavoritePrinters =
new ArrayList<>();
private final PersistenceManager mPersistenceManager;
@@ -84,33 +107,111 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
private boolean mPrintersUpdatedBefore;
+ /** Last known location, can be null or out of date */
+ private final Object mLocationLock;
+ private Location mLocation;
+
+ /** Location used when the printers were updated the last time */
+ private Location mLocationOfLastPrinterUpdate;
+
+ /** Reference to the system's location manager */
+ private final LocationManager mLocationManager;
+
+ /**
+ * Get a reference to the current location.
+ */
+ private Location getCurrentLocation() {
+ synchronized (mLocationLock) {
+ return mLocation;
+ }
+ }
+
public FusedPrintersProvider(Context context) {
super(context);
+ mLocationLock = new Object();
mPersistenceManager = new PersistenceManager(context);
+ mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
public void addHistoricalPrinter(PrinterInfo printer) {
mPersistenceManager.addPrinterAndWritePrinterHistory(printer);
}
+ /**
+ * Add printer to dest, or if updatedPrinters add the updated printer. If the updated printer
+ * was added, remove it from updatedPrinters.
+ *
+ * @param dest The list the printers should be added to
+ * @param printer The printer to add
+ * @param updatedPrinters The printer to add
+ */
+ private void updateAndAddPrinter(List<PrinterInfo> dest, PrinterInfo printer,
+ Map<PrinterId, PrinterInfo> updatedPrinters) {
+ PrinterInfo updatedPrinter = updatedPrinters.remove(printer.getId());
+ if (updatedPrinter != null) {
+ dest.add(updatedPrinter);
+ } else {
+ dest.add(printer);
+ }
+ }
+
+ /**
+ * Compute the printers, order them appropriately and deliver the printers to the clients. We
+ * prefer printers that have been previously used (favorites) and printers that have been used
+ * previously close to the current location (near printers).
+ *
+ * @param discoveredPrinters All printers currently discovered by the print discovery session.
+ * @param favoritePrinters The ordered list of printers. The earlier in the list, the more
+ * preferred.
+ */
private void computeAndDeliverResult(Map<PrinterId, PrinterInfo> discoveredPrinters,
- List<PrinterInfo> favoritePrinters) {
+ List<Pair<PrinterInfo, Location>> favoritePrinters) {
List<PrinterInfo> printers = new ArrayList<>();
- // Add the updated favorite printers.
+ // Store the printerIds that have already been added. We cannot compare the printerInfos in
+ // "printers" as they might have been taken from discoveredPrinters and the printerInfo does
+ // not equals() anymore
+ HashSet<PrinterId> alreadyAddedPrinter = new HashSet<>(MAX_FAVORITE_PRINTER_COUNT);
+
+ Location location = getCurrentLocation();
+
+ // Add the favorite printers that have last been used close to the current location
final int favoritePrinterCount = favoritePrinters.size();
+ if (location != null) {
+ for (int i = 0; i < favoritePrinterCount; i++) {
+ // Only add a certain amount of favorite printers
+ if (printers.size() == MAX_FAVORITE_PRINTER_COUNT) {
+ break;
+ }
+
+ PrinterInfo favoritePrinter = favoritePrinters.get(i).first;
+ Location printerLocation = favoritePrinters.get(i).second;
+
+ if (printerLocation != null
+ && !alreadyAddedPrinter.contains(favoritePrinter.getId())) {
+ if (printerLocation.distanceTo(location) <= MAX_PRINTER_DISTANCE) {
+ updateAndAddPrinter(printers, favoritePrinter, discoveredPrinters);
+ alreadyAddedPrinter.add(favoritePrinter.getId());
+ }
+ }
+ }
+ }
+
+ // Add the other favorite printers
for (int i = 0; i < favoritePrinterCount; i++) {
- PrinterInfo favoritePrinter = favoritePrinters.get(i);
- PrinterInfo updatedPrinter = discoveredPrinters.remove(
- favoritePrinter.getId());
- if (updatedPrinter != null) {
- printers.add(updatedPrinter);
- } else {
- printers.add(favoritePrinter);
+ // Only add a certain amount of favorite printers
+ if (printers.size() == MAX_FAVORITE_PRINTER_COUNT) {
+ break;
+ }
+
+ PrinterInfo favoritePrinter = favoritePrinters.get(i).first;
+ if (!alreadyAddedPrinter.contains(favoritePrinter.getId())) {
+ updateAndAddPrinter(printers, favoritePrinter, discoveredPrinters);
}
}
- // Add other updated printers.
+ // Add other updated printers. Printers that have already been added have been removed from
+ // discoveredPrinters in the calls to updateAndAddPrinter
final int printerCount = mPrinters.size();
for (int i = 0; i < printerCount; i++) {
PrinterInfo printer = mPrinters.get(i);
@@ -142,6 +243,21 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
if (DEBUG) {
Log.i(LOG_TAG, "onStartLoading() " + FusedPrintersProvider.this.hashCode());
}
+
+ mLocationManager.requestLocationUpdates(LocationRequest.create()
+ .setQuality(LocationRequest.POWER_LOW).setInterval(LOCATION_UPDATE_MS), this,
+ Looper.getMainLooper());
+
+ Location lastLocation = mLocationManager.getLastLocation();
+ if (lastLocation != null) {
+ onLocationChanged(lastLocation);
+ }
+
+ // Jumpstart location with a single forced update
+ Criteria oneTimeCriteria = new Criteria();
+ oneTimeCriteria.setAccuracy(Criteria.ACCURACY_FINE);
+ mLocationManager.requestSingleUpdate(oneTimeCriteria, this, Looper.getMainLooper());
+
// The contract is that if we already have a valid,
// result the we have to deliver it immediately.
if (!mPrinters.isEmpty()) {
@@ -158,6 +274,8 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
Log.i(LOG_TAG, "onStopLoading() " + FusedPrintersProvider.this.hashCode());
}
onCancelLoad();
+
+ mLocationManager.removeUpdates(this);
}
@Override
@@ -188,34 +306,38 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
+ " " + FusedPrintersProvider.this.hashCode());
}
- updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters);
+ updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters,
+ getCurrentLocation());
}
});
final int favoriteCount = mFavoritePrinters.size();
List<PrinterId> printerIds = new ArrayList<>(favoriteCount);
for (int i = 0; i < favoriteCount; i++) {
- printerIds.add(mFavoritePrinters.get(i).getId());
+ printerIds.add(mFavoritePrinters.get(i).first.getId());
}
mDiscoverySession.startPrinterDiscovery(printerIds);
List<PrinterInfo> printers = mDiscoverySession.getPrinters();
- if (!printers.isEmpty()) {
- updatePrinters(printers, mFavoritePrinters);
- }
+
+ updatePrinters(printers, mFavoritePrinters, getCurrentLocation());
}
}
- private void updatePrinters(List<PrinterInfo> printers, List<PrinterInfo> favoritePrinters) {
+ private void updatePrinters(List<PrinterInfo> printers,
+ List<Pair<PrinterInfo, Location>> favoritePrinters,
+ Location location) {
if (mPrintersUpdatedBefore && mPrinters.equals(printers)
- && mFavoritePrinters.equals(favoritePrinters)) {
+ && mFavoritePrinters.equals(favoritePrinters)
+ && Objects.equals(mLocationOfLastPrinterUpdate, location)) {
return;
}
+ mLocationOfLastPrinterUpdate = location;
mPrintersUpdatedBefore = true;
// Some of the found printers may have be a printer that is in the
- // history but with its name changed. Hence, we try to update the
- // printer to use its current name instead of the historical one.
- mPersistenceManager.updatePrintersHistoricalNamesIfNeeded(printers);
+ // history but with its properties changed. Hence, we try to update the
+ // printer to use its current properties instead of the historical one.
+ mPersistenceManager.updateHistoricalPrintersIfNeeded(printers);
Map<PrinterId, PrinterInfo> printersMap = new LinkedHashMap<>();
final int printerCount = printers.size();
@@ -271,6 +393,60 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
onStopLoading();
}
+ /**
+ * Check if the location is acceptable. This is to filter out excessively old or inaccurate
+ * location updates.
+ *
+ * @param location the location to check
+ * @return true iff the location is usable.
+ */
+ private boolean isLocationAcceptable(Location location) {
+ return location != null
+ && location.getElapsedRealtimeNanos() > SystemClock.elapsedRealtimeNanos()
+ - MAX_LOCATION_AGE_MS * 1000_000L
+ && location.hasAccuracy()
+ && location.getAccuracy() < MIN_LOCATION_ACCURACY;
+ }
+
+ @Override
+ public void onLocationChanged(Location location) {
+ synchronized(mLocationLock) {
+ // We expect the user to not move too fast while printing. Hence prefer more accurate
+ // updates over more recent ones for LOCATION_UPDATE_MS. We add a 10% fudge factor here
+ // as the location provider might send an update slightly too early.
+ if (isLocationAcceptable(location)
+ && !location.equals(mLocation)
+ && (mLocation == null
+ || location
+ .getElapsedRealtimeNanos() > mLocation.getElapsedRealtimeNanos()
+ + LOCATION_UPDATE_MS * 0.9 * 1000_000L
+ || (!mLocation.hasAccuracy()
+ || location.getAccuracy() < mLocation.getAccuracy()))) {
+ // Other callers of updatePrinters might want to know the location, hence cache it
+ mLocation = location;
+
+ if (areHistoricalPrintersLoaded()) {
+ updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters, mLocation);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ // nothing to do
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ // nothing to do
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ // nothing to do
+ }
+
public boolean areHistoricalPrintersLoaded() {
return mPersistenceManager.mReadHistoryCompleted;
}
@@ -294,7 +470,7 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
public boolean isFavoritePrinter(PrinterId printerId) {
final int printerCount = mFavoritePrinters.size();
for (int i = 0; i < printerCount; i++) {
- PrinterInfo favoritePritner = mFavoritePrinters.get(i);
+ PrinterInfo favoritePritner = mFavoritePrinters.get(i).first;
if (favoritePritner.getId().equals(printerId)) {
return true;
}
@@ -303,28 +479,22 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
}
public void forgetFavoritePrinter(PrinterId printerId) {
- List<PrinterInfo> newFavoritePrinters = null;
+ final int favoritePrinterCount = mFavoritePrinters.size();
+ List<Pair<PrinterInfo, Location>> newFavoritePrinters = new ArrayList<>(
+ favoritePrinterCount - 1);
// Remove the printer from the favorites.
- final int favoritePrinterCount = mFavoritePrinters.size();
for (int i = 0; i < favoritePrinterCount; i++) {
- PrinterInfo favoritePrinter = mFavoritePrinters.get(i);
- if (favoritePrinter.getId().equals(printerId)) {
- newFavoritePrinters = new ArrayList<>();
- newFavoritePrinters.addAll(mPrinters);
- newFavoritePrinters.remove(i);
- break;
+ if (!mFavoritePrinters.get(i).first.getId().equals(printerId)) {
+ newFavoritePrinters.add(mFavoritePrinters.get(i));
}
}
- // If we removed a favorite printer, we have work to do.
- if (newFavoritePrinters != null) {
- // Remove the printer from history and persist the latter.
- mPersistenceManager.removeHistoricalPrinterAndWritePrinterHistory(printerId);
+ // Remove the printer from history and persist the latter.
+ mPersistenceManager.removeHistoricalPrinterAndWritePrinterHistory(printerId);
- // Recompute and deliver the printers.
- updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters);
- }
+ // Recompute and deliver the printers.
+ updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters, getCurrentLocation());
}
private final class PersistenceManager {
@@ -333,18 +503,22 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
private static final String TAG_PRINTERS = "printers";
private static final String TAG_PRINTER = "printer";
+ private static final String TAG_LOCATION = "location";
private static final String TAG_PRINTER_ID = "printerId";
private static final String ATTR_LOCAL_ID = "localId";
private static final String ATTR_SERVICE_NAME = "serviceName";
+ private static final String ATTR_LONGITUDE = "longitude";
+ private static final String ATTR_LATITUDE = "latitude";
+ private static final String ATTR_ACCURACY = "accuracy";
+
private static final String ATTR_NAME = "name";
private static final String ATTR_DESCRIPTION = "description";
- private static final String ATTR_STATUS = "status";
private final AtomicFile mStatePersistFile;
- private List<PrinterInfo> mHistoricalPrinters = new ArrayList<>();
+ private List<Pair<PrinterInfo, Location>> mHistoricalPrinters = new ArrayList<>();
private boolean mReadHistoryCompleted;
@@ -378,13 +552,13 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
mReadTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
}
- public void updatePrintersHistoricalNamesIfNeeded(List<PrinterInfo> printers) {
+ public void updateHistoricalPrintersIfNeeded(List<PrinterInfo> printers) {
boolean writeHistory = false;
final int printerCount = printers.size();
for (int i = 0; i < printerCount; i++) {
PrinterInfo printer = printers.get(i);
- writeHistory |= renamePrinterIfNeeded(printer);
+ writeHistory |= updateHistoricalPrinterIfNeeded(printer);
}
if (writeHistory) {
@@ -392,25 +566,57 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
}
}
- public boolean renamePrinterIfNeeded(PrinterInfo printer) {
- boolean renamed = false;
+ /**
+ * Updates the historical printer state with the given printer.
+ *
+ * @param printer the printer to update
+ *
+ * @return true iff the historical printer list needs to be updated
+ */
+ public boolean updateHistoricalPrinterIfNeeded(PrinterInfo printer) {
+ boolean writeHistory = false;
final int printerCount = mHistoricalPrinters.size();
for (int i = 0; i < printerCount; i++) {
- PrinterInfo historicalPrinter = mHistoricalPrinters.get(i);
- if (historicalPrinter.getId().equals(printer.getId())
- && !TextUtils.equals(historicalPrinter.getName(), printer.getName())) {
- mHistoricalPrinters.set(i, printer);
- renamed = true;
+ PrinterInfo historicalPrinter = mHistoricalPrinters.get(i).first;
+
+ if (!historicalPrinter.getId().equals(printer.getId())) {
+ continue;
+ }
+
+ // Overwrite the historical printer with the updated printer as some properties
+ // changed. We ignore the status as this is a volatile state.
+ if (historicalPrinter.equalsIgnoringStatus(printer)) {
+ continue;
+ }
+
+ mHistoricalPrinters.set(i, new Pair<PrinterInfo, Location>(printer,
+ mHistoricalPrinters.get(i).second));
+
+ // We only persist limited information in the printer history, hence check if
+ // we need to persist the update.
+ // @see PersistenceManager.WriteTask#doWritePrinterHistory
+ if (!historicalPrinter.getName().equals(printer.getName())) {
+ if (Objects.equals(historicalPrinter.getDescription(),
+ printer.getDescription())) {
+ writeHistory = true;
+ }
}
}
- return renamed;
+ return writeHistory;
}
public void addPrinterAndWritePrinterHistory(PrinterInfo printer) {
if (mHistoricalPrinters.size() >= MAX_HISTORY_LENGTH) {
mHistoricalPrinters.remove(0);
}
- mHistoricalPrinters.add(printer);
+
+ Location location = getCurrentLocation();
+ if (!isLocationAcceptable(location)) {
+ location = null;
+ }
+
+ mHistoricalPrinters.add(new Pair<PrinterInfo, Location>(printer, location));
+
writePrinterHistory();
}
@@ -418,7 +624,7 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
boolean writeHistory = false;
final int printerCount = mHistoricalPrinters.size();
for (int i = printerCount - 1; i >= 0; i--) {
- PrinterInfo historicalPrinter = mHistoricalPrinters.get(i);
+ PrinterInfo historicalPrinter = mHistoricalPrinters.get(i).first;
if (historicalPrinter.getId().equals(printerId)) {
mHistoricalPrinters.remove(i);
writeHistory = true;
@@ -439,63 +645,91 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
return mLastReadHistoryTimestamp != mStatePersistFile.getBaseFile().lastModified();
}
- private List<PrinterInfo> computeFavoritePrinters(List<PrinterInfo> printers) {
+ /**
+ * Sort the favorite printers by weight. If a printer is in the list multiple times for
+ * different locations, all instances are considered to have the accumulative weight. The
+ * actual favorite printers to display are computed in {@link #computeAndDeliverResult} as
+ * only at this time we know the location to use to determine if a printer is close enough
+ * to be preferred.
+ *
+ * @param printers The printers to sort.
+ * @return The sorted printers.
+ */
+ private List<Pair<PrinterInfo, Location>> sortFavoritePrinters(
+ List<Pair<PrinterInfo, Location>> printers) {
Map<PrinterId, PrinterRecord> recordMap = new ArrayMap<>();
- // Recompute the weights.
+ // Compute the weights.
float currentWeight = 1.0f;
final int printerCount = printers.size();
for (int i = printerCount - 1; i >= 0; i--) {
- PrinterInfo printer = printers.get(i);
- // Aggregate weight for the same printer
- PrinterRecord record = recordMap.get(printer.getId());
+ PrinterId printerId = printers.get(i).first.getId();
+ PrinterRecord record = recordMap.get(printerId);
if (record == null) {
- record = new PrinterRecord(printer);
- recordMap.put(printer.getId(), record);
+ record = new PrinterRecord();
+ recordMap.put(printerId, record);
}
+
+ record.printers.add(printers.get(i));
+
+ // Aggregate weight for the same printer
record.weight += currentWeight;
currentWeight *= WEIGHT_DECAY_COEFFICIENT;
}
- // Soft the favorite printers.
+ // Sort the favorite printers.
List<PrinterRecord> favoriteRecords = new ArrayList<>(
recordMap.values());
Collections.sort(favoriteRecords);
// Write the favorites to the output.
- final int favoriteCount = Math.min(favoriteRecords.size(),
- MAX_FAVORITE_PRINTER_COUNT);
- List<PrinterInfo> favoritePrinters = new ArrayList<>(favoriteCount);
- for (int i = 0; i < favoriteCount; i++) {
- PrinterInfo printer = favoriteRecords.get(i).printer;
- favoritePrinters.add(printer);
+ final int recordCount = favoriteRecords.size();
+ List<Pair<PrinterInfo, Location>> favoritePrinters = new ArrayList<>(printerCount);
+ for (int i = 0; i < recordCount; i++) {
+ favoritePrinters.addAll(favoriteRecords.get(i).printers);
}
return favoritePrinters;
}
+ /**
+ * A set of printers with the same ID and the weight associated with them during
+ * {@link #sortFavoritePrinters}.
+ */
private final class PrinterRecord implements Comparable<PrinterRecord> {
- public final PrinterInfo printer;
+ /**
+ * The printers, all with the same ID, but potentially different properties or locations
+ */
+ public final List<Pair<PrinterInfo, Location>> printers;
+
+ /** The weight associated with the printers */
public float weight;
- public PrinterRecord(PrinterInfo printer) {
- this.printer = printer;
+ /**
+ * Create a new record.
+ */
+ public PrinterRecord() {
+ printers = new ArrayList<>();
}
+ /**
+ * Compare two records by weight.
+ */
@Override
public int compareTo(PrinterRecord another) {
return Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight);
}
}
- private final class ReadTask extends AsyncTask<Void, Void, List<PrinterInfo>> {
+ private final class ReadTask
+ extends AsyncTask<Void, Void, List<Pair<PrinterInfo, Location>>> {
@Override
- protected List<PrinterInfo> doInBackground(Void... args) {
+ protected List<Pair<PrinterInfo, Location>> doInBackground(Void... args) {
return doReadPrinterHistory();
}
@Override
- protected void onPostExecute(List<PrinterInfo> printers) {
+ protected void onPostExecute(List<Pair<PrinterInfo, Location>> printers) {
if (DEBUG) {
Log.i(LOG_TAG, "read history completed "
+ FusedPrintersProvider.this.hashCode());
@@ -518,7 +752,8 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
final int printerCount = printers.size();
for (int i = printerCount - 1; i >= 0; i--) {
- ComponentName printerServiceName = printers.get(i).getId().getServiceName();
+ ComponentName printerServiceName = printers.get(i).first.getId()
+ .getServiceName();
if (!enabledComponents.contains(printerServiceName)) {
printers.remove(i);
}
@@ -529,12 +764,13 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
// Compute the favorite printers.
mFavoritePrinters.clear();
- mFavoritePrinters.addAll(computeFavoritePrinters(mHistoricalPrinters));
+ mFavoritePrinters.addAll(sortFavoritePrinters(mHistoricalPrinters));
mReadHistoryCompleted = true;
// Deliver the printers.
- updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters);
+ updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters,
+ getCurrentLocation());
// We are done.
mReadTask = null;
@@ -544,12 +780,12 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
}
@Override
- protected void onCancelled(List<PrinterInfo> printerInfos) {
+ protected void onCancelled(List<Pair<PrinterInfo, Location>> printerInfos) {
// We are done.
mReadTask = null;
}
- private List<PrinterInfo> doReadPrinterHistory() {
+ private List<Pair<PrinterInfo, Location>> doReadPrinterHistory() {
final FileInputStream in;
try {
in = mStatePersistFile.openRead();
@@ -561,7 +797,7 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
return new ArrayList<>();
}
try {
- List<PrinterInfo> printers = new ArrayList<>();
+ List<Pair<PrinterInfo, Location>> printers = new ArrayList<>();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(in, StandardCharsets.UTF_8.name());
parseState(parser, printers);
@@ -582,8 +818,9 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
return Collections.emptyList();
}
- private void parseState(XmlPullParser parser, List<PrinterInfo> outPrinters)
- throws IOException, XmlPullParserException {
+ private void parseState(XmlPullParser parser,
+ List<Pair<PrinterInfo, Location>> outPrinters)
+ throws IOException, XmlPullParserException {
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.START_TAG, TAG_PRINTERS);
@@ -601,8 +838,9 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
expect(parser, XmlPullParser.END_TAG, TAG_PRINTERS);
}
- private boolean parsePrinter(XmlPullParser parser, List<PrinterInfo> outPrinters)
- throws IOException, XmlPullParserException {
+ private boolean parsePrinter(XmlPullParser parser,
+ List<Pair<PrinterInfo, Location>> outPrinters)
+ throws IOException, XmlPullParserException {
skipEmptyTextTags(parser);
if (!accept(parser, XmlPullParser.START_TAG, TAG_PRINTER)) {
return false;
@@ -610,7 +848,6 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
String name = parser.getAttributeValue(null, ATTR_NAME);
String description = parser.getAttributeValue(null, ATTR_DESCRIPTION);
- final int status = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATUS));
parser.next();
@@ -625,11 +862,34 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID);
parser.next();
- PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, name, status);
+ skipEmptyTextTags(parser);
+ Location location;
+ if (accept(parser, XmlPullParser.START_TAG, TAG_LOCATION)) {
+ location = new Location("");
+ location.setLongitude(
+ Double.parseDouble(parser.getAttributeValue(null, ATTR_LONGITUDE)));
+ location.setLatitude(
+ Double.parseDouble(parser.getAttributeValue(null, ATTR_LATITUDE)));
+ location.setAccuracy(
+ Float.parseFloat(parser.getAttributeValue(null, ATTR_ACCURACY)));
+ parser.next();
+
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.END_TAG, TAG_LOCATION);
+ parser.next();
+ } else {
+ location = null;
+ }
+
+ // If the printer is available the printer will be replaced by the one read from the
+ // discovery session, hence the only time when this object is used is when the
+ // printer is unavailable.
+ PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, name,
+ PrinterInfo.STATUS_UNAVAILABLE);
builder.setDescription(description);
PrinterInfo printer = builder.build();
- outPrinters.add(printer);
+ outPrinters.add(new Pair<PrinterInfo, Location>(printer, location));
if (DEBUG) {
Log.i(LOG_TAG, "[RESTORED] " + printer);
@@ -642,7 +902,7 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
}
private void expect(XmlPullParser parser, int type, String tag)
- throws IOException, XmlPullParserException {
+ throws XmlPullParserException {
if (!accept(parser, type, tag)) {
throw new XmlPullParserException("Exepected event: " + type
+ " and tag: " + tag + " but got event: " + parser.getEventType()
@@ -659,7 +919,7 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
}
private boolean accept(XmlPullParser parser, int type, String tag)
- throws IOException, XmlPullParserException {
+ throws XmlPullParserException {
if (parser.getEventType() != type) {
return false;
}
@@ -674,14 +934,16 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
}
}
- private final class WriteTask extends AsyncTask<List<PrinterInfo>, Void, Void> {
+ private final class WriteTask
+ extends AsyncTask<List<Pair<PrinterInfo, Location>>, Void, Void> {
@Override
- protected Void doInBackground(List<PrinterInfo>... printers) {
+ protected Void doInBackground(
+ @SuppressWarnings("unchecked") List<Pair<PrinterInfo, Location>>... printers) {
doWritePrinterHistory(printers[0]);
return null;
}
- private void doWritePrinterHistory(List<PrinterInfo> printers) {
+ private void doWritePrinterHistory(List<Pair<PrinterInfo, Location>> printers) {
FileOutputStream out = null;
try {
out = mStatePersistFile.startWrite();
@@ -693,14 +955,11 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
final int printerCount = printers.size();
for (int i = 0; i < printerCount; i++) {
- PrinterInfo printer = printers.get(i);
+ PrinterInfo printer = printers.get(i).first;
serializer.startTag(null, TAG_PRINTER);
serializer.attribute(null, ATTR_NAME, printer.getName());
- // Historical printers are always stored as unavailable.
- serializer.attribute(null, ATTR_STATUS, String.valueOf(
- PrinterInfo.STATUS_UNAVAILABLE));
String description = printer.getDescription();
if (description != null) {
serializer.attribute(null, ATTR_DESCRIPTION, description);
@@ -713,6 +972,18 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
.flattenToString());
serializer.endTag(null, TAG_PRINTER_ID);
+ Location location = printers.get(i).second;
+ if (location != null) {
+ serializer.startTag(null, TAG_LOCATION);
+ serializer.attribute(null, ATTR_LONGITUDE,
+ String.valueOf(location.getLongitude()));
+ serializer.attribute(null, ATTR_LATITUDE,
+ String.valueOf(location.getLatitude()));
+ serializer.attribute(null, ATTR_ACCURACY,
+ String.valueOf(location.getAccuracy()));
+ serializer.endTag(null, TAG_LOCATION);
+ }
+
serializer.endTag(null, TAG_PRINTER);
if (DEBUG) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index 2757b816db40..606f4eb79c2e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -52,7 +52,7 @@ import java.util.List;
/**
* This class represents the adapter for the pages in the print preview list.
*/
-public final class PageAdapter extends Adapter {
+public final class PageAdapter extends Adapter<ViewHolder> {
private static final String LOG_TAG = "PageAdapter";
private static final int MAX_PREVIEW_PAGES_BATCH = 50;
@@ -409,7 +409,7 @@ public final class PageAdapter extends Adapter {
- horizontalPaddingAndMargins) / columnCount) + 0.5f);
// Compute max page height.
- final int pageContentDesiredHeight = (int) (((float) pageContentDesiredWidth
+ final int pageContentDesiredHeight = (int) ((pageContentDesiredWidth
/ pageAspectRatio) + 0.5f);
// If the page does not fit entirely in a vertical direction,
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 652156542575..9c1cf645320d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -30,7 +30,6 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
@@ -462,6 +461,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
}
}
+ @Override
public void onUpdateCanceled() {
if (DEBUG) {
Log.i(LOG_TAG, "onUpdateCanceled()");
@@ -1738,8 +1738,9 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
}
private void updatePageRangeOptions(int pageCount) {
+ @SuppressWarnings("unchecked")
ArrayAdapter<SpinnerItem<Integer>> rangeOptionsSpinnerAdapter =
- (ArrayAdapter) mRangeOptionsSpinner.getAdapter();
+ (ArrayAdapter<SpinnerItem<Integer>>) mRangeOptionsSpinner.getAdapter();
rangeOptionsSpinnerAdapter.clear();
final int[] rangeOptionsValues = getResources().getIntArray(
@@ -1928,6 +1929,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
this.label = label;
}
+ @Override
public String toString() {
return label.toString();
}
@@ -2187,7 +2189,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
if (position == 0 && getPdfPrinter() != null) {
PrinterHolder printerHolder = (PrinterHolder) getItem(position);
title = printerHolder.printer.getName();
- icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf);
+ icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf, null);
} else if (position == 1) {
title = getString(R.string.all_printers);
}
@@ -2195,20 +2197,16 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
if (position == 1 && getPdfPrinter() != null) {
PrinterHolder printerHolder = (PrinterHolder) getItem(position);
title = printerHolder.printer.getName();
- icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf);
+ icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf, null);
} else if (position == getCount() - 1) {
title = getString(R.string.all_printers);
} else {
PrinterHolder printerHolder = (PrinterHolder) getItem(position);
- title = printerHolder.printer.getName();
- try {
- PackageInfo packageInfo = getPackageManager().getPackageInfo(
- printerHolder.printer.getId().getServiceName().getPackageName(), 0);
- subtitle = packageInfo.applicationInfo.loadLabel(getPackageManager());
- icon = packageInfo.applicationInfo.loadIcon(getPackageManager());
- } catch (NameNotFoundException nnfe) {
- /* ignore */
- }
+ PrinterInfo printInfo = printerHolder.printer;
+
+ title = printInfo.getName();
+ icon = printInfo.loadIcon(PrintActivity.this);
+ subtitle = printInfo.getDescription();
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
index 8716fd21cdb8..ce54204ef870 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
@@ -78,8 +78,8 @@ class PrintPreviewController implements MutexFileProvider.OnReleaseRequestCallba
mRecyclerView.setLayoutManager(mLayoutManger);
mRecyclerView.setAdapter(mPageAdapter);
mRecyclerView.setItemViewCacheSize(0);
- mPreloadController = new PreloadController(mRecyclerView);
- mRecyclerView.setOnScrollListener(mPreloadController);
+ mPreloadController = new PreloadController();
+ mRecyclerView.addOnScrollListener(mPreloadController);
mContentView = (PrintContentView) activity.findViewById(R.id.options_content);
mEmbeddedContentContainer = (EmbeddedContentContainer) activity.findViewById(
@@ -314,12 +314,9 @@ class PrintPreviewController implements MutexFileProvider.OnReleaseRequestCallba
}
private final class PreloadController extends RecyclerView.OnScrollListener {
- private final RecyclerView mRecyclerView;
-
private int mOldScrollState;
- public PreloadController(RecyclerView recyclerView) {
- mRecyclerView = recyclerView;
+ public PreloadController() {
mOldScrollState = mRecyclerView.getScrollState();
}
@@ -371,7 +368,8 @@ class PrintPreviewController implements MutexFileProvider.OnReleaseRequestCallba
View lastChild = layoutManager.getChildAt(layoutManager.getChildCount() - 1);
ViewHolder lastHolder = mRecyclerView.getChildViewHolder(lastChild);
- return new PageRange(firstHolder.getPosition(), lastHolder.getPosition());
+ return new PageRange(firstHolder.getLayoutPosition(),
+ lastHolder.getLayoutPosition());
}
return null;
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index ab0b2f1acf85..cdfc7ee11b1e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -27,6 +27,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.IntentSender.SendIntentException;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -51,6 +52,7 @@ import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
import android.widget.AdapterView;
@@ -587,20 +589,31 @@ public final class SelectPrinterActivity extends Activity {
convertView.setEnabled(isActionable(position));
- PrinterInfo printer = (PrinterInfo) getItem(position);
+ final PrinterInfo printer = (PrinterInfo) getItem(position);
CharSequence title = printer.getName();
- CharSequence subtitle = null;
- Drawable icon = null;
+ Drawable icon = printer.loadIcon(SelectPrinterActivity.this);
+ CharSequence printServiceLabel;
try {
- PackageManager pm = getPackageManager();
- PackageInfo packageInfo = pm.getPackageInfo(printer.getId()
- .getServiceName().getPackageName(), 0);
- subtitle = packageInfo.applicationInfo.loadLabel(pm);
- icon = packageInfo.applicationInfo.loadIcon(pm);
- } catch (NameNotFoundException nnfe) {
- /* ignore */
+ PackageInfo packageInfo = getPackageManager().getPackageInfo(
+ printer.getId().getServiceName().getPackageName(), 0);
+
+ printServiceLabel = packageInfo.applicationInfo.loadLabel(getPackageManager());
+ } catch (NameNotFoundException e) {
+ printServiceLabel = null;
+ }
+
+ CharSequence description = printer.getDescription();
+
+ CharSequence subtitle;
+ if (printServiceLabel == null) {
+ subtitle = description;
+ } else if (description == null) {
+ subtitle = printServiceLabel;
+ } else {
+ subtitle = getString(R.string.printer_extended_description_template,
+ printServiceLabel, description);
}
TextView titleView = (TextView) convertView.findViewById(R.id.title);
@@ -615,6 +628,20 @@ public final class SelectPrinterActivity extends Activity {
subtitleView.setVisibility(View.GONE);
}
+ ImageView moreInfoView = (ImageView) convertView.findViewById(R.id.more_info);
+ if (printer.getInfoIntent() != null) {
+ moreInfoView.setVisibility(View.VISIBLE);
+ moreInfoView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ try {
+ startIntentSender(printer.getInfoIntent().getIntentSender(), null, 0, 0, 0);
+ } catch (SendIntentException e) {
+ Log.e(LOG_TAG, "Could not execute pending info intent: %s", e);
+ }
+ }
+ });
+ }
ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
if (icon != null) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
index e6613faebae5..0bb4bfa18513 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
@@ -415,6 +415,7 @@ public final class PrintContentView extends ViewGroup implements View.OnClickLis
onDragProgress(progress);
}
+ @Override
public void onViewReleased(View child, float velocityX, float velocityY) {
final int childTop = child.getTop();
@@ -435,14 +436,17 @@ public final class PrintContentView extends ViewGroup implements View.OnClickLis
invalidate();
}
+ @Override
public int getOrderedChildIndex(int index) {
return getChildCount() - index - 1;
}
+ @Override
public int getViewVerticalDragRange(View child) {
return mDraggableContent.getHeight();
}
+ @Override
public int clampViewPositionVertical(View child, int top, int dy) {
final int staticOptionBottom = mStaticContent.getBottom();
return Math.max(Math.min(top, getOpenedOptionsY()), getClosedOptionsY());
diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml
index c88647678af6..8720eb20986e 100644
--- a/packages/SettingsLib/res/values-af/arrays.xml
+++ b/packages/SettingsLib/res/values-af/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Gebruik altyd HDCP-kontrolering"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Af"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Af"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K per logbuffer"</item>
- <item msgid="2822309747675758628">"256 K per logbuffer"</item>
- <item msgid="6699306198357496731">"1 M per logbuffer"</item>
- <item msgid="5748528643937500349">"4 M per logbuffer"</item>
- <item msgid="1978629051085111592">"16 M per logbuffer"</item>
+ <item msgid="6921048829791179331">"Af"</item>
+ <item msgid="2969458029344750262">"64 K per logbuffer"</item>
+ <item msgid="1342285115665698168">"256 K per logbuffer"</item>
+ <item msgid="1314234299552254621">"1 M per logbuffer"</item>
+ <item msgid="3606047780792894151">"4 M per logbuffer"</item>
+ <item msgid="5431354956856655120">"16 M per logbuffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasie af"</item>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 0d9d79ce19f0..ebe8752777f6 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"Aktiveer vormvrye vensters"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiveer steun vir eksperimentele vormvrye vensters."</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>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Raak om die wagwoord vir volledige rekenaarrugsteune te verander of te verwyder"</string>
diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml
index 324ee83747e6..62e372bd404e 100644
--- a/packages/SettingsLib/res/values-am/arrays.xml
+++ b/packages/SettingsLib/res/values-am/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ሁልጊዜ የHDCP ምልከታ ተጠቀም"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 ኪባ"</item>
- <item msgid="505611754508988476">"256 ኪባ"</item>
- <item msgid="6361286924268716397">"1 ሜባ"</item>
- <item msgid="6405203239560695266">"4 ሜባ"</item>
- <item msgid="3025431211013424097">"16 ሜባ"</item>
+ <item msgid="8665206199209698501">"ጠፍቷል"</item>
+ <item msgid="1593289376502312923">"64 ኪባ"</item>
+ <item msgid="487545340236145324">"256 ኪባ"</item>
+ <item msgid="2423528675294333831">"1 ሜባ"</item>
+ <item msgid="180883774509476541">"4 ሜባ"</item>
+ <item msgid="2803199102589126938">"16 ሜባ"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 ኪባ"</item>
- <item msgid="3534782711045262344">"256 ኪባ"</item>
- <item msgid="8085867209202153403">"1 ሜባ"</item>
+ <item msgid="6089470720451068364">"ጠፍቷል"</item>
+ <item msgid="4622460333038586791">"64 ኪባ"</item>
+ <item msgid="2212125625169582330">"256 ኪባ"</item>
+ <item msgid="1704946766699242653">"1 ሜባ"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
- <item msgid="2822309747675758628">"256 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
- <item msgid="6699306198357496731">"1 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
- <item msgid="5748528643937500349">"4 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
- <item msgid="1978629051085111592">"16 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
+ <item msgid="6921048829791179331">"ጠፍቷል"</item>
+ <item msgid="2969458029344750262">"64 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
+ <item msgid="1342285115665698168">"256 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
+ <item msgid="1314234299552254621">"1 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
+ <item msgid="3606047780792894151">"4 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
+ <item msgid="5431354956856655120">"16 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"እነማ ጠፍቷል"</item>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 1c9b0a9d6f54..e33d0fa9dace 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"የነጻ ቅርጽ መስኮቶችን ያንቁ"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"የሙከራ ነጻ ቅርጽ መስኮቶች ድጋፍን ያነቃል።"</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="2731163425081172638">"ለዴስክቶፕ ሙሉ ምትኬዎች የይለፍ ቃል ለመለወጥ ወይም ለማስወገድ ንካ"</string>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index 654759f1086b..60eebeb25564 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"‏استخدام التحقق من HDCP دومًا"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 كيلوبايت"</item>
- <item msgid="505611754508988476">"256 كيلوبايت"</item>
- <item msgid="6361286924268716397">"1 ميغابايت"</item>
- <item msgid="6405203239560695266">"4 ميغابايت"</item>
- <item msgid="3025431211013424097">"16 ميغابايت"</item>
+ <item msgid="8665206199209698501">"إيقاف"</item>
+ <item msgid="1593289376502312923">"64 كيلوبايت"</item>
+ <item msgid="487545340236145324">"256 كيلوبايت"</item>
+ <item msgid="2423528675294333831">"1 ميغابايت"</item>
+ <item msgid="180883774509476541">"4 ميغابايت"</item>
+ <item msgid="2803199102589126938">"16 ميغابايت"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 كيلوبايت"</item>
- <item msgid="3534782711045262344">"256 كيلوبايت"</item>
- <item msgid="8085867209202153403">"1 ميغابايت"</item>
+ <item msgid="6089470720451068364">"إيقاف"</item>
+ <item msgid="4622460333038586791">"64 كيلوبايت"</item>
+ <item msgid="2212125625169582330">"256 كيلوبايت"</item>
+ <item msgid="1704946766699242653">"1 ميغابايت"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
- <item msgid="2822309747675758628">"256 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
- <item msgid="6699306198357496731">"1 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
- <item msgid="5748528643937500349">"4 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
- <item msgid="1978629051085111592">"16 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+ <item msgid="6921048829791179331">"إيقاف"</item>
+ <item msgid="2969458029344750262">"64 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+ <item msgid="1342285115665698168">"256 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+ <item msgid="1314234299552254621">"1 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+ <item msgid="3606047780792894151">"4 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+ <item msgid="5431354956856655120">"16 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"إيقاف الرسوم المتحركة"</item>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index fc11a6b6fab3..71761b99a235 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"تمكين النوافذ الحرة"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"لتمكين إتاحة استخدام النوافذ الحرة التجريبية."</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="2731163425081172638">"المس لتغيير كلمة مرور النسخ الاحتياطية الكاملة لسطح المكتب أو إزالتها"</string>
diff --git a/packages/SettingsLib/res/values-az-rAZ/arrays.xml b/packages/SettingsLib/res/values-az-rAZ/arrays.xml
index c58b1c6ac175..682b13937523 100644
--- a/packages/SettingsLib/res/values-az-rAZ/arrays.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Həmişə HDCP yoxlama istifadə edin"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Deaktiv"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Deaktiv"</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="7346595473588765019">"hər jurnal buferinə 64K"</item>
- <item msgid="2822309747675758628">"hər jurnal buferinə 256K"</item>
- <item msgid="6699306198357496731">"hər jurnal buferinə 1M"</item>
- <item msgid="5748528643937500349">"hər jurnal buferinə 4M"</item>
- <item msgid="1978629051085111592">"hər jurnal buferinə 16M"</item>
+ <item msgid="6921048829791179331">"Deaktiv"</item>
+ <item msgid="2969458029344750262">"hər jurnal buferinə 64K"</item>
+ <item msgid="1342285115665698168">"hər jurnal buferinə 256K"</item>
+ <item msgid="1314234299552254621">"hər jurnal buferinə 1M"</item>
+ <item msgid="3606047780792894151">"hər jurnal buferinə 4M"</item>
+ <item msgid="5431354956856655120">"hər jurnal buferinə 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasiya deaktiv"</item>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 4a5ea375b056..b5a718116e30 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -247,6 +247,8 @@
<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="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="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="2731163425081172638">"Masaüstünün tam rezevr kopyalanması üçün parolu dəyişmək və ya silmək üçün toxunun"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
index 8bdec3297a58..4715cbf653aa 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Uvek koristi HDCP proveru"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Isključeno"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Isključeno"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB po baferu evidencije"</item>
- <item msgid="2822309747675758628">"256 kB po baferu evidencije"</item>
- <item msgid="6699306198357496731">"1 MB po baferu evidencije"</item>
- <item msgid="5748528643937500349">"4 MB po baferu evidencije"</item>
- <item msgid="1978629051085111592">"16 MB po baferu evidencije"</item>
+ <item msgid="6921048829791179331">"Isključeno"</item>
+ <item msgid="2969458029344750262">"64 kB po međumemoriji evidencije"</item>
+ <item msgid="1342285115665698168">"256 kB po međumemoriji evidencije"</item>
+ <item msgid="1314234299552254621">"1 MB po međumemoriji evidencije"</item>
+ <item msgid="3606047780792894151">"4 MB po međumemoriji evidencije"</item>
+ <item msgid="5431354956856655120">"16 MB po međumemoriji evidencije"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija je isključena"</item>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 676c618389fe..54d2dfa3c8ef 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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 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>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dodirnite da biste promenili ili uklonili lozinku za pravljenje rezervnih kopija čitavog sistema na računaru"</string>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index 277800d9de10..42339ef2867b 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Винаги да се използва проверка с HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 КБ"</item>
- <item msgid="505611754508988476">"256 КБ"</item>
- <item msgid="6361286924268716397">"1 МБ"</item>
- <item msgid="6405203239560695266">"4 МБ"</item>
- <item msgid="3025431211013424097">"16 МБ"</item>
+ <item msgid="8665206199209698501">"Изключено"</item>
+ <item msgid="1593289376502312923">"64 КБ"</item>
+ <item msgid="487545340236145324">"256 КБ"</item>
+ <item msgid="2423528675294333831">"1 МБ"</item>
+ <item msgid="180883774509476541">"4 МБ"</item>
+ <item msgid="2803199102589126938">"16 МБ"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 КБ"</item>
- <item msgid="3534782711045262344">"256 КБ"</item>
- <item msgid="8085867209202153403">"1 МБ"</item>
+ <item msgid="6089470720451068364">"Изключено"</item>
+ <item msgid="4622460333038586791">"64 КБ"</item>
+ <item msgid="2212125625169582330">"256 КБ"</item>
+ <item msgid="1704946766699242653">"1 МБ"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Рег. буфер – 64 КБ"</item>
- <item msgid="2822309747675758628">"Рег. буфер – 256 КБ"</item>
- <item msgid="6699306198357496731">"Рег. буфер – 1 МБ"</item>
- <item msgid="5748528643937500349">"Рег. буфер – 4 МБ"</item>
- <item msgid="1978629051085111592">"Рег. буфер – 16 МБ"</item>
+ <item msgid="6921048829791179331">"Изключено"</item>
+ <item msgid="2969458029344750262">"Рег. буфер – 64 КБ"</item>
+ <item msgid="1342285115665698168">"Рег. буфер – 256 КБ"</item>
+ <item msgid="1314234299552254621">"Рег. буфер – 1 МБ"</item>
+ <item msgid="3606047780792894151">"Рег. буфер – 4 МБ"</item>
+ <item msgid="5431354956856655120">"Рег. буфер – 16 МБ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анимацията е изключена"</item>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 8180261bb619..95badc57f108 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Наст. комп.: Парола"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Понастоящем пълните резервни копия за настолен компютър не са защитени"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Докоснете, за да промените или премахнете паролата за пълни резервни копия на настолния компютър"</string>
diff --git a/packages/SettingsLib/res/values-bn-rBD/arrays.xml b/packages/SettingsLib/res/values-bn-rBD/arrays.xml
index 7729a4db9b3b..b863934a87fb 100644
--- a/packages/SettingsLib/res/values-bn-rBD/arrays.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"সর্বদা HDCP পরীক্ষণ ব্যবহার করুন"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"৬৪০০০"</item>
- <item msgid="505611754508988476">"২৫৬০০০"</item>
- <item msgid="6361286924268716397">"১০০০০০০"</item>
- <item msgid="6405203239560695266">"৪০০০০০০"</item>
- <item msgid="3025431211013424097">"১৬০০০০০০"</item>
+ <item msgid="8665206199209698501">"বন্ধ আছে"</item>
+ <item msgid="1593289376502312923">"৬৪K"</item>
+ <item msgid="487545340236145324">"২৫৬K"</item>
+ <item msgid="2423528675294333831">"১M"</item>
+ <item msgid="180883774509476541">"৪M"</item>
+ <item msgid="2803199102589126938">"১৬M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"৬৪০০০"</item>
- <item msgid="3534782711045262344">"২৫৬০০০"</item>
- <item msgid="8085867209202153403">"১০০০০০০"</item>
+ <item msgid="6089470720451068364">"বন্ধ আছে"</item>
+ <item msgid="4622460333038586791">"৬৪K"</item>
+ <item msgid="2212125625169582330">"২৫৬K"</item>
+ <item msgid="1704946766699242653">"১M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"লগ বাফার প্রতি 64K"</item>
- <item msgid="2822309747675758628">"লগ বাফার প্রতি 256K"</item>
- <item msgid="6699306198357496731">"লগ বাফার প্রতি 1M"</item>
- <item msgid="5748528643937500349">"লগ বাফার প্রতি 4M"</item>
- <item msgid="1978629051085111592">"লগ বাফার প্রতি 16M"</item>
+ <item msgid="6921048829791179331">"বন্ধ আছে"</item>
+ <item msgid="2969458029344750262">"লগ বাফার প্রতি ৬৪K"</item>
+ <item msgid="1342285115665698168">"লগ বাফার প্রতি ২৫৬K"</item>
+ <item msgid="1314234299552254621">"লগ বাফার প্রতি ১M"</item>
+ <item msgid="3606047780792894151">"লগ বাফার প্রতি ৪M"</item>
+ <item msgid="5431354956856655120">"লগ বাফার প্রতি ১৬M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"অ্যানিমেশন বন্ধ করুন"</item>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index a5787f5cc1da..e4d97d7e8516 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"ডেস্কটপ ব্যাকআপ পাসওয়ার্ড"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ডেস্কটপ পূর্ণ ব্যাকআপ বর্তমানে সুরক্ষিত নয়"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ডেস্কটপ পুরো ব্যাকআপের জন্য পাসওয়ার্ড পরিবর্তন বা মুছে ফেলার জন্য স্পর্শ করুন"</string>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index ab80ccc780f2..99c8a27e58e9 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Utilitza sempre la comprovació HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"No"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64.000"</item>
- <item msgid="3534782711045262344">"256.000"</item>
- <item msgid="8085867209202153403">"1.000.000"</item>
+ <item msgid="6089470720451068364">"No"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/memòria intermèdia reg."</item>
- <item msgid="2822309747675758628">"256 K/memòria intermèdia reg."</item>
- <item msgid="6699306198357496731">"1 M/memòria intermèdia reg."</item>
- <item msgid="5748528643937500349">"4 M/memòria intermèdia reg."</item>
- <item msgid="1978629051085111592">"16 M/memòria intermèdia reg."</item>
+ <item msgid="6921048829791179331">"No"</item>
+ <item msgid="2969458029344750262">"64 K / memòria intermèdia reg."</item>
+ <item msgid="1342285115665698168">"256 K / memòria intermèdia reg."</item>
+ <item msgid="1314234299552254621">"1 M / memòria intermèdia reg."</item>
+ <item msgid="3606047780792894151">"4 M / memòria intermèdia reg."</item>
+ <item msgid="5431354956856655120">"16 M / memòria intermèdia reg."</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animació desactivada"</item>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 8553ed9f5ad1..93b6438b37c0 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Toca per canviar o eliminar la contrasenya per a còpies de seguretat d\'ordinador completes"</string>
diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml
index d46781ae6989..8953485c1fb2 100644
--- a/packages/SettingsLib/res/values-cs/arrays.xml
+++ b/packages/SettingsLib/res/values-cs/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Vždy používat kontrolu HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Vypnuto"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Vypnuto"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB na vyrovnávací paměť protokolů"</item>
- <item msgid="2822309747675758628">"256 kB na vyrovnávací paměť protokolů"</item>
- <item msgid="6699306198357496731">"1 MB na vyrovnávací paměť protokolů"</item>
- <item msgid="5748528643937500349">"4 MB na vyrovnávací paměť protokolů"</item>
- <item msgid="1978629051085111592">"16 MB na vyrovnávací paměť protokolů"</item>
+ <item msgid="6921048829791179331">"Vypnuto"</item>
+ <item msgid="2969458029344750262">"64 kB na vyrovnávací paměť protokolů"</item>
+ <item msgid="1342285115665698168">"256 kB na vyrovnávací paměť protokolů"</item>
+ <item msgid="1314234299552254621">"1 MB na vyrovnávací paměť protokolů"</item>
+ <item msgid="3606047780792894151">"4 MB na vyrovnávací paměť protokolů"</item>
+ <item msgid="5431354956856655120">"16 MB na vyrovnávací paměť protokolů"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animace je vypnuta"</item>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 495f10fa3729..beb8f94abebc 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -247,6 +247,8 @@
<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="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="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>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tuto možnost vyberte, chcete-li změnit nebo odebrat heslo pro úplné zálohy v počítači"</string>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index 293548917a06..d700c05c8f62 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Brug altid HDCP-kontrol"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Fra"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Fra"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB pr. logbuffer"</item>
- <item msgid="2822309747675758628">"256 KB pr. logbuffer"</item>
- <item msgid="6699306198357496731">"1 MB pr. logbuffer"</item>
- <item msgid="5748528643937500349">"4 MB pr. logbuffer"</item>
- <item msgid="1978629051085111592">"16 MB pr. logbuffer"</item>
+ <item msgid="6921048829791179331">"Fra"</item>
+ <item msgid="2969458029344750262">"64 kB pr. logbuffer"</item>
+ <item msgid="1342285115665698168">"256 kB pr. logbuffer"</item>
+ <item msgid="1314234299552254621">"1 MB pr. logbuffer"</item>
+ <item msgid="3606047780792894151">"4 MB pr. logbuffer"</item>
+ <item msgid="5431354956856655120">"16 MB pr. logbuffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation fra"</item>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 82654bcc0a66..3923dbd7326b 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -247,6 +247,8 @@
<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="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="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>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tryk for at skifte eller fjerne adgangskoden til fuld lokal sikkerhedskopiering"</string>
diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml
index d2a7f0d296c8..a9c802d4a5d2 100644
--- a/packages/SettingsLib/res/values-de/arrays.xml
+++ b/packages/SettingsLib/res/values-de/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP-Prüfung immer verwenden"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64.000"</item>
- <item msgid="505611754508988476">"256.000"</item>
- <item msgid="6361286924268716397">"1 Mio."</item>
- <item msgid="6405203239560695266">"4 Mio."</item>
- <item msgid="3025431211013424097">"16 Mio."</item>
+ <item msgid="8665206199209698501">"Aus"</item>
+ <item msgid="1593289376502312923">"64.000"</item>
+ <item msgid="487545340236145324">"256.000"</item>
+ <item msgid="2423528675294333831">"1 Mio."</item>
+ <item msgid="180883774509476541">"4 Mio."</item>
+ <item msgid="2803199102589126938">"16 Mio."</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64.000"</item>
- <item msgid="3534782711045262344">"256.000"</item>
- <item msgid="8085867209202153403">"1 Mio."</item>
+ <item msgid="6089470720451068364">"Aus"</item>
+ <item msgid="4622460333038586791">"64.000"</item>
+ <item msgid="2212125625169582330">"256.000"</item>
+ <item msgid="1704946766699242653">"1 Mio."</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64.000 pro Puffer"</item>
- <item msgid="2822309747675758628">"256.000 pro Puffer"</item>
- <item msgid="6699306198357496731">"1 Mio. pro Puffer"</item>
- <item msgid="5748528643937500349">"4 Mio. pro Puffer"</item>
- <item msgid="1978629051085111592">"16 Mio. pro Puffer"</item>
+ <item msgid="6921048829791179331">"Aus"</item>
+ <item msgid="2969458029344750262">"64.000 pro Puffer"</item>
+ <item msgid="1342285115665698168">"256.000 pro Puffer"</item>
+ <item msgid="1314234299552254621">"1 Mio. pro Puffer"</item>
+ <item msgid="3606047780792894151">"4 Mio. pro Puffer"</item>
+ <item msgid="5431354956856655120">"16 Mio. pro Puffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation aus"</item>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index a2f750b06708..0b1238b84ffb 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen berühren"</string>
diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml
index 2672eeca8075..91f9d6a6b9de 100644
--- a/packages/SettingsLib/res/values-el/arrays.xml
+++ b/packages/SettingsLib/res/values-el/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Να χρησιμοποιείται πάντα έλεγχος HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Ανενεργό"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Ανενεργό"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K ανά μεγ.πρ.μν.καταγρ."</item>
- <item msgid="2822309747675758628">"256 K ανά μεγ.πρ.μν.καταγρ."</item>
- <item msgid="6699306198357496731">"1 Μ ανά μεγ.πρ.μν.καταγρ."</item>
- <item msgid="5748528643937500349">"4 M ανά μεγ.πρ.μν.καταγρ."</item>
- <item msgid="1978629051085111592">"16 M ανά μεγ.πρ.μν.καταγρ."</item>
+ <item msgid="6921048829791179331">"Ανενεργό"</item>
+ <item msgid="2969458029344750262">"64 K ανά πρ. μν. αρχ. καταγρ."</item>
+ <item msgid="1342285115665698168">"256 K ανά πρ. μν. αρχ. καταγρ."</item>
+ <item msgid="1314234299552254621">"1 Μ ανά προσ. μν. αρχ. καταγρ."</item>
+ <item msgid="3606047780792894151">"4 M ανά προσ. μν. αρχ. καταγρ."</item>
+ <item msgid="5431354956856655120">"16 M ανά πρ. μν. αρχ. καταγρ."</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Κινούμ.εικόνες απενεργοποιημένες"</item>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index d42661638f78..c3acca719754 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"Ενεργοποίηση παραθύρων ελεύθερης μορφής"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ενεργοποιεί την υποστήριξη για πειραματικά παράθυρα ελεύθερης μορφής."</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="2731163425081172638">"Αγγίξτε για αλλαγή ή κατάργηση του κωδικού πρόσβασης για τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index 21340d8b1d8c..05518900982e 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Always use HDCP checking"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Off"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Off"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K per log buffer"</item>
- <item msgid="2822309747675758628">"256 K per log buffer"</item>
- <item msgid="6699306198357496731">"1 M per log buffer"</item>
- <item msgid="5748528643937500349">"4 M per log buffer"</item>
- <item msgid="1978629051085111592">"16 M per log buffer"</item>
+ <item msgid="6921048829791179331">"Off"</item>
+ <item msgid="2969458029344750262">"64 K per log buffer"</item>
+ <item msgid="1342285115665698168">"256 K per log buffer"</item>
+ <item msgid="1314234299552254621">"1 M per log buffer"</item>
+ <item msgid="3606047780792894151">"4 M per log buffer"</item>
+ <item msgid="5431354956856655120">"16 M per log buffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation off"</item>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index b8c852135549..dae40d91882c 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index 21340d8b1d8c..05518900982e 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Always use HDCP checking"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Off"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Off"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K per log buffer"</item>
- <item msgid="2822309747675758628">"256 K per log buffer"</item>
- <item msgid="6699306198357496731">"1 M per log buffer"</item>
- <item msgid="5748528643937500349">"4 M per log buffer"</item>
- <item msgid="1978629051085111592">"16 M per log buffer"</item>
+ <item msgid="6921048829791179331">"Off"</item>
+ <item msgid="2969458029344750262">"64 K per log buffer"</item>
+ <item msgid="1342285115665698168">"256 K per log buffer"</item>
+ <item msgid="1314234299552254621">"1 M per log buffer"</item>
+ <item msgid="3606047780792894151">"4 M per log buffer"</item>
+ <item msgid="5431354956856655120">"16 M per log buffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation off"</item>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index b8c852135549..dae40d91882c 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index 21340d8b1d8c..05518900982e 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Always use HDCP checking"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Off"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Off"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K per log buffer"</item>
- <item msgid="2822309747675758628">"256 K per log buffer"</item>
- <item msgid="6699306198357496731">"1 M per log buffer"</item>
- <item msgid="5748528643937500349">"4 M per log buffer"</item>
- <item msgid="1978629051085111592">"16 M per log buffer"</item>
+ <item msgid="6921048829791179331">"Off"</item>
+ <item msgid="2969458029344750262">"64 K per log buffer"</item>
+ <item msgid="1342285115665698168">"256 K per log buffer"</item>
+ <item msgid="1314234299552254621">"1 M per log buffer"</item>
+ <item msgid="3606047780792894151">"4 M per log buffer"</item>
+ <item msgid="5431354956856655120">"16 M per log buffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation off"</item>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index b8c852135549..dae40d91882c 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml
index 52992d55d2a4..1b7a9f0f22ed 100644
--- a/packages/SettingsLib/res/values-es-rUS/arrays.xml
+++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Siempre utilizar comprobación HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desactivado"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desactivado"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/búfer registro"</item>
- <item msgid="2822309747675758628">"256 K/búfer registro"</item>
- <item msgid="6699306198357496731">"1 M/búfer registro"</item>
- <item msgid="5748528643937500349">"4 M/búfer registro"</item>
- <item msgid="1978629051085111592">"16 M/búfer registro"</item>
+ <item msgid="6921048829791179331">"Desactivado"</item>
+ <item msgid="2969458029344750262">"64 K/búfer registro"</item>
+ <item msgid="1342285115665698168">"256 K/búfer registro"</item>
+ <item msgid="1314234299552254621">"1 M/búfer registro"</item>
+ <item msgid="3606047780792894151">"4 M/búfer registro"</item>
+ <item msgid="5431354956856655120">"16 M/búfer registro"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animación desactivada"</item>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 34ebef451b62..855b72ca97b7 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Toca para cambiar o eliminar la contraseña de las copias de seguridad completas de tu escritorio."</string>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index 04932175098a..e4b661ef5b65 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Utilizar siempre comprobación de HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"No"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"No"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/búfer registro"</item>
- <item msgid="2822309747675758628">"256 K/búfer registro"</item>
- <item msgid="6699306198357496731">"1 M/búfer registro"</item>
- <item msgid="5748528643937500349">"4 M/búfer registro"</item>
- <item msgid="1978629051085111592">"16 M/búfer registro"</item>
+ <item msgid="6921048829791179331">"No"</item>
+ <item msgid="2969458029344750262">"64 K/búfer registro"</item>
+ <item msgid="1342285115665698168">"256 K/búfer registro"</item>
+ <item msgid="1314234299552254621">"1 M/búfer registro"</item>
+ <item msgid="3606047780792894151">"4 M/búfer registro"</item>
+ <item msgid="5431354956856655120">"16 M/búfer registro"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animación desactivada"</item>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index cedd5825b6e2..858c1b6d31b1 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -247,6 +247,8 @@
<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="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="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>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tocar para cambiar o quitar la contraseña para las copias de seguridad completas de ordenador"</string>
diff --git a/packages/SettingsLib/res/values-et-rEE/arrays.xml b/packages/SettingsLib/res/values-et-rEE/arrays.xml
index 5bf13bb5f82c..97319835446f 100644
--- a/packages/SettingsLib/res/values-et-rEE/arrays.xml
+++ b/packages/SettingsLib/res/values-et-rEE/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Kasuta alati HDCP-kontrollimist"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 000"</item>
- <item msgid="505611754508988476">"256 000"</item>
- <item msgid="6361286924268716397">"1 000 000"</item>
- <item msgid="6405203239560695266">"4 000 000"</item>
- <item msgid="3025431211013424097">"16 000 000"</item>
+ <item msgid="8665206199209698501">"Väljas"</item>
+ <item msgid="1593289376502312923">"64 000"</item>
+ <item msgid="487545340236145324">"256 000"</item>
+ <item msgid="2423528675294333831">"1 000 000"</item>
+ <item msgid="180883774509476541">"4 000 000"</item>
+ <item msgid="2803199102589126938">"16 000 000"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 000"</item>
- <item msgid="3534782711045262344">"256 000"</item>
- <item msgid="8085867209202153403">"1 000 000"</item>
+ <item msgid="6089470720451068364">"Väljas"</item>
+ <item msgid="4622460333038586791">"64 000"</item>
+ <item msgid="2212125625169582330">"256 000"</item>
+ <item msgid="1704946766699242653">"1 000 000"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 k / logipuhver"</item>
- <item msgid="2822309747675758628">"256 k / logipuhver"</item>
- <item msgid="6699306198357496731">"1 mln / logipuhver"</item>
- <item msgid="5748528643937500349">"4 mln / logipuhver"</item>
- <item msgid="1978629051085111592">"16 mln / logipuhver"</item>
+ <item msgid="6921048829791179331">"Väljas"</item>
+ <item msgid="2969458029344750262">"64 000 / logipuhver"</item>
+ <item msgid="1342285115665698168">"256 000 / logipuhver"</item>
+ <item msgid="1314234299552254621">"1 000 000 / logipuhver"</item>
+ <item msgid="3606047780792894151">"4 000 000 / logipuhver"</item>
+ <item msgid="5431354956856655120">"16 000 000 / logipuhver"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animatsioon väljas"</item>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index 714004e1c409..7f1056ca077d 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -247,6 +247,8 @@
<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="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="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="2731163425081172638">"Puudutage, et muuta või eemaldada täielike arvutivarunduste parool"</string>
diff --git a/packages/SettingsLib/res/values-eu-rES/arrays.xml b/packages/SettingsLib/res/values-eu-rES/arrays.xml
index 707ace521737..b72b53773753 100644
--- a/packages/SettingsLib/res/values-eu-rES/arrays.xml
+++ b/packages/SettingsLib/res/values-eu-rES/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Erabili beti HDCP egiaztapena"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desaktibatuta"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desaktibatuta"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K erregistroen bufferreko"</item>
- <item msgid="2822309747675758628">"256 K erregistroen bufferreko"</item>
- <item msgid="6699306198357496731">"1 M erregistroen bufferreko"</item>
- <item msgid="5748528643937500349">"4 M erregistroen bufferreko"</item>
- <item msgid="1978629051085111592">"16 M erregistroen bufferreko"</item>
+ <item msgid="6921048829791179331">"Desaktibatuta"</item>
+ <item msgid="2969458029344750262">"64 K erregistroen bufferreko"</item>
+ <item msgid="1342285115665698168">"256 K erregistroen bufferreko"</item>
+ <item msgid="1314234299552254621">"1 M erregistroen bufferreko"</item>
+ <item msgid="3606047780792894151">"4 M erregistroen bufferreko"</item>
+ <item msgid="5431354956856655120">"16 M erregistroen bufferreko"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animazioa desaktibatuta"</item>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index 7f47bf3fbe7f..fe5fc2945e99 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Ukitu ordenagailuko babeskopia osoak egiteko pasahitza aldatzeko edo kentzeko"</string>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index d75280b82626..1b4e335748ed 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"‏همیشه از بررسی HDCP استفاده شود"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"۶۴ کیلوبایت"</item>
- <item msgid="505611754508988476">"۲۵۶ کیلوبایت"</item>
- <item msgid="6361286924268716397">"۱ مگابایت"</item>
- <item msgid="6405203239560695266">"۴ مگابایت"</item>
- <item msgid="3025431211013424097">"۱۶ مگابایت"</item>
+ <item msgid="8665206199209698501">"خاموش"</item>
+ <item msgid="1593289376502312923">"۶۴ هزار"</item>
+ <item msgid="487545340236145324">"۲۵۶ هزار"</item>
+ <item msgid="2423528675294333831">"۱ میلیون"</item>
+ <item msgid="180883774509476541">"۴ میلیون"</item>
+ <item msgid="2803199102589126938">"۱۶ میلیون"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"۶۴ کیلوبایت"</item>
- <item msgid="3534782711045262344">"۲۵۶ کیلوبایت"</item>
- <item msgid="8085867209202153403">"۱ مگابایت"</item>
+ <item msgid="6089470720451068364">"خاموش"</item>
+ <item msgid="4622460333038586791">"۶۴ هزار"</item>
+ <item msgid="2212125625169582330">"۲۵۶ هزار"</item>
+ <item msgid="1704946766699242653">"۱ میلیون"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"‏۶۴K در حافظه موقت ثبت"</item>
- <item msgid="2822309747675758628">"‏۲۵۶Kدر حافظه موقت ثبت"</item>
- <item msgid="6699306198357496731">"‏۱Mدر حافظه موقت ثبت"</item>
- <item msgid="5748528643937500349">"‏۴M در حافظه موقت ثبت"</item>
- <item msgid="1978629051085111592">"‏۱۶M در حافظه موقت ثبت"</item>
+ <item msgid="6921048829791179331">"خاموش"</item>
+ <item msgid="2969458029344750262">"۶۴ هزار در هر بافر گزارش"</item>
+ <item msgid="1342285115665698168">"۲۵۶ هزار در هر بافر گزارش"</item>
+ <item msgid="1314234299552254621">"۱ میلیون در هر بافر گزارش"</item>
+ <item msgid="3606047780792894151">"۴ میلیون در هر بافر گزارش"</item>
+ <item msgid="5431354956856655120">"۱۶ میلیون در هر بافر گزارش"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"پویانمایی خاموش"</item>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 1f8b575cf667..e1a35f7ba7a3 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"گذرواژه پشتیبان‌گیری محلی"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"پشتیبان‌گیری کامل رایانه درحال حاضر محافظت نمی‌شود"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"برای تغییر یا حذف گذرواژه برای نسخه‌های پشتیبان کامل دسک‌تاپ لمس کنید"</string>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index 40d07876a99a..15e6e40dffbe 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Käytä aina HDCP-tarkistusta"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kt"</item>
- <item msgid="505611754508988476">"256 kt"</item>
- <item msgid="6361286924268716397">"1 Mt"</item>
- <item msgid="6405203239560695266">"4 Mt"</item>
- <item msgid="3025431211013424097">"16 Mt"</item>
+ <item msgid="8665206199209698501">"Ei käytössä"</item>
+ <item msgid="1593289376502312923">"64 kt"</item>
+ <item msgid="487545340236145324">"256 kt"</item>
+ <item msgid="2423528675294333831">"1 Mt"</item>
+ <item msgid="180883774509476541">"4 Mt"</item>
+ <item msgid="2803199102589126938">"16 Mt"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kt"</item>
- <item msgid="3534782711045262344">"256 kt"</item>
- <item msgid="8085867209202153403">"1 Mt"</item>
+ <item msgid="6089470720451068364">"Ei käytössä"</item>
+ <item msgid="4622460333038586791">"64 kt"</item>
+ <item msgid="2212125625169582330">"256 kt"</item>
+ <item msgid="1704946766699242653">"1 Mt"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kt / lokipuskuri"</item>
- <item msgid="2822309747675758628">"256 kt / lokipuskuri"</item>
- <item msgid="6699306198357496731">"1 Mt / lokipuskuri"</item>
- <item msgid="5748528643937500349">"4 Mt / lokipuskuri"</item>
- <item msgid="1978629051085111592">"16 Mt / lokipuskuri"</item>
+ <item msgid="6921048829791179331">"Ei käytössä"</item>
+ <item msgid="2969458029344750262">"64 kt / lokipuskuri"</item>
+ <item msgid="1342285115665698168">"256 kt / lokipuskuri"</item>
+ <item msgid="1314234299552254621">"1 Mt / lokipuskuri"</item>
+ <item msgid="3606047780792894151">"4 Mt / lokipuskuri"</item>
+ <item msgid="5431354956856655120">"16 Mt / lokipuskuri"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animaatio pois käytöstä"</item>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index e4b4b93fd8ff..498f2045c0c8 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Muuta tai vaihda tietokoneen kaikkien tietojen varmuuskopioinnin salasana koskettamalla"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
index 714dbe486c07..ab48103ffb7d 100644
--- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Toujours utiliser la vérification HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 ko"</item>
- <item msgid="505611754508988476">"256 ko"</item>
- <item msgid="6361286924268716397">"1 Mo"</item>
- <item msgid="6405203239560695266">"4 Mo"</item>
- <item msgid="3025431211013424097">"16 Mo"</item>
+ <item msgid="8665206199209698501">"Désactivé"</item>
+ <item msgid="1593289376502312923">"64 ko"</item>
+ <item msgid="487545340236145324">"256 ko"</item>
+ <item msgid="2423528675294333831">"1 Mo"</item>
+ <item msgid="180883774509476541">"4 Mo"</item>
+ <item msgid="2803199102589126938">"16 Mo"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 ko"</item>
- <item msgid="3534782711045262344">"256 ko"</item>
- <item msgid="8085867209202153403">"1 Mo"</item>
+ <item msgid="6089470720451068364">"Désactivé"</item>
+ <item msgid="4622460333038586791">"64 ko"</item>
+ <item msgid="2212125625169582330">"256 ko"</item>
+ <item msgid="1704946766699242653">"1 Mo"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"1 ko/tampon journal"</item>
- <item msgid="2822309747675758628">"256 Ko/tampon journal"</item>
- <item msgid="6699306198357496731">"1 Mo/tampon journal"</item>
- <item msgid="5748528643937500349">"4 Mo/tampon journal"</item>
- <item msgid="1978629051085111592">"16 Mo/tampon journal"</item>
+ <item msgid="6921048829791179331">"Désactivé"</item>
+ <item msgid="2969458029344750262">"64 ko/tampon journal"</item>
+ <item msgid="1342285115665698168">"256 Ko/tampon journal"</item>
+ <item msgid="1314234299552254621">"1 Mo/tampon journal"</item>
+ <item msgid="3606047780792894151">"4 Mo/tampon journal"</item>
+ <item msgid="5431354956856655120">"16 Mo/tampon journal"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation désactivée"</item>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 66c54a196ddc..b32bfb7eb35d 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
index a8bed699a3a1..1cfd3d422cfd 100644
--- a/packages/SettingsLib/res/values-fr/arrays.xml
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Toujours utiliser la vérification HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 Ko"</item>
- <item msgid="505611754508988476">"256 Ko"</item>
- <item msgid="6361286924268716397">"1 Mo"</item>
- <item msgid="6405203239560695266">"4 Mo"</item>
- <item msgid="3025431211013424097">"16 Mo"</item>
+ <item msgid="8665206199209698501">"Désactivé"</item>
+ <item msgid="1593289376502312923">"64 Ko"</item>
+ <item msgid="487545340236145324">"256 Ko"</item>
+ <item msgid="2423528675294333831">"1 Mo"</item>
+ <item msgid="180883774509476541">"4 Mo"</item>
+ <item msgid="2803199102589126938">"16 Mo"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 Ko"</item>
- <item msgid="3534782711045262344">"256 Ko"</item>
- <item msgid="8085867209202153403">"1 Mo"</item>
+ <item msgid="6089470720451068364">"Désactivé"</item>
+ <item msgid="4622460333038586791">"64 Ko"</item>
+ <item msgid="2212125625169582330">"256 Ko"</item>
+ <item msgid="1704946766699242653">"1 Mo"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 Ko/tampon journal"</item>
- <item msgid="2822309747675758628">"256 Ko/tampon journal"</item>
- <item msgid="6699306198357496731">"1 Mo/tampon journal"</item>
- <item msgid="5748528643937500349">"4 Mo/tampon journal"</item>
- <item msgid="1978629051085111592">"16 Mo/tampon journal"</item>
+ <item msgid="6921048829791179331">"Désactivé"</item>
+ <item msgid="2969458029344750262">"64 Ko par tampon journal"</item>
+ <item msgid="1342285115665698168">"256 Ko par tampon journal"</item>
+ <item msgid="1314234299552254621">"1 Mo par tampon journal"</item>
+ <item msgid="3606047780792894151">"4 Mo par tampon journal"</item>
+ <item msgid="5431354956856655120">"16 Mo par tampon journal"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation désactivée"</item>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index e56940a43312..0190454e52be 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string>
diff --git a/packages/SettingsLib/res/values-gl-rES/arrays.xml b/packages/SettingsLib/res/values-gl-rES/arrays.xml
index 606e6f6499d7..01b8fdf902c8 100644
--- a/packages/SettingsLib/res/values-gl-rES/arrays.xml
+++ b/packages/SettingsLib/res/values-gl-rES/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Utilizar sempre a comprobación HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desactivado"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desactivado"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Búfer 64 K rexistro"</item>
- <item msgid="2822309747675758628">"Búfer 256 K rexist."</item>
- <item msgid="6699306198357496731">"Búfer 1 M rexistro"</item>
- <item msgid="5748528643937500349">"Búfer 4 M rexistro"</item>
- <item msgid="1978629051085111592">"Búfer 16 M rexistro"</item>
+ <item msgid="6921048829791179331">"Desactivado"</item>
+ <item msgid="2969458029344750262">"64 K por búfer de rexistro"</item>
+ <item msgid="1342285115665698168">"256 K por búfer de rexistro"</item>
+ <item msgid="1314234299552254621">"1 M por búfer de rexistro"</item>
+ <item msgid="3606047780792894151">"4 M por búfer de rexistro"</item>
+ <item msgid="5431354956856655120">"16 M por búfer de rexistro"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animación desactivada"</item>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index 9bcf77037279..0efe805be218 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -247,6 +247,8 @@
<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="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="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>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca para cambiar ou eliminar o contrasinal para as copias de seguranza completas do escritorio"</string>
diff --git a/packages/SettingsLib/res/values-gu-rIN/arrays.xml b/packages/SettingsLib/res/values-gu-rIN/arrays.xml
index c7d62c563f9f..92cbb2d8d41b 100644
--- a/packages/SettingsLib/res/values-gu-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"હંમેશા HDCP તપાસનો ઉપયોગ કરો"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"બંધ"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"બંધ"</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="7346595473588765019">"લૉગ બફર દીઠ 64K"</item>
- <item msgid="2822309747675758628">"લૉગ દીઠ 256K બફર"</item>
- <item msgid="6699306198357496731">"લૉગ બફર દીઠ 1M"</item>
- <item msgid="5748528643937500349">"લૉગ બફર દીઠ 4M"</item>
- <item msgid="1978629051085111592">"પ્રતિ લૉગ બફર 16M"</item>
+ <item msgid="6921048829791179331">"બંધ"</item>
+ <item msgid="2969458029344750262">"લૉગ બફર દીઠ 64K"</item>
+ <item msgid="1342285115665698168">"લૉગ બફર દીઠ 256K"</item>
+ <item msgid="1314234299552254621">"લૉગ બફર દીઠ 1M"</item>
+ <item msgid="3606047780792894151">"લૉગ બફર દીઠ 4M"</item>
+ <item msgid="5431354956856655120">"લૉગ બફર દીઠ 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"એનિમેશન બંધ"</item>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 6dff8faddc6c..4b72648244bb 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"મુક્તાકાર વિંડોઝ સક્ષમ કરો"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"પ્રાયોગિક મુક્તાકાર વિંડોઝ માટે સમર્થનને સક્ષમ કરે છે."</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="2731163425081172638">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ્સ માટેનો પાસવર્ડ બદલવા અથવા દૂર કરવા માટે ટચ કરો"</string>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 883e997546af..8aa98a1f1d67 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"हमेशा HDCP जांच का उपयोग करें"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"बंद"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"बंद"</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="7346595473588765019">"64K प्रति लॉग बफ़र"</item>
- <item msgid="2822309747675758628">"256K प्रति लॉग बफ़र"</item>
- <item msgid="6699306198357496731">"1M प्रति लॉग बफ़र"</item>
- <item msgid="5748528643937500349">"4M प्रति लॉग बफ़र"</item>
- <item msgid="1978629051085111592">"16M प्रति लॉग बफ़र"</item>
+ <item msgid="6921048829791179331">"बंद"</item>
+ <item msgid="2969458029344750262">"64K प्रति लॉग बफ़र"</item>
+ <item msgid="1342285115665698168">"256K प्रति लॉग बफ़र"</item>
+ <item msgid="1314234299552254621">"1M प्रति लॉग बफ़र"</item>
+ <item msgid="3606047780792894151">"4M प्रति लॉग बफ़र"</item>
+ <item msgid="5431354956856655120">"16M प्रति लॉग बफ़र"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"एनिमेशन बंद"</item>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 9ce83fa48247..5224c380e125 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"फ़्रीफ़ॉर्म विंडो सक्षम करें"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ़्रीफ़ॉर्म विंडो का समर्थन सक्षम करती है."</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="2731163425081172638">"डेस्कटॉप के पूर्ण बैकअप के पासवर्ड को बदलने या निकालने के लिए स्‍पर्श करें."</string>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
index d51f82dfea42..db460c7cce92 100644
--- a/packages/SettingsLib/res/values-hr/arrays.xml
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Uvijek upotrebljavaj HDCP provjeru"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Isključeno"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Isključeno"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB po međusprem."</item>
- <item msgid="2822309747675758628">"256 KB po međuspr."</item>
- <item msgid="6699306198357496731">"1 MB po međusprem."</item>
- <item msgid="5748528643937500349">"4 MB po međusprem."</item>
- <item msgid="1978629051085111592">"16 MB po međusprem."</item>
+ <item msgid="6921048829791179331">"Isključeno"</item>
+ <item msgid="2969458029344750262">"64 KB po međusprem. zapisnika"</item>
+ <item msgid="1342285115665698168">"256 KB po međusprem. zapisnika"</item>
+ <item msgid="1314234299552254621">"1 MB po međusprem. zapisnika"</item>
+ <item msgid="3606047780792894151">"4 MB po međusprem. zapisnika"</item>
+ <item msgid="5431354956856655120">"16 MB po međusprem. zapisnika"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija isključena"</item>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index dd0217151bf6..5cde2332d91f 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Odaberite za promjenu ili uklanjanje zaporke u potpunim sigurnosnim kopijama na stolnom računalu"</string>
diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml
index 03c9ed7f0cbd..0d201b5be03b 100644
--- a/packages/SettingsLib/res/values-hu/arrays.xml
+++ b/packages/SettingsLib/res/values-hu/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Mindig használjon HDCP ellenőrzést"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Ki"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Ki"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB/naplópuffer"</item>
- <item msgid="2822309747675758628">"256 KB/naplópuffer"</item>
- <item msgid="6699306198357496731">"1 MB/naplópuffer"</item>
- <item msgid="5748528643937500349">"4 MB/naplópuffer"</item>
- <item msgid="1978629051085111592">"16 MB/naplópuffer"</item>
+ <item msgid="6921048829791179331">"Ki"</item>
+ <item msgid="2969458029344750262">"64 KB/naplópuffer"</item>
+ <item msgid="1342285115665698168">"256 KB/naplópuffer"</item>
+ <item msgid="1314234299552254621">"1 MB/naplópuffer"</item>
+ <item msgid="3606047780792894151">"4 MB/naplópuffer"</item>
+ <item msgid="5431354956856655120">"16 MB/naplópuffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animáció ki"</item>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 9b3a386c5abb..3559f1e23646 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -247,6 +247,8 @@
<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="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="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="2731163425081172638">"Érintse meg, ha módosítaná vagy eltávolítaná a jelszót az asztali teljes mentésekhez"</string>
diff --git a/packages/SettingsLib/res/values-hy-rAM/arrays.xml b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
index 41143de5b9f6..0755a8ab0370 100644
--- a/packages/SettingsLib/res/values-hy-rAM/arrays.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Միշտ օգտագործել HDCP ստուգումը"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64ԿԲ"</item>
- <item msgid="505611754508988476">"256ԿԲ"</item>
- <item msgid="6361286924268716397">"1ՄԲ"</item>
- <item msgid="6405203239560695266">"4ՄԲ"</item>
- <item msgid="3025431211013424097">"16ՄԲ"</item>
+ <item msgid="8665206199209698501">"Անջատված է"</item>
+ <item msgid="1593289376502312923">"64ԿԲ"</item>
+ <item msgid="487545340236145324">"256ԿԲ"</item>
+ <item msgid="2423528675294333831">"1ՄԲ"</item>
+ <item msgid="180883774509476541">"4ՄԲ"</item>
+ <item msgid="2803199102589126938">"16ՄԲ"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64ԿԲ"</item>
- <item msgid="3534782711045262344">"256ԿԲ"</item>
- <item msgid="8085867209202153403">"1ՄԲ"</item>
+ <item msgid="6089470720451068364">"Անջատված է"</item>
+ <item msgid="4622460333038586791">"64ԿԲ"</item>
+ <item msgid="2212125625169582330">"256ԿԲ"</item>
+ <item msgid="1704946766699242653">"1ՄԲ"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Պահնակ՝ առավ. 64ԿԲ"</item>
- <item msgid="2822309747675758628">"Պահնակ՝ առավ. 256ԿԲ"</item>
- <item msgid="6699306198357496731">"Պահնակ՝ առավ. 1ՄԲ"</item>
- <item msgid="5748528643937500349">"Պահնակ՝ առավ. 4ՄԲ"</item>
- <item msgid="1978629051085111592">"Պահնակ՝ առավ. 16ՄԲ"</item>
+ <item msgid="6921048829791179331">"Անջատված է"</item>
+ <item msgid="2969458029344750262">"Պահնակ՝ առավ. 64ԿԲ"</item>
+ <item msgid="1342285115665698168">"Պահնակ՝ առավ. 256ԿԲ"</item>
+ <item msgid="1314234299552254621">"Պահնակ՝ առավ. 1ՄԲ"</item>
+ <item msgid="3606047780792894151">"Պահնակ՝ առավ. 4ՄԲ"</item>
+ <item msgid="5431354956856655120">"Պահնակ՝ առավ. 16ՄԲ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Անջատել շարժապատկերը"</item>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index 27db9fedbb7a..42c9a05c0221 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Աշխատասեղանի պահուստավորման գաղտնաբառ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Աշխատասեղանի ամբողջական պահուստավորումները այժմ պաշտպանված չեն"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Աշխատասեղանի ամբողջական պահուստավորման համար ընտրել փոխել կամ հեռացնել գաղտնաբառը"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 5aadc13347ec..166efd500156 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Selalu gunakan pemeriksaan HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Nonaktif"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Nonaktif"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/penyangga log"</item>
- <item msgid="2822309747675758628">"256 K/penyangga log"</item>
- <item msgid="6699306198357496731">"1 M/penyangga log"</item>
- <item msgid="5748528643937500349">"4 M/penyangga log"</item>
- <item msgid="1978629051085111592">"16 M/penyangga log"</item>
+ <item msgid="6921048829791179331">"Nonaktif"</item>
+ <item msgid="2969458029344750262">"64 K/penyangga log"</item>
+ <item msgid="1342285115665698168">"256 K/penyangga log"</item>
+ <item msgid="1314234299552254621">"1 M/penyangga log"</item>
+ <item msgid="3606047780792894151">"4 M/penyangga log"</item>
+ <item msgid="5431354956856655120">"16 M/penyangga log"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasi mati"</item>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 0cea20637741..6988a732eb26 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Sentuh guna mengubah atau menghapus sandi untuk cadangan lengkap desktop"</string>
diff --git a/packages/SettingsLib/res/values-is-rIS/arrays.xml b/packages/SettingsLib/res/values-is-rIS/arrays.xml
index bbc7aec6bbbd..6024e30d5ea1 100644
--- a/packages/SettingsLib/res/values-is-rIS/arrays.xml
+++ b/packages/SettingsLib/res/values-is-rIS/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Nota alltaf HDCP-eftirlit"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 k"</item>
- <item msgid="505611754508988476">"256 k"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Slökkt"</item>
+ <item msgid="1593289376502312923">"64 k"</item>
+ <item msgid="487545340236145324">"256 k"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 k"</item>
- <item msgid="3534782711045262344">"256 k"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Slökkt"</item>
+ <item msgid="4622460333038586791">"64 k"</item>
+ <item msgid="2212125625169582330">"256 k"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 k/biðminni"</item>
- <item msgid="2822309747675758628">"256 k/biðminni"</item>
- <item msgid="6699306198357496731">"1 M/biðminni"</item>
- <item msgid="5748528643937500349">"4 M/biðminni"</item>
- <item msgid="1978629051085111592">"16 M/biðminni"</item>
+ <item msgid="6921048829791179331">"Slökkt"</item>
+ <item msgid="2969458029344750262">"64 k/biðminni"</item>
+ <item msgid="1342285115665698168">"256 k/biðminni"</item>
+ <item msgid="1314234299552254621">"1 M/biðminni"</item>
+ <item msgid="3606047780792894151">"4 M/biðminni"</item>
+ <item msgid="5431354956856655120">"16 M/biðminni"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Slökkt á hreyfiáhrifum"</item>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index b3509ca2f39f..8d912e947fc3 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Aðgangsorð tölvuafritunar"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Heildarafritun á tölvu er ekki varin sem stendur."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Snertu til að breyta eða fjarlægja aðgangsorðið fyrir heildarafritun á tölvu"</string>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index 686d61de5e15..d64ec0633ffa 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Usa sempre la verifica HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Non attiva"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Non attiva"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB/buffer log"</item>
- <item msgid="2822309747675758628">"256 kB/buffer log"</item>
- <item msgid="6699306198357496731">"1 MB/buffer log"</item>
- <item msgid="5748528643937500349">"4 MB/buffer log"</item>
- <item msgid="1978629051085111592">"16 MB/buffer log"</item>
+ <item msgid="6921048829791179331">"Non attiva"</item>
+ <item msgid="2969458029344750262">"64 kB/buffer log"</item>
+ <item msgid="1342285115665698168">"256 kB/buffer log"</item>
+ <item msgid="1314234299552254621">"1 MB/buffer log"</item>
+ <item msgid="3606047780792894151">"4 MB/buffer log"</item>
+ <item msgid="5431354956856655120">"16 MB/buffer log"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animazione disattivata"</item>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 9f897f7ab0d8..2d98a7403041 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -247,6 +247,8 @@
<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="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="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="2731163425081172638">"Tocca per modificare o rimuovere la password per i backup desktop completi"</string>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
index 24a40b9dca52..01127c604f01 100644
--- a/packages/SettingsLib/res/values-iw/arrays.xml
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"‏תמיד השתמש בבדיקת HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"‎256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"כבוי"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"‎256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"כבוי"</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="7346595473588765019">"‏64K לכל מאגר יומן"</item>
- <item msgid="2822309747675758628">"‏256K לכל מאגר יומן"</item>
- <item msgid="6699306198357496731">"‏1M לכל מאגר יומן"</item>
- <item msgid="5748528643937500349">"‏4M לכל מאגר יומן"</item>
- <item msgid="1978629051085111592">"‏16M לכל מאגר יומן"</item>
+ <item msgid="6921048829791179331">"כבוי"</item>
+ <item msgid="2969458029344750262">"‏64K לכל מאגר יומן"</item>
+ <item msgid="1342285115665698168">"‏256K לכל מאגר יומן"</item>
+ <item msgid="1314234299552254621">"‏1M לכל מאגר יומן"</item>
+ <item msgid="3606047780792894151">"‏4M לכל מאגר יומן"</item>
+ <item msgid="5431354956856655120">"‏16M לכל מאגר יומן"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"אנימציה כבויה"</item>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 2d446120514f..e175208293ce 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"סיסמת גיבוי מקומי"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"גיבויים מלאים בשולחן העבודה אינם מוגנים כעת"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"גע כדי לשנות או להסיר את הסיסמה עבור גיבויים מלאים בשולחן העבודה"</string>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index 6307a100b7a7..3426b5c5e883 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCPチェックを常に使用する"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"OFF"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"OFF"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K/ログバッファ"</item>
- <item msgid="2822309747675758628">"256K/ログバッファ"</item>
- <item msgid="6699306198357496731">"1M/ログバッファ"</item>
- <item msgid="5748528643937500349">"4M/ログバッファ"</item>
- <item msgid="1978629051085111592">"16M/ログバッファ"</item>
+ <item msgid="6921048829791179331">"OFF"</item>
+ <item msgid="2969458029344750262">"64 K / ログバッファ"</item>
+ <item msgid="1342285115665698168">"256 K / ログバッファ"</item>
+ <item msgid="1314234299552254621">"1 M / ログバッファ"</item>
+ <item msgid="3606047780792894151">"4 M / ログバッファ"</item>
+ <item msgid="5431354956856655120">"16 M / ログバッファ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"アニメーションオフ"</item>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 81a5eaf5cd04..bf9bf8a44c2b 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"PCバックアップパスワード"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"デスクトップのフルバックアップは現在保護されていません"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"デスクトップのフルバックアップ用のパスワードを変更または削除する場合にタップします"</string>
@@ -263,9 +267,9 @@
<item msgid="8280754435979370728">"目に自然な色"</item>
<item msgid="5363960654009010371">"デジタルコンテンツに最適な色"</item>
</string-array>
- <string name="inactive_apps_title" msgid="1317817863508274533">"無効なアプリ"</string>
- <string name="inactive_app_inactive_summary" msgid="6768756967594202411">"無効。タップすると切り替わります。"</string>
- <string name="inactive_app_active_summary" msgid="4512911571954375968">"有効。タップすると切り替わります。"</string>
+ <string name="inactive_apps_title" msgid="1317817863508274533">"休止中のアプリ"</string>
+ <string name="inactive_app_inactive_summary" msgid="6768756967594202411">"休止中。タップすると切り替わります。"</string>
+ <string name="inactive_app_active_summary" msgid="4512911571954375968">"実行中。タップすると切り替わります。"</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>
diff --git a/packages/SettingsLib/res/values-ka-rGE/arrays.xml b/packages/SettingsLib/res/values-ka-rGE/arrays.xml
index ac627a292d34..4b6f78b1f90f 100644
--- a/packages/SettingsLib/res/values-ka-rGE/arrays.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ყოველთვის გამოიყენე HDCP შემოწმება"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"გამორთული"</item>
+ <item msgid="1593289376502312923">"64 კბაიტი"</item>
+ <item msgid="487545340236145324">"256 კბაიტი"</item>
+ <item msgid="2423528675294333831">"1 მბაიტი"</item>
+ <item msgid="180883774509476541">"4 მბაიტი"</item>
+ <item msgid="2803199102589126938">"16 მბაიტი"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"გამორთული"</item>
+ <item msgid="4622460333038586791">"64 კბაიტი"</item>
+ <item msgid="2212125625169582330">"256 კბაიტი"</item>
+ <item msgid="1704946766699242653">"1 მბაიტი"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K / ჟურნ. ბუფერზე"</item>
- <item msgid="2822309747675758628">"256K/ჟურნ. ბუფერზე"</item>
- <item msgid="6699306198357496731">"1M / ჟურნ. ბუფერზე"</item>
- <item msgid="5748528643937500349">"4M / ჟურნ. ბუფერზე"</item>
- <item msgid="1978629051085111592">"16M / ჟურნ. ბუფერზე"</item>
+ <item msgid="6921048829791179331">"გამორთული"</item>
+ <item msgid="2969458029344750262">"64 კბაიტი / ჟურნალის ბუფერი"</item>
+ <item msgid="1342285115665698168">"256 კბაიტი / ჟურნალის ბუფერი"</item>
+ <item msgid="1314234299552254621">"1 მბაიტი / ჟურნალის ბუფერი"</item>
+ <item msgid="3606047780792894151">"4 მბაიტი / ჟურნალის ბუფერი"</item>
+ <item msgid="5431354956856655120">"16 მბაიტი / ჟურნალის ბუფერი"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ანიმაციის გამორთვა"</item>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index e2dfd7e744f5..da9d204a80f7 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"დესკტოპის სარეზერვო ასლის პაროლი"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"დესკტოპის სრული სარეზერვო ასლები ამჟამად დაცული არ არის"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"შეეხეთ დესკტოპის სრული სარეზერვო ასლების პაროლის შესაცვლელად ან წასაშლელად"</string>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/arrays.xml b/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
index b994eb7768d9..43afb2f0ebaa 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Әрқашан HDCP (жоғары кең жолақты сандық мазмұн қорғаушы) тексерулерін қолданыңыз"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 КБ"</item>
- <item msgid="505611754508988476">"256 КБ"</item>
- <item msgid="6361286924268716397">"1 МБ"</item>
- <item msgid="6405203239560695266">"4 МБ"</item>
- <item msgid="3025431211013424097">"16 МБ"</item>
+ <item msgid="8665206199209698501">"Өшірулі"</item>
+ <item msgid="1593289376502312923">"64 КБ"</item>
+ <item msgid="487545340236145324">"256 КБ"</item>
+ <item msgid="2423528675294333831">"1 МБ"</item>
+ <item msgid="180883774509476541">"4 МБ"</item>
+ <item msgid="2803199102589126938">"16 МБ"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 КБ"</item>
- <item msgid="3534782711045262344">"256 КБ"</item>
- <item msgid="8085867209202153403">"1 МБ"</item>
+ <item msgid="6089470720451068364">"Өшірулі"</item>
+ <item msgid="4622460333038586791">"64 КБ"</item>
+ <item msgid="2212125625169582330">"256 КБ"</item>
+ <item msgid="1704946766699242653">"1 МБ"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Әр журнал буферіне 64 КБ"</item>
- <item msgid="2822309747675758628">"Әр журнал буферіне 256 КБ"</item>
- <item msgid="6699306198357496731">"Әр журнал буферіне 1 МБ"</item>
- <item msgid="5748528643937500349">"Әр журнал буферіне 4 МБ"</item>
- <item msgid="1978629051085111592">"Әр журнал буферіне 16 МБ"</item>
+ <item msgid="6921048829791179331">"Өшірулі"</item>
+ <item msgid="2969458029344750262">"Әр журнал буферіне 64 КБ"</item>
+ <item msgid="1342285115665698168">"Әр журнал буферіне 256 КБ"</item>
+ <item msgid="1314234299552254621">"Әр журнал буферіне 1 МБ"</item>
+ <item msgid="3606047780792894151">"Әр журнал буферіне 4 МБ"</item>
+ <item msgid="5431354956856655120">"Әр журнал буферіне 16 МБ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Aнимация өшірілген"</item>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index 1b8e17689bd1..549711c8a283 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Компьютер үстелінің сақтық көшірмесі"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Жұмыс үстелінің сақтық көшірмелері қазір қорғалмаған"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Жұмыс үстелінің толық сақтық көшірмесінің кілтсөзін өзгерту немесе жою үшін түртіңіз"</string>
diff --git a/packages/SettingsLib/res/values-km-rKH/arrays.xml b/packages/SettingsLib/res/values-km-rKH/arrays.xml
index 50c1299445d5..63921bc13a22 100644
--- a/packages/SettingsLib/res/values-km-rKH/arrays.xml
+++ b/packages/SettingsLib/res/values-km-rKH/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ប្រើ​ការ​ពិនិត្យ HDCP ជា​និច្ច"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"បិទ"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"បិទ"</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="7346595473588765019">"64K per log buffer"</item>
- <item msgid="2822309747675758628">"256K per log buffer"</item>
- <item msgid="6699306198357496731">"1M per log buffer"</item>
- <item msgid="5748528643937500349">"4M per log buffer"</item>
- <item msgid="1978629051085111592">"16M per log buffer"</item>
+ <item msgid="6921048829791179331">"បិទ"</item>
+ <item msgid="2969458029344750262">"64K per log buffer"</item>
+ <item msgid="1342285115665698168">"256K per log buffer"</item>
+ <item msgid="1314234299552254621">"1M per log buffer"</item>
+ <item msgid="3606047780792894151">"4M per log buffer"</item>
+ <item msgid="5431354956856655120">"16M per log buffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"បិទ​ចលនា"</item>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index 0186a68131a5..aed43652ae74 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"ពាក្យ​សម្ងាត់​បម្រុង​ទុក​លើ​ផ្ទៃតុ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ការ​បម្រុង​ទុក​ពេញលេញ​លើ​ផ្ទៃតុ​បច្ចុប្បន្ន​មិន​ត្រូវ​បាន​ការពារ​ទេ។"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ប៉ះ ដើម្បី​ប្ដូរ ឬ​លុប​ពាក្យ​សម្ងាត់​សម្រាប់​ការ​បម្រុងទុក​ពេញលេញ​លើ​ផ្ទៃតុ"</string>
diff --git a/packages/SettingsLib/res/values-kn-rIN/arrays.xml b/packages/SettingsLib/res/values-kn-rIN/arrays.xml
index fe04d28ffcc0..e1e69f706ee1 100644
--- a/packages/SettingsLib/res/values-kn-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP ಪರಿಶೀಲನೆಯನ್ನು ಯಾವಾಗಲೂ ಬಳಸು"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ಆಫ್"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ಆಫ್"</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="7346595473588765019">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 64K"</item>
- <item msgid="2822309747675758628">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 256K"</item>
- <item msgid="6699306198357496731">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 1M"</item>
- <item msgid="5748528643937500349">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 4M"</item>
- <item msgid="1978629051085111592">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 16M"</item>
+ <item msgid="6921048829791179331">"ಆಫ್"</item>
+ <item msgid="2969458029344750262">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 64K"</item>
+ <item msgid="1342285115665698168">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 256K"</item>
+ <item msgid="1314234299552254621">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 1M"</item>
+ <item msgid="3606047780792894151">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 4M"</item>
+ <item msgid="5431354956856655120">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ಆನಿಮೇಶನ್ ಆಫ್"</item>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index 56f400614523..50e5955f272d 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ಪ್ರಾಯೋಗಿಕ ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</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="2731163425081172638">"ಡೆಸ್ಕ್‌ಟಾಪ್‌ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್‌ಗಳಿಗೆ ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ಬದಲಾಯಿಸಲು ಅಥವಾ ತೆಗೆದುಹಾಕಲು ಸ್ಪರ್ಶಿಸಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
index a8d548ffc467..3e8867e36d38 100644
--- a/packages/SettingsLib/res/values-ko/arrays.xml
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"항상 HDCP 확인 사용"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"사용 안함"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"사용 안함"</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="7346595473588765019">"로그 버퍼당 64K"</item>
- <item msgid="2822309747675758628">"로그 버퍼당 256K"</item>
- <item msgid="6699306198357496731">"로그 버퍼당 1M"</item>
- <item msgid="5748528643937500349">"로그 버퍼당 4M"</item>
- <item msgid="1978629051085111592">"로그 버퍼당 16M"</item>
+ <item msgid="6921048829791179331">"사용 안함"</item>
+ <item msgid="2969458029344750262">"로그 버퍼당 64K"</item>
+ <item msgid="1342285115665698168">"로그 버퍼당 256K"</item>
+ <item msgid="1314234299552254621">"로그 버퍼당 1M"</item>
+ <item msgid="3606047780792894151">"로그 버퍼당 4M"</item>
+ <item msgid="5431354956856655120">"로그 버퍼당 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"애니메이션 사용 안함"</item>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 6ad3efd49511..ea5dc0062f0f 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"데스크톱 백업 비밀번호"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"데스크톱 전체 백업에 비밀번호가 설정되어 있지 않음"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"데스크톱 전체 백업에 대한 비밀번호를 변경하거나 삭제하려면 터치하세요."</string>
diff --git a/packages/SettingsLib/res/values-ky-rKG/arrays.xml b/packages/SettingsLib/res/values-ky-rKG/arrays.xml
index 7ec569e5077b..34c713e87c7b 100644
--- a/packages/SettingsLib/res/values-ky-rKG/arrays.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Ар дайым HDCP текшерүү колдонулсун"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Өчүк"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Өчүк"</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="7346595473588765019">"64 K каттоо буфери үчүн"</item>
- <item msgid="2822309747675758628">"256 K каттоо буфери үчүн"</item>
- <item msgid="6699306198357496731">"1 M каттоо буфери үчүн"</item>
- <item msgid="5748528643937500349">"4 M каттоо буфери үчүн"</item>
- <item msgid="1978629051085111592">"16 M каттоо буфери үчүн"</item>
+ <item msgid="6921048829791179331">"Өчүк"</item>
+ <item msgid="2969458029344750262">"Буфер: 64КБ ашпашы керек"</item>
+ <item msgid="1342285115665698168">"Буфер: 256КБ ашпашы керек"</item>
+ <item msgid="1314234299552254621">"Буфер: 1М ашпашы керек"</item>
+ <item msgid="3606047780792894151">"Буфер: 4М ашпашы керек"</item>
+ <item msgid="5431354956856655120">"Буфер: 16М ашпашы керек"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анимацияны өчүрүү"</item>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index bf37ac45b2fa..6a474066a166 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Компүтердеги бэкаптын сырсөзү"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Компүтердеги толук бэкап учурда корголгон эмес"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Тийип, компүтердеги толук бэкаптын сырсөзүн өзгөртүңүз же жок кылыңыз"</string>
diff --git a/packages/SettingsLib/res/values-lo-rLA/arrays.xml b/packages/SettingsLib/res/values-lo-rLA/arrays.xml
index 642217473eac..312ecc0c09e6 100644
--- a/packages/SettingsLib/res/values-lo-rLA/arrays.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ໃຊ້ການກວດສອບ HDCP ສະເໝີ"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ປິດ"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ປິດ"</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="7346595473588765019">"ບັບ​ເຟີ 64K ​ຕໍ່​ລັອກ"</item>
- <item msgid="2822309747675758628">"ບັບ​ເຟີ 256K ​ຕໍ່​ລັອກ"</item>
- <item msgid="6699306198357496731">"ບັບ​ເຟີ 1M ​ຕໍ່​ລັອກ"</item>
- <item msgid="5748528643937500349">"ບັບ​ເຟີ 4M ​ຕໍ່​ລັອກ"</item>
- <item msgid="1978629051085111592">"ບັບ​ເຟີ 16M ​ຕໍ່​ລັອກ"</item>
+ <item msgid="6921048829791179331">"ປິດ"</item>
+ <item msgid="2969458029344750262">"ບັບ​ເຟີ 64K ຕໍ່​ບັນທຶກ"</item>
+ <item msgid="1342285115665698168">"ບັບ​ເຟີ 256K ​ຕໍ່​ບັນທຶກ"</item>
+ <item msgid="1314234299552254621">"ບັບ​ເຟີ 1M ​ຕໍ່​ບັນທຶກ"</item>
+ <item msgid="3606047780792894151">"ບັບ​ເຟີ 4M ​ຕໍ່​ບັນທຶກ"</item>
+ <item msgid="5431354956856655120">"ບັບ​ເຟີ 16M ​ຕໍ່​ບັນທຶກ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ປິດອະນິເມຊັນ"</item>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index 9e6a4b72ac63..538a38cb2db4 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"ລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນເດັກສະທັອບ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ການ​ສຳຮອງ​ຂໍ້ມູນ​ເຕັມຮູບແບບ​ໃນ​ເດັກສະທັອບ​ຍັງ​ບໍ່​ໄດ້​ຮັບ​ການ​ປ້ອງກັນ​ໃນ​ເວລາ​ນີ້"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ແຕະເພື່ອປ່ຽນ ຫຼືລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບ"</string>
diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml
index 0d20a8a1650b..76ae3fbf06f3 100644
--- a/packages/SettingsLib/res/values-lt/arrays.xml
+++ b/packages/SettingsLib/res/values-lt/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Visada naudoti HDCP tikrinimą"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Išjungta"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Išjungta"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB žurn. bufer."</item>
- <item msgid="2822309747675758628">"256 KB žurn. bufer."</item>
- <item msgid="6699306198357496731">"1 MB žurn. bufer."</item>
- <item msgid="5748528643937500349">"4 MB žurn. bufer."</item>
- <item msgid="1978629051085111592">"16 MB žurn. bufer."</item>
+ <item msgid="6921048829791179331">"Išjungta"</item>
+ <item msgid="2969458029344750262">"64 KB žurnalo buferis"</item>
+ <item msgid="1342285115665698168">"256 KB žurnalo buferis"</item>
+ <item msgid="1314234299552254621">"1 MB žurnalo buferis"</item>
+ <item msgid="3606047780792894151">"4 MB žurnalo buferis"</item>
+ <item msgid="5431354956856655120">"16 MB žurnalo buferis"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija išjungta"</item>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 201964647d85..014a6fb37054 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Viet. atsrg. kop. slapt."</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Šiuo metu visos vietinės atsarginės kopijos neapsaugotos"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Jei norite pakeisti ar pašalinti visų vietinių atsarginių kopijų slaptažodį, palieskite"</string>
diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml
index a033d1bf3c56..03aff8c9a466 100644
--- a/packages/SettingsLib/res/values-lv/arrays.xml
+++ b/packages/SettingsLib/res/values-lv/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Vienmēr izmantot HDCP pārbaudi"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Izslēgts"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Izslēgts"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB žurn. buferis"</item>
- <item msgid="2822309747675758628">"256 KB žurn. buf."</item>
- <item msgid="6699306198357496731">"1 MB žurn. buferis"</item>
- <item msgid="5748528643937500349">"4 MB žurn. buferis"</item>
- <item msgid="1978629051085111592">"16 MB žurn. buferis"</item>
+ <item msgid="6921048829791179331">"Izslēgts"</item>
+ <item msgid="2969458029344750262">"64 KB vienam žurnāla buferim"</item>
+ <item msgid="1342285115665698168">"256 KB vienam žurnāla buferim"</item>
+ <item msgid="1314234299552254621">"1 MB vienam žurnāla buferim"</item>
+ <item msgid="3606047780792894151">"4 MB vienam žurnāla buferim"</item>
+ <item msgid="5431354956856655120">"16 MB vienam žurnāla buferim"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animācija ir izslēgta"</item>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 2f9a83b38874..87da10551316 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Datora dublējuma parole"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Darbvirsmas pilnie dublējumi pašlaik nav aizsargāti."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Pieskarieties, lai mainītu vai noņemtu paroli pilniem darbvirsmas dublējumiem."</string>
diff --git a/packages/SettingsLib/res/values-mk-rMK/arrays.xml b/packages/SettingsLib/res/values-mk-rMK/arrays.xml
index c97b57796247..588c21ad8a0b 100644
--- a/packages/SettingsLib/res/values-mk-rMK/arrays.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Секогаш користи ХДЦП проверка"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Исклучено"</item>
+ <item msgid="1593289376502312923">"64.000"</item>
+ <item msgid="487545340236145324">"256.000"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64.000"</item>
- <item msgid="3534782711045262344">"256.000"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Исклучено"</item>
+ <item msgid="4622460333038586791">"64.000"</item>
+ <item msgid="2212125625169582330">"256.000"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/меѓумеморија"</item>
- <item msgid="2822309747675758628">"256 K/меѓумеморија"</item>
- <item msgid="6699306198357496731">"1 M/меѓумеморија"</item>
- <item msgid="5748528643937500349">"4 M/меѓумеморија"</item>
- <item msgid="1978629051085111592">"16 M/меѓумеморија"</item>
+ <item msgid="6921048829791179331">"Исклучено"</item>
+ <item msgid="2969458029344750262">"64 K/меѓумеморија"</item>
+ <item msgid="1342285115665698168">"256 K/меѓумеморија"</item>
+ <item msgid="1314234299552254621">"1 M/меѓумеморија"</item>
+ <item msgid="3606047780792894151">"4 M/меѓумеморија"</item>
+ <item msgid="5431354956856655120">"16 M/меѓумеморија"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Без анимација"</item>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index e01d00c72141..b588c2c986b9 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -97,7 +97,7 @@
<string name="running_process_item_user_label" msgid="3129887865552025943">"Корисник: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="313159469856372621">"Поставени се некои стандардни вредности"</string>
<string name="launch_defaults_none" msgid="4241129108140034876">"Нема поставено стандардни вредности"</string>
- <string name="tts_settings" msgid="8186971894801348327">"Подесувања на текст-во-говор"</string>
+ <string name="tts_settings" msgid="8186971894801348327">"Поставки на текст-во-говор"</string>
<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>
@@ -117,7 +117,7 @@
<string name="tts_status_requires_network" msgid="6042500821503226892">"<xliff:g id="LOCALE">%1$s</xliff:g> бара мрежно поврзување"</string>
<string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> не е поддржано"</string>
<string name="tts_status_checking" msgid="5339150797940483592">"Се проверува..."</string>
- <string name="tts_engine_settings_title" msgid="3499112142425680334">"Подесувања на <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
+ <string name="tts_engine_settings_title" msgid="3499112142425680334">"Поставки на <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
<string name="tts_engine_settings_button" msgid="1030512042040722285">"Стартувај подесувања на софтвер"</string>
<string name="tts_engine_preference_section_title" msgid="448294500990971413">"Претпочитан софтвер"</string>
<string name="tts_general_section_title" msgid="4402572014604490502">"Општо"</string>
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"Овозможи прозорци со слободна форма"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Овозможува поддршка за експериментални прозорци со слободна форма."</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="2731163425081172638">"Допрете за да се промени или отстрани лозинката за целосна резервна копија на работната површина"</string>
diff --git a/packages/SettingsLib/res/values-ml-rIN/arrays.xml b/packages/SettingsLib/res/values-ml-rIN/arrays.xml
index 404b20a62eb0..f04cc6524fd0 100644
--- a/packages/SettingsLib/res/values-ml-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"എല്ലായ്‌പ്പോഴും HDCP പരിശോധന ഉപയോഗിക്കുക"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ഓഫ്"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ഓഫ്"</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="7346595473588765019">"ഓരോ ലോഗ് ബഫറിനും 64K"</item>
- <item msgid="2822309747675758628">"ഓരോ ലോഗ് ബഫറിനും 256K"</item>
- <item msgid="6699306198357496731">"ഓരോ ലോഗ് ബഫറിനും 1M"</item>
- <item msgid="5748528643937500349">"ഓരോ ലോഗ് ബഫറിനും 4M"</item>
- <item msgid="1978629051085111592">"ഓരോ ലോഗ് ബഫറിനും 16M"</item>
+ <item msgid="6921048829791179331">"ഓഫ്"</item>
+ <item msgid="2969458029344750262">"ഓരോ ലോഗ് ബഫറിനും 64K"</item>
+ <item msgid="1342285115665698168">"ഓരോ ലോഗ് ബഫറിനും 256K"</item>
+ <item msgid="1314234299552254621">"ഓരോ ലോഗ് ബഫറിനും 1M"</item>
+ <item msgid="3606047780792894151">"ഓരോ ലോഗ് ബഫറിനും 4M"</item>
+ <item msgid="5431354956856655120">"ഓരോ ലോഗ് ബഫറിനും 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ആനിമേഷൻ ഓഫുചെയ്യുക"</item>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index f00103f10a11..d76e87f7a562 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"ഡെ‌സ്‌ക്ടോപ്പ് ബാക്കപ്പ് പാസ്‌വേഡ്"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ഡെസ്‌ക്‌ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾ നിലവിൽ പരിരക്ഷിച്ചിട്ടില്ല"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ഡെസ്‌ക്‌ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾക്കായി പാസ്‌വേഡുകൾ മാറ്റാനോ നീക്കംചെയ്യാനോ സ്‌പർശിക്കുക"</string>
diff --git a/packages/SettingsLib/res/values-mn-rMN/arrays.xml b/packages/SettingsLib/res/values-mn-rMN/arrays.xml
index c4c6d28c9a73..c4bbbcbf44dd 100644
--- a/packages/SettingsLib/res/values-mn-rMN/arrays.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Байнга HDCP шалгахыг ашиглах"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1М"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Идэвхгүй"</item>
+ <item msgid="1593289376502312923">"64000"</item>
+ <item msgid="487545340236145324">"256000"</item>
+ <item msgid="2423528675294333831">"1 сая"</item>
+ <item msgid="180883774509476541">"4 сая"</item>
+ <item msgid="2803199102589126938">"16 сая"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1М"</item>
+ <item msgid="6089470720451068364">"Идэвхгүй"</item>
+ <item msgid="4622460333038586791">"64000"</item>
+ <item msgid="2212125625169582330">"256000"</item>
+ <item msgid="1704946766699242653">"1 сая"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"лог буфер бүрт 64K"</item>
- <item msgid="2822309747675758628">"лог буфер бүрт 256K"</item>
- <item msgid="6699306198357496731">"лог буфер бүрт 1M"</item>
- <item msgid="5748528643937500349">"лог буфер бүрт 4M"</item>
- <item msgid="1978629051085111592">"лог буфер бүрт 16M"</item>
+ <item msgid="6921048829791179331">"Идэвхгүй"</item>
+ <item msgid="2969458029344750262">"лог буфер бүрт 64K"</item>
+ <item msgid="1342285115665698168">"лог буфер бүрт 256K"</item>
+ <item msgid="1314234299552254621">"лог буфер бүрт 1M"</item>
+ <item msgid="3606047780792894151">"лог буфер бүрт 4M"</item>
+ <item msgid="5431354956856655120">"лог буфер бүрт 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Дүрс амилуулалт идэвхгүй"</item>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index cc0e7cb89b46..4aea631972fe 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Десктоп нөөшлөлтийн нууц үг"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Десктоп бүрэн нөөцлөлт одоогоор хамгаалалтгүй байна"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Десктоп дээрх бүрэн нөөшлөлтийн нууц үгийг өөрчлөх буюу арилгахын тулд хүрнэ үү"</string>
diff --git a/packages/SettingsLib/res/values-mr-rIN/arrays.xml b/packages/SettingsLib/res/values-mr-rIN/arrays.xml
index 70c11577542c..2f07389c7592 100644
--- a/packages/SettingsLib/res/values-mr-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"नेहमी HDCP तपासणी वापरा"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"बंद"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"बंद"</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="7346595473588765019">"प्रति लॉग बफर 64K"</item>
- <item msgid="2822309747675758628">"प्रति लॉग बफर 256K"</item>
- <item msgid="6699306198357496731">"प्रति लॉग बफर 1M"</item>
- <item msgid="5748528643937500349">"प्रति लॉग बफर 4M"</item>
- <item msgid="1978629051085111592">"प्रति लॉग बफर 16M"</item>
+ <item msgid="6921048829791179331">"बंद"</item>
+ <item msgid="2969458029344750262">"प्रति लॉग बफर 64K"</item>
+ <item msgid="1342285115665698168">"प्रति लॉग बफर 256K"</item>
+ <item msgid="1314234299552254621">"प्रति लॉग बफर 1M"</item>
+ <item msgid="3606047780792894151">"प्रति लॉग बफर 4M"</item>
+ <item msgid="5431354956856655120">"प्रति लॉग बफर 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"अॅनिमेशन बंद"</item>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index b939ca0c6bf4..ed57fb73e530 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"freeform विंडो सक्षम करा"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सक्षम करते."</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="2731163425081172638">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला संकेतशब्द बदलण्यासाठी किंवा काढून टाकण्यासाठी स्पर्श करा"</string>
diff --git a/packages/SettingsLib/res/values-ms-rMY/arrays.xml b/packages/SettingsLib/res/values-ms-rMY/arrays.xml
index 320fa9bfdf22..49f0f289e83c 100644
--- a/packages/SettingsLib/res/values-ms-rMY/arrays.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Sentiasa gunakan penyemakan HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Mati"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Mati"</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="7346595473588765019">"64K per penimbal log"</item>
- <item msgid="2822309747675758628">"256K per penimbal log"</item>
- <item msgid="6699306198357496731">"1M per penimbal log"</item>
- <item msgid="5748528643937500349">"4M per penimbal log"</item>
- <item msgid="1978629051085111592">"16M per penimbal log"</item>
+ <item msgid="6921048829791179331">"Mati"</item>
+ <item msgid="2969458029344750262">"64K per penimbal log"</item>
+ <item msgid="1342285115665698168">"256K per penimbal log"</item>
+ <item msgid="1314234299552254621">"1M per penimbal log"</item>
+ <item msgid="3606047780792894151">"4M per penimbal log"</item>
+ <item msgid="5431354956856655120">"16M per penimbal log"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasi dimatikan"</item>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index 2e6775280dcf..1f72d04297fe 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Sentuh untuk menukar atau mengalih keluar kata laluan untuk sandaran penuh komputer meja"</string>
diff --git a/packages/SettingsLib/res/values-my-rMM/arrays.xml b/packages/SettingsLib/res/values-my-rMM/arrays.xml
index 71b35ad5dbea..ad3a59fadee8 100644
--- a/packages/SettingsLib/res/values-my-rMM/arrays.xml
+++ b/packages/SettingsLib/res/values-my-rMM/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP checkingအားအမြဲသုံးပါ"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ပိတ်ပါ"</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="524799395770610154">"၆၄K"</item>
- <item msgid="3534782711045262344">"၂၅၆K"</item>
- <item msgid="8085867209202153403">"၁M"</item>
+ <item msgid="6089470720451068364">"ပိတ်ပါ"</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="7346595473588765019">"64K လော့ ဘာဖားတွက်"</item>
- <item msgid="2822309747675758628">"256K လော့ ဘာဖားတွက်"</item>
- <item msgid="6699306198357496731">"1M လော့ ဘာဖားတွက်"</item>
- <item msgid="5748528643937500349">"4M လော့ ဘာဖားတွက်"</item>
- <item msgid="1978629051085111592">"16M လော့ ဘာဖားတွက်"</item>
+ <item msgid="6921048829791179331">"ပိတ်ပါ"</item>
+ <item msgid="2969458029344750262">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 64K"</item>
+ <item msgid="1342285115665698168">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 256K"</item>
+ <item msgid="1314234299552254621">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 1M"</item>
+ <item msgid="3606047780792894151">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 4M"</item>
+ <item msgid="5431354956856655120">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"လှုပ်ရှားသက်ဝင်မှုပုံများကိုပိတ်ပါ"</item>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index 002aed163356..cd4812fc32f8 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Desktop အရန်စကားဝှက်"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"အလုပ်ခုံတွင် အရန်သိမ်းဆည်းခြင်းများကို လောလောဆယ် မကာကွယ်နိုင်ပါ။"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"အလုပ်ခုံ တွင် အရန်သိမ်းဆည်းခြင်းအပြည့်လုပ်ရန် အတွက် စကားဝှက်ဖယ်ရန် သို့ ပြောင်းရန် တို့ထိပါ။"</string>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
index 0877f5c525fe..8311db392da1 100644
--- a/packages/SettingsLib/res/values-nb/arrays.xml
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Bruk alltid HDCP-kontroll"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Av"</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="524799395770610154">"64 000"</item>
- <item msgid="3534782711045262344">"256 000"</item>
- <item msgid="8085867209202153403">"1 million"</item>
+ <item msgid="6089470720451068364">"Av"</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="7346595473588765019">"64 kB pr loggbuffer"</item>
- <item msgid="2822309747675758628">"256 kB pr buffer"</item>
- <item msgid="6699306198357496731">"1 MB pr loggbuffer"</item>
- <item msgid="5748528643937500349">"4 MB pr loggbuffer"</item>
- <item msgid="1978629051085111592">"16 MB pr loggbuffer"</item>
+ <item msgid="6921048829791179331">"Av"</item>
+ <item msgid="2969458029344750262">"64K per loggbuffer"</item>
+ <item msgid="1342285115665698168">"256K per loggbuffer"</item>
+ <item msgid="1314234299552254621">"1M per loggbuffer"</item>
+ <item msgid="3606047780792894151">"4M per loggbuffer"</item>
+ <item msgid="5431354956856655120">"16M per loggbuffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasjon av"</item>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index a496a21b9b65..ae0b15de635b 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Passord for sikkerhetskopiering på datamaskin"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Fullstendig sikkerhetskopiering på datamaskin beskyttes ikke for øyeblikket."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Trykk for å endre eller fjerne passordet for fullstendige sikkerhetskopier på datamaskinen"</string>
diff --git a/packages/SettingsLib/res/values-ne-rNP/arrays.xml b/packages/SettingsLib/res/values-ne-rNP/arrays.xml
index 99ec88150145..7468982d7eea 100644
--- a/packages/SettingsLib/res/values-ne-rNP/arrays.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"सधैँ HDCP जाँच प्रयोग गर्नुहोस्"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"निष्क्रिय गर्नुहोस्"</item>
+ <item msgid="1593289376502312923">"६४के"</item>
+ <item msgid="487545340236145324">"२५६के"</item>
+ <item msgid="2423528675294333831">"१एम"</item>
+ <item msgid="180883774509476541">"४एम"</item>
+ <item msgid="2803199102589126938">"१६एम"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"६४K"</item>
- <item msgid="3534782711045262344">"२५६K"</item>
- <item msgid="8085867209202153403">"१ मेगा पिक्सेल"</item>
+ <item msgid="6089470720451068364">"निष्क्रिय गर्नुहोस्"</item>
+ <item msgid="4622460333038586791">"६४के"</item>
+ <item msgid="2212125625169582330">"२५६के"</item>
+ <item msgid="1704946766699242653">"१एम"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K प्रति लग बफर"</item>
- <item msgid="2822309747675758628">"256K प्रति लग बफर"</item>
- <item msgid="6699306198357496731">"1M प्रति लग बफर"</item>
- <item msgid="5748528643937500349">"4M प्रति लग बफर"</item>
- <item msgid="1978629051085111592">"16M प्रति लग बफर"</item>
+ <item msgid="6921048829791179331">"निष्क्रिय गर्नुहोस्"</item>
+ <item msgid="2969458029344750262">"६४के प्रति लग बफर"</item>
+ <item msgid="1342285115665698168">"२५६के प्रति लग बफर"</item>
+ <item msgid="1314234299552254621">"१एम प्रति लग बफर"</item>
+ <item msgid="3606047780792894151">"४एम प्रति लग बफर"</item>
+ <item msgid="5431354956856655120">"१६एम प्रति लग बफर"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"सजीविकरण बन्द"</item>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index 5c85c256c318..58855132d33e 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"फ्रीफर्म विन्डोहरू सक्रिय गर्नुहोस्"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ्रीफर्म विन्डोहरूका लागि समर्थनलाई सक्रिय गर्छ।"</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="2731163425081172638">"डेस्कटप पूर्ण ब्याकअपको लागि पासवर्ड बदल्न वा हटाउन छुनुहोस्"</string>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index 7f76bba56005..48b135dcd5ae 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP-controle altijd gebruiken"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Uit"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Uit"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K per logbuffer"</item>
- <item msgid="2822309747675758628">"256K per logbuffer"</item>
- <item msgid="6699306198357496731">"1M per logbuffer"</item>
- <item msgid="5748528643937500349">"4M per logbuffer"</item>
- <item msgid="1978629051085111592">"16M per logbuffer"</item>
+ <item msgid="6921048829791179331">"Uit"</item>
+ <item msgid="2969458029344750262">"64 K per logbuffer"</item>
+ <item msgid="1342285115665698168">"256 K per logbuffer"</item>
+ <item msgid="1314234299552254621">"1 M per logbuffer"</item>
+ <item msgid="3606047780792894151">"4 M per logbuffer"</item>
+ <item msgid="5431354956856655120">"16 M per logbuffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animatie uit"</item>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 1afa4441b492..1dd477dd7f92 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -247,6 +247,8 @@
<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="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="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="2731163425081172638">"Raak dit aan om het wachtwoord voor volledige back-ups naar desktops te wijzigen of te verwijderen"</string>
diff --git a/packages/SettingsLib/res/values-pa-rIN/arrays.xml b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
index fa624a02eb2c..d644da636e41 100644
--- a/packages/SettingsLib/res/values-pa-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ਹਮੇਸਾਂ HDCP ਜਾਂਚ ਵਰਤੋ"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ਬੰਦ"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ਬੰਦ"</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="7346595473588765019">"64K ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
- <item msgid="2822309747675758628">"256K ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
- <item msgid="6699306198357496731">"1M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
- <item msgid="5748528643937500349">"4M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
- <item msgid="1978629051085111592">"16M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
+ <item msgid="6921048829791179331">"ਬੰਦ"</item>
+ <item msgid="2969458029344750262">"64K ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
+ <item msgid="1342285115665698168">"256K ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
+ <item msgid="1314234299552254621">"1M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
+ <item msgid="3606047780792894151">"4M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
+ <item msgid="5431354956856655120">"16M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ਐਨੀਮੇਸ਼ਨ ਬੰਦ"</item>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index ad3d3ede4c15..85f9ffb284f4 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"freeform windows ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ਪ੍ਰਯੋਗਾਤਮਕ freeform windows ਲਈ ਸਮਰਥਨ ਨੂੰ ਯੋਗ ਬਣਾਉਂਦੀ ਹੈ।"</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="2731163425081172638">"ਡੈਸਕਟੌਪ ਪੂਰੇ ਬੈਕਅਪਸ ਲਈ ਪਾਸਵਰਡ ਬਦਲਣ ਜਾਂ ਹਟਾਉਣ ਲਈ ਛੋਹਵੋ"</string>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index 8df26cd333b7..3b3e95d8eb14 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Zawsze używaj sprawdzania HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Wył."</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Wył."</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB/bufor dziennika"</item>
- <item msgid="2822309747675758628">"256 KB/bufor dziennika"</item>
- <item msgid="6699306198357496731">"1 MB/bufor dziennika"</item>
- <item msgid="5748528643937500349">"4 MB/bufor dziennika"</item>
- <item msgid="1978629051085111592">"16 MB/bufor dziennika"</item>
+ <item msgid="6921048829791179331">"Wył."</item>
+ <item msgid="2969458029344750262">"64 KB/bufor dziennika"</item>
+ <item msgid="1342285115665698168">"256 KB/bufor dziennika"</item>
+ <item msgid="1314234299552254621">"1 MB/bufor dziennika"</item>
+ <item msgid="3606047780792894151">"4 MB/bufor dziennika"</item>
+ <item msgid="5431354956856655120">"16 MB/bufor dziennika"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacja wyłączona"</item>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index d58070ee33eb..9f7c022de110 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -247,6 +247,8 @@
<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="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="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="2731163425081172638">"Wybierz, aby zmienić lub usunąć hasło pełnych kopii zapasowych na komputerze stacjonarnym."</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
index d8be2514d1ed..0d94a6de014c 100644
--- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desativado"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desativado"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K/buffer de log"</item>
- <item msgid="2822309747675758628">"256K/buffer de log"</item>
- <item msgid="6699306198357496731">"1M/buffer de log"</item>
- <item msgid="5748528643937500349">"4M/buffer de log"</item>
- <item msgid="1978629051085111592">"16M/buffer de log"</item>
+ <item msgid="6921048829791179331">"Desativado"</item>
+ <item msgid="2969458029344750262">"64 K/buffer de log"</item>
+ <item msgid="1342285115665698168">"256 K/buffer de log"</item>
+ <item msgid="1314234299552254621">"1 M/buffer de log"</item>
+ <item msgid="3606047780792894151">"4 M/buffer de log"</item>
+ <item msgid="5431354956856655120">"16 M/buffer de log"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animação desligada"</item>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 3b280431ba78..dd4b58d51cbc 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index 693430ceed89..6e84fcec977b 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Utilizar sempre a verificação HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desativado"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desativado"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Mem. int. 64K p rg."</item>
- <item msgid="2822309747675758628">"Mem. int. 256K p rg"</item>
- <item msgid="6699306198357496731">"Mem. int. 1M p reg."</item>
- <item msgid="5748528643937500349">"Mem. int. 4M p reg."</item>
- <item msgid="1978629051085111592">"Mem. int. 16M p. rg"</item>
+ <item msgid="6921048829791179331">"Desativado"</item>
+ <item msgid="2969458029344750262">"64 K por buffer de registo"</item>
+ <item msgid="1342285115665698168">"256 K por buffer de registo"</item>
+ <item msgid="1314234299552254621">"1 M por buffer de registo"</item>
+ <item msgid="3606047780792894151">"4 M por buffer de registo"</item>
+ <item msgid="5431354956856655120">"16 M por buffer de registo"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animação desativada"</item>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index c5f94cb486b4..0cbe5e4e7f86 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -247,6 +247,8 @@
<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="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="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="2731163425081172638">"Toque para alterar ou remover a palavra-passe para cópias de segurança completas no ambiente de trabalho"</string>
diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml
index d8be2514d1ed..0d94a6de014c 100644
--- a/packages/SettingsLib/res/values-pt/arrays.xml
+++ b/packages/SettingsLib/res/values-pt/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desativado"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desativado"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K/buffer de log"</item>
- <item msgid="2822309747675758628">"256K/buffer de log"</item>
- <item msgid="6699306198357496731">"1M/buffer de log"</item>
- <item msgid="5748528643937500349">"4M/buffer de log"</item>
- <item msgid="1978629051085111592">"16M/buffer de log"</item>
+ <item msgid="6921048829791179331">"Desativado"</item>
+ <item msgid="2969458029344750262">"64 K/buffer de log"</item>
+ <item msgid="1342285115665698168">"256 K/buffer de log"</item>
+ <item msgid="1314234299552254621">"1 M/buffer de log"</item>
+ <item msgid="3606047780792894151">"4 M/buffer de log"</item>
+ <item msgid="5431354956856655120">"16 M/buffer de log"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animação desligada"</item>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 3b280431ba78..dd4b58d51cbc 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index f75154f660ca..141f877a64f9 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Utilizează întotdeauna verificarea HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Dezactivată"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Dezactivată"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K/tampon jurnal"</item>
- <item msgid="2822309747675758628">"256K/tampon jurnal"</item>
- <item msgid="6699306198357496731">"1M/tampon jurnal"</item>
- <item msgid="5748528643937500349">"4M/tampon jurnal"</item>
- <item msgid="1978629051085111592">"16M/tampon jurnal"</item>
+ <item msgid="6921048829791179331">"Dezactivată"</item>
+ <item msgid="2969458029344750262">"64 KB/zonă-tampon de înregistrări în jurnal"</item>
+ <item msgid="1342285115665698168">"256 KB/zonă-tampon de înregistrări în jurnal"</item>
+ <item msgid="1314234299552254621">"1 MB/zonă-tampon de înregistrări în jurnal"</item>
+ <item msgid="3606047780792894151">"4 MB/zonă-tampon de înregistrări în jurnal"</item>
+ <item msgid="5431354956856655120">"16 MB/zonă-tampon de înregistrări în jurnal"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animație dezactivată"</item>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index c76faf02e19c..a666da042bfb 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Atingeţi pentru a modifica sau pentru a elimina parola pentru copiile de rezervă complete pe desktop"</string>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
index c8c789eb1e17..78965acc1fb3 100644
--- a/packages/SettingsLib/res/values-ru/arrays.xml
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Всегда использовать проверку HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 КБ"</item>
- <item msgid="505611754508988476">"256 КБ"</item>
- <item msgid="6361286924268716397">"1 МБ"</item>
- <item msgid="6405203239560695266">"4 МБ"</item>
- <item msgid="3025431211013424097">"16 МБ"</item>
+ <item msgid="8665206199209698501">"Выкл."</item>
+ <item msgid="1593289376502312923">"64 КБ"</item>
+ <item msgid="487545340236145324">"256 КБ"</item>
+ <item msgid="2423528675294333831">"1 МБ"</item>
+ <item msgid="180883774509476541">"4 МБ"</item>
+ <item msgid="2803199102589126938">"16 МБ"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 КБ"</item>
- <item msgid="3534782711045262344">"256 КБ"</item>
- <item msgid="8085867209202153403">"1 МБ"</item>
+ <item msgid="6089470720451068364">"Выкл."</item>
+ <item msgid="4622460333038586791">"64 КБ"</item>
+ <item msgid="2212125625169582330">"256 КБ"</item>
+ <item msgid="1704946766699242653">"1 МБ"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Буфер: макс. 64 КБ"</item>
- <item msgid="2822309747675758628">"Буфер: макс. 256 КБ"</item>
- <item msgid="6699306198357496731">"Буфер: макс. 1 МБ"</item>
- <item msgid="5748528643937500349">"Буфер: макс. 4 МБ"</item>
- <item msgid="1978629051085111592">"Буфер: макс. 16 МБ"</item>
+ <item msgid="6921048829791179331">"Выкл."</item>
+ <item msgid="2969458029344750262">"Буфер: макс. 64 КБ"</item>
+ <item msgid="1342285115665698168">"Буфер: макс. 256 КБ"</item>
+ <item msgid="1314234299552254621">"Буфер: макс. 1 МБ"</item>
+ <item msgid="3606047780792894151">"Буфер: макс. 4 МБ"</item>
+ <item msgid="5431354956856655120">"Буфер: макс. 16 МБ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Без анимации"</item>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index f1cd18254dbf..e93bae13bc98 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Пароль для резервного копирования"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Полные резервные копии в настоящее время не защищены"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Изменить или удалить пароль для резервного копирования"</string>
diff --git a/packages/SettingsLib/res/values-si-rLK/arrays.xml b/packages/SettingsLib/res/values-si-rLK/arrays.xml
index 564ecee0b2f4..ab30e458b364 100644
--- a/packages/SettingsLib/res/values-si-rLK/arrays.xml
+++ b/packages/SettingsLib/res/values-si-rLK/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"සැමවිටම HDCP පිරික්සුම භාවිතා කරන්න"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ක්‍රියාවිරහිතය"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ක්‍රියාවිරහිතය"</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="7346595473588765019">"ලොග අන්තරාවකට 64K"</item>
- <item msgid="2822309747675758628">"ලොග අන්තරාවකට 256K"</item>
- <item msgid="6699306198357496731">"ලොග අන්තරාවකට 1M"</item>
- <item msgid="5748528643937500349">"ලොග අන්තරාවකට 4M"</item>
- <item msgid="1978629051085111592">"ලොග අන්තරාවකට 16M"</item>
+ <item msgid="6921048829791179331">"ක්‍රියාවිරහිතය"</item>
+ <item msgid="2969458029344750262">"ලොග අන්තරාවකට 64K"</item>
+ <item msgid="1342285115665698168">"ලොග අන්තරාවකට 256K"</item>
+ <item msgid="1314234299552254621">"ලොග අන්තරාවකට 1M"</item>
+ <item msgid="3606047780792894151">"ලොග අන්තරාවකට 4M"</item>
+ <item msgid="5431354956856655120">"ලොග අන්තරාවකට 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"සජිවිකරණය අක්‍රිය කිරීම"</item>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index eb13ce498437..6753624a9bba 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"ඩෙස්ක්ටොප් උපස්ථ මුරපදය"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ දැනට ආරක්ෂා කර නොමැත"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ සඳහා මුරපදය වෙනස් කිරීමට හෝ ඉවත් කිරීමට ස්පර්ශ කරන්න"</string>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
index ec33e632e893..9a56e7807700 100644
--- a/packages/SettingsLib/res/values-sk/arrays.xml
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Vždy používať kontrolu HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Vypnuté"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Vypnuté"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB na vyrovn. pamäť denníka"</item>
- <item msgid="2822309747675758628">"256 kB na vyrovn. pamäť denníka"</item>
- <item msgid="6699306198357496731">"1 MB na vyrovn. pamäť denníka"</item>
- <item msgid="5748528643937500349">"4 MB na vyrovn. pamäť denníka"</item>
- <item msgid="1978629051085111592">"16 MB na vyrovn. pamäť denníka"</item>
+ <item msgid="6921048829791179331">"Vypnuté"</item>
+ <item msgid="2969458029344750262">"64 kB na vyrov. pamäť denníka"</item>
+ <item msgid="1342285115665698168">"256 kB na vyrov. pamäť denníka"</item>
+ <item msgid="1314234299552254621">"1 MB na vyrov. pam. denníka"</item>
+ <item msgid="3606047780792894151">"4 MB na vyrov. pamäť denníka"</item>
+ <item msgid="5431354956856655120">"16 MB na vyrov. pamäť denníka"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animácia je vypnutá"</item>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index b5b6d2a2b303..7db7835eda8e 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Dotykom zmeníte alebo odstránite heslo pre úplné zálohy do počítača"</string>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index 253f11360e20..11b2babbfadb 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Vedno uporabi preverjanje HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Izklopljeno"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Izklopljeno"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/medpom. dnevn."</item>
- <item msgid="2822309747675758628">"256 K/medpom. dnev."</item>
- <item msgid="6699306198357496731">"1 M/medpom. dnevn."</item>
- <item msgid="5748528643937500349">"4 M/medpom. dnevn."</item>
- <item msgid="1978629051085111592">"16 M/medpom. dnevn."</item>
+ <item msgid="6921048829791179331">"Izklopljeno"</item>
+ <item msgid="2969458029344750262">"64 K/medpomnilnik dnevnika"</item>
+ <item msgid="1342285115665698168">"256 K/medpomnilnik dnevnika"</item>
+ <item msgid="1314234299552254621">"1 M/medpomnilnik dnevnika"</item>
+ <item msgid="3606047780792894151">"4 M/medpomnilnik dnevnika"</item>
+ <item msgid="5431354956856655120">"16 M/medpomnilnik dnevnika"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija je izključena"</item>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index cb107d7e58a9..ed37933daff3 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Dotaknite se, če želite spremeniti ali odstraniti geslo za popolno varnostno kopiranje namizja."</string>
diff --git a/packages/SettingsLib/res/values-sq-rAL/arrays.xml b/packages/SettingsLib/res/values-sq-rAL/arrays.xml
index 7473f16625d4..0f0efb8d4259 100644
--- a/packages/SettingsLib/res/values-sq-rAL/arrays.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Përdor gjithmonë kontrollin e HDCP-së"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Joaktiv"</item>
+ <item msgid="1593289376502312923">"64 mijë"</item>
+ <item msgid="487545340236145324">"256 mijë"</item>
+ <item msgid="2423528675294333831">"1 milion"</item>
+ <item msgid="180883774509476541">"4 milionë"</item>
+ <item msgid="2803199102589126938">"16 milionë"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Joaktiv"</item>
+ <item msgid="4622460333038586791">"64 mijë"</item>
+ <item msgid="2212125625169582330">"256 mijë"</item>
+ <item msgid="1704946766699242653">"1 milion"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 mijë / memorie regjistrimi"</item>
- <item msgid="2822309747675758628">"256K për çdo memorie të përkohshme"</item>
- <item msgid="6699306198357496731">"1 M për memorien e regjistrit"</item>
- <item msgid="5748528643937500349">"4 M për memorien e regjistrit"</item>
- <item msgid="1978629051085111592">"16 M për memorien e regjistrit"</item>
+ <item msgid="6921048829791179331">"Joaktiv"</item>
+ <item msgid="2969458029344750262">"64 mijë/memorie regjistrimi"</item>
+ <item msgid="1342285115665698168">"256 mijë/memorie regjistrimi"</item>
+ <item msgid="1314234299552254621">"1 milion/memorie regjistrimi"</item>
+ <item msgid="3606047780792894151">"4 milionë/memorie regjistrimi"</item>
+ <item msgid="5431354956856655120">"16 milionë/memorie regjistrimi"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacioni është i çaktivizuar"</item>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index c176f18aa579..7f4d6a864af9 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -247,6 +247,8 @@
<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="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="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>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Prek për të ndryshuar ose hequr fjalëkalimin për rezervime të plota të desktopit"</string>
diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml
index cd44e15e79c2..2389339f9e24 100644
--- a/packages/SettingsLib/res/values-sr/arrays.xml
+++ b/packages/SettingsLib/res/values-sr/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Увек користи HDCP проверу"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Искључено"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Искључено"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB по баферу евиденције"</item>
- <item msgid="2822309747675758628">"256 kB по баферу евиденције"</item>
- <item msgid="6699306198357496731">"1 MB по баферу евиденције"</item>
- <item msgid="5748528643937500349">"4 MB по баферу евиденције"</item>
- <item msgid="1978629051085111592">"16 MB по баферу евиденције"</item>
+ <item msgid="6921048829791179331">"Искључено"</item>
+ <item msgid="2969458029344750262">"64 kB по међумеморији евиденције"</item>
+ <item msgid="1342285115665698168">"256 kB по међумеморији евиденције"</item>
+ <item msgid="1314234299552254621">"1 MB по међумеморији евиденције"</item>
+ <item msgid="3606047780792894151">"4 MB по међумеморији евиденције"</item>
+ <item msgid="5431354956856655120">"16 MB по међумеморији евиденције"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анимација је искључена"</item>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 6b6609493d55..9596ce5e1caf 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Лозинка резервне копије за рачунар"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Резервне копије читавог система тренутно нису заштићене"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Додирните да бисте променили или уклонили лозинку за прављење резервних копија читавог система на рачунару"</string>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index 54537f46977e..cbc7dde1cdb5 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Använd alltid HDCP-kontroll"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Av"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Av"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB/loggbuffert"</item>
- <item msgid="2822309747675758628">"256 kB/loggbuffert"</item>
- <item msgid="6699306198357496731">"1 MB/loggbuffert"</item>
- <item msgid="5748528643937500349">"4 MB/loggbuffert"</item>
- <item msgid="1978629051085111592">"16 MB/loggbuffert"</item>
+ <item msgid="6921048829791179331">"Av"</item>
+ <item msgid="2969458029344750262">"64 kB/loggbuffert"</item>
+ <item msgid="1342285115665698168">"256 kB/loggbuffert"</item>
+ <item msgid="1314234299552254621">"1 MB/loggbuffert"</item>
+ <item msgid="3606047780792894151">"4 MB/loggbuffert"</item>
+ <item msgid="5431354956856655120">"16 MB/loggbuffert"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animering avstängd"</item>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 40e1593250be..7d0d0a08b0e9 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Tryck om du vill ändra eller ta bort lösenordet för fullständig säkerhetskopiering av datorn"</string>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index 450e385c0a86..8593fd52971b 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Kila wakati tumia ukakuaji wa HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"K64"</item>
- <item msgid="505611754508988476">"K256"</item>
- <item msgid="6361286924268716397">"M1"</item>
- <item msgid="6405203239560695266">"M4"</item>
- <item msgid="3025431211013424097">"M16"</item>
+ <item msgid="8665206199209698501">"Imezimwa"</item>
+ <item msgid="1593289376502312923">"K64"</item>
+ <item msgid="487545340236145324">"K256"</item>
+ <item msgid="2423528675294333831">"M1"</item>
+ <item msgid="180883774509476541">"M4"</item>
+ <item msgid="2803199102589126938">"M16"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"K64"</item>
- <item msgid="3534782711045262344">"K256"</item>
- <item msgid="8085867209202153403">"M1"</item>
+ <item msgid="6089470720451068364">"Imezimwa"</item>
+ <item msgid="4622460333038586791">"K64"</item>
+ <item msgid="2212125625169582330">"K256"</item>
+ <item msgid="1704946766699242653">"M1"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"K64 kwa kumbukumbu"</item>
- <item msgid="2822309747675758628">"K256 kwa kumbukumbu"</item>
- <item msgid="6699306198357496731">"M1 kwa kumbukumbu"</item>
- <item msgid="5748528643937500349">"M4 kwa kumbukumbu"</item>
- <item msgid="1978629051085111592">"M16 kwa kumbukumbu"</item>
+ <item msgid="6921048829791179331">"Imezimwa"</item>
+ <item msgid="2969458029344750262">"K64 kwa kila akiba ya kumbukumbu"</item>
+ <item msgid="1342285115665698168">"K256 kwa kila akiba ya kumbukumbu"</item>
+ <item msgid="1314234299552254621">"M1 kwa kila akiba ya kumbukumbu"</item>
+ <item msgid="3606047780792894151">"M4 kwa kila akiba ya kumbukumbu"</item>
+ <item msgid="5431354956856655120">"M16 kwa kila akiba ya kumbukumbu"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Haiwani imezimwa"</item>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index a014e1d43536..d1041da0db20 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Gusa ili ubadilishe au uondoe nenosiri la hifadhi rudufu kamili za eneo kazi"</string>
diff --git a/packages/SettingsLib/res/values-ta-rIN/arrays.xml b/packages/SettingsLib/res/values-ta-rIN/arrays.xml
index ad421595f93c..18deff36cc2d 100644
--- a/packages/SettingsLib/res/values-ta-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP சரிபார்ப்பை எப்போதும் பயன்படுத்து"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"முடக்கு"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"முடக்கு"</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="7346595473588765019">"64K / லாக் பஃபர்"</item>
- <item msgid="2822309747675758628">"256K / லாக் பஃபர்"</item>
- <item msgid="6699306198357496731">"1M / லாக் பஃபர்"</item>
- <item msgid="5748528643937500349">"4M / லாக் பஃபர்"</item>
- <item msgid="1978629051085111592">"16M / லாக் பஃபர்"</item>
+ <item msgid="6921048829791179331">"முடக்கத்தில்"</item>
+ <item msgid="2969458029344750262">"64K / லாக் பஃபர்"</item>
+ <item msgid="1342285115665698168">"256K / லாக் பஃபர்"</item>
+ <item msgid="1314234299552254621">"1M / லாக் பஃபர்"</item>
+ <item msgid="3606047780792894151">"4M / லாக் பஃபர்"</item>
+ <item msgid="5431354956856655120">"16M / லாக் பஃபர்"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"அனிமேஷனை முடக்கு"</item>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index 4f6ea57d6a48..e66f07325677 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"டெஸ்க்டாப் காப்புப்பிரதி கடவுச்சொல்"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"டெஸ்க்டாப்பின் முழு காப்புப்பிரதிகள் தற்போது பாதுகாக்கப்படவில்லை"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"டெஸ்க்டாப்பின் முழுமையான காப்புப்பிரதிகளுக்கான கடவுச்சொல்லை மாற்றுவதற்கு அல்லது அகற்றுவதற்குத் தொடவும்"</string>
diff --git a/packages/SettingsLib/res/values-te-rIN/arrays.xml b/packages/SettingsLib/res/values-te-rIN/arrays.xml
index 9287aba3fe27..3ba0dc7f155d 100644
--- a/packages/SettingsLib/res/values-te-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-te-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ఎప్పటికీ HDCP తనిఖీని ఉపయోగించు"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ఆఫ్"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ఆఫ్"</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="7346595473588765019">"లాగ్ బఫర్‌కి 64K"</item>
- <item msgid="2822309747675758628">"లాగ్ బఫర్‌కి 256K"</item>
- <item msgid="6699306198357496731">"లాగ్ బఫర్‌కి 1M"</item>
- <item msgid="5748528643937500349">"లాగ్ బఫర్‌కి 4M"</item>
- <item msgid="1978629051085111592">"లాగ్ బఫర్‌కి 16M"</item>
+ <item msgid="6921048829791179331">"ఆఫ్ చేయబడింది"</item>
+ <item msgid="2969458029344750262">"లాగ్ బఫర్‌కి 64K"</item>
+ <item msgid="1342285115665698168">"లాగ్ బఫర్‌కి 256K"</item>
+ <item msgid="1314234299552254621">"లాగ్ బఫర్‌కి 1M"</item>
+ <item msgid="3606047780792894151">"లాగ్ బఫర్‌కి 4M"</item>
+ <item msgid="5431354956856655120">"లాగ్ బఫర్‌కి 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"యానిమేషన్ ఆఫ్‌లో ఉంది"</item>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index a6d2140313e8..80b84f06cc09 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"స్వతంత్ర రూప విండోలను ప్రారంభించండి"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ప్రయోగాత్మక స్వతంత్ర రూప విండోలకు మద్దతును ప్రారంభిస్తుంది."</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="2731163425081172638">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌ల కోసం పాస్‌వర్డ్‌ను మార్చడానికి లేదా తీసివేయడానికి తాకండి"</string>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index 43d273970e59..4282975b2cba 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ใช้การตรวจสอบ HDCP เสมอ"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"ปิด"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"ปิด"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
- <item msgid="2822309747675758628">"256 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
- <item msgid="6699306198357496731">"1 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
- <item msgid="5748528643937500349">"4 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
- <item msgid="1978629051085111592">"16 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+ <item msgid="6921048829791179331">"ปิด"</item>
+ <item msgid="2969458029344750262">"64 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+ <item msgid="1342285115665698168">"256 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+ <item msgid="1314234299552254621">"1 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+ <item msgid="3606047780792894151">"4 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+ <item msgid="5431354956856655120">"16 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ปิดภาพเคลื่อนไหว"</item>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index de2f33dbe377..6826419ce278 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"รหัสผ่านการสำรองข้อมูลในเดสก์ท็อป"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"การสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป ไม่ได้รับการป้องกันในขณะนี้"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"แตะเพื่อเปลี่ยนหรือลบรหัสผ่านสำหรับการสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป"</string>
diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml
index c7cf6d24f6be..a7fb68c16c3c 100644
--- a/packages/SettingsLib/res/values-tl/arrays.xml
+++ b/packages/SettingsLib/res/values-tl/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Palaging gumamit ng pagsusuring HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"I-off"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"I-off"</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="7346595473588765019">"64K kada log buffer"</item>
- <item msgid="2822309747675758628">"256K kada log buffer"</item>
- <item msgid="6699306198357496731">"1M kada log buffer"</item>
- <item msgid="5748528643937500349">"4M kada log buffer"</item>
- <item msgid="1978629051085111592">"16M kada log buffer"</item>
+ <item msgid="6921048829791179331">"I-off"</item>
+ <item msgid="2969458029344750262">"64K kada log buffer"</item>
+ <item msgid="1342285115665698168">"256K kada log buffer"</item>
+ <item msgid="1314234299552254621">"1M kada log buffer"</item>
+ <item msgid="3606047780792894151">"4M kada log buffer"</item>
+ <item msgid="5431354956856655120">"16M kada log buffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Naka-off ang animation"</item>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 231079b92e7b..8f623268e23e 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Pindutin upang baguhin o alisin ang password para sa mga buong pag-backup ng desktop"</string>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
index 9326903e9955..0bae437549ab 100644
--- a/packages/SettingsLib/res/values-tr/arrays.xml
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP denetimini her zaman kullan"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Kapalı"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Kapalı"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Günlük arabelleği başına 64 KB"</item>
- <item msgid="2822309747675758628">"Günlük arabelleği başına 256 KB"</item>
- <item msgid="6699306198357496731">"Günlük arabelleği başına 1 MB"</item>
- <item msgid="5748528643937500349">"Günlük arabelleği başına 4 MB"</item>
- <item msgid="1978629051085111592">"Günlük arabelleği başına 16 MB"</item>
+ <item msgid="6921048829791179331">"Kapalı"</item>
+ <item msgid="2969458029344750262">"Günlük arabelleği başına 64 KB"</item>
+ <item msgid="1342285115665698168">"Günlük arabelleği başına 256 KB"</item>
+ <item msgid="1314234299552254621">"Günlük arabelleği başına 1 MB"</item>
+ <item msgid="3606047780792894151">"Günlük arabelleği başına 4 MB"</item>
+ <item msgid="5431354956856655120">"Günlük arabelleği başına 16 MB"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasyon kapalı"</item>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index c44d7f8ee574..5e0839a6db10 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Masaüstü yedekleme şifresi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam yedeklemeleri şu an korunmuyor"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Masaüstü tam yedeklemelerinin şifresini değiştirmek veya kaldırmak için dokunun"</string>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
index 6cccc8c122e3..0786ac368e6f 100644
--- a/packages/SettingsLib/res/values-uk/arrays.xml
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Завжди використовувати перевірку HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 Кб"</item>
- <item msgid="505611754508988476">"256 Кб"</item>
- <item msgid="6361286924268716397">"1 Мб"</item>
- <item msgid="6405203239560695266">"4 Мб"</item>
- <item msgid="3025431211013424097">"16 Мб"</item>
+ <item msgid="8665206199209698501">"Вимкнено"</item>
+ <item msgid="1593289376502312923">"64 Кб"</item>
+ <item msgid="487545340236145324">"256 Кб"</item>
+ <item msgid="2423528675294333831">"1 Мб"</item>
+ <item msgid="180883774509476541">"4 Мб"</item>
+ <item msgid="2803199102589126938">"16 Мб"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 Кб"</item>
- <item msgid="3534782711045262344">"256 Кб"</item>
- <item msgid="8085867209202153403">"1 Мб"</item>
+ <item msgid="6089470720451068364">"Вимкнено"</item>
+ <item msgid="4622460333038586791">"64 Кб"</item>
+ <item msgid="2212125625169582330">"256 Кб"</item>
+ <item msgid="1704946766699242653">"1 Мб"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Буфер: макс. 64 Кб"</item>
- <item msgid="2822309747675758628">"Буфер: макс. 256 Кб"</item>
- <item msgid="6699306198357496731">"Буфер: макс. 1 Мб"</item>
- <item msgid="5748528643937500349">"Буфер: макс. 4 Мб"</item>
- <item msgid="1978629051085111592">"Буфер: макс. 16 Мб"</item>
+ <item msgid="6921048829791179331">"Вимкнено"</item>
+ <item msgid="2969458029344750262">"Буфер журналу: 64 Кб"</item>
+ <item msgid="1342285115665698168">"Буфер журналу: 256 Кб"</item>
+ <item msgid="1314234299552254621">"Буфер журналу: 1 Мб"</item>
+ <item msgid="3606047780792894151">"Буфер журналу: 4 Мб"</item>
+ <item msgid="5431354956856655120">"Буфер журналу: 16 Мб"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анімацію вимкнено"</item>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index d5dbe902aaa4..2448b2326ae7 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -247,6 +247,8 @@
<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="enable_freeform_support" msgid="1461893351278940416">"Увімкнути вікна довільного формату"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Увімкнуться експериментальні вікна довільного формату."</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="2731163425081172638">"Торкніться, щоб змінити чи видалити пароль для повного резервного копіювання на комп’ютер"</string>
diff --git a/packages/SettingsLib/res/values-ur-rPK/arrays.xml b/packages/SettingsLib/res/values-ur-rPK/arrays.xml
index 80fb750461db..e1fe2699b9a2 100644
--- a/packages/SettingsLib/res/values-ur-rPK/arrays.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"‏ہمیشہ HDCP چیکنگ استعمال کریں"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"آف"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"آف"</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="7346595473588765019">"‏64K فی لاگ بفر"</item>
- <item msgid="2822309747675758628">"‏256K فی لاگ بفر"</item>
- <item msgid="6699306198357496731">"‏1M فی لاگ بفر"</item>
- <item msgid="5748528643937500349">"‏4M فی لاگ بفر"</item>
- <item msgid="1978629051085111592">"‏16M فی لاگ بفر"</item>
+ <item msgid="6921048829791179331">"آف"</item>
+ <item msgid="2969458029344750262">"‏64K فی لاگ بفر"</item>
+ <item msgid="1342285115665698168">"‏256K فی لاگ بفر"</item>
+ <item msgid="1314234299552254621">"‏1M فی لاگ بفر"</item>
+ <item msgid="3606047780792894151">"‏4M فی لاگ بفر"</item>
+ <item msgid="5431354956856655120">"‏16M فی لاگ بفر"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"اینیمیشن آف ہے"</item>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index 4c9c17850409..0834303fb310 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"ڈیسک ٹاپ کا بیک اپ پاس ورڈ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ڈیسک ٹاپ کے مکمل بیک اپس فی الحال محفوظ کیے ہوئے نہیں ہیں"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ڈیسک ٹاپ کے مکمل بیک اپس کیلئے پاس ورڈ کو تبدیل کرنے یا ہٹانے کیلئے ٹچ کریں"</string>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/arrays.xml b/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
index a84c5d52d4ef..53d4db7d54b3 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Har doim HDCP tekshiruvidan foydalanilsin"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"O‘chiq"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"O‘chiq"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Bufer: maks. 64 KB"</item>
- <item msgid="2822309747675758628">"Bufer: maks. 256 KB"</item>
- <item msgid="6699306198357496731">"Bufer: maks. 1 MB"</item>
- <item msgid="5748528643937500349">"Bufer: maks. 4 MB"</item>
- <item msgid="1978629051085111592">"Bufer: maks. 16 MB"</item>
+ <item msgid="6921048829791179331">"O‘chiq"</item>
+ <item msgid="2969458029344750262">"Bufer: maks. 64 KB"</item>
+ <item msgid="1342285115665698168">"Bufer: maks. 256 KB"</item>
+ <item msgid="1314234299552254621">"Bufer: maks. 1 MB"</item>
+ <item msgid="3606047780792894151">"Bufer: maks. 4 MB"</item>
+ <item msgid="5431354956856655120">"Bufer: maks. 16 MB"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animatsiya o‘chiq"</item>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index d138a284b81d..d2d8b76670dc 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"Zaxira nusxa uchun parol"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kompyuterdagi zaxira nusxalar hozirgi vaqtda himoyalanmagan"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Ish stoli to\'liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing."</string>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index 7c3181fcb5df..b03d847fe6bb 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Luôn sử dụng kiểm tra HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Tắt"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Tắt"</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="7346595473588765019">"64K/lần tải nhật ký"</item>
- <item msgid="2822309747675758628">"256K/lần tải nhật ký"</item>
- <item msgid="6699306198357496731">"1M/lần tải nhật ký"</item>
- <item msgid="5748528643937500349">"4M/lần tải nhật ký"</item>
- <item msgid="1978629051085111592">"16M/lần tải nhật ký"</item>
+ <item msgid="6921048829791179331">"Tắt"</item>
+ <item msgid="2969458029344750262">"64K/lần tải nhật ký"</item>
+ <item msgid="1342285115665698168">"256K/lần tải nhật ký"</item>
+ <item msgid="1314234299552254621">"1M/lần tải nhật ký"</item>
+ <item msgid="3606047780792894151">"4M/lần tải nhật ký"</item>
+ <item msgid="5431354956856655120">"16M/lần tải nhật ký"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Tắt hình động"</item>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 7ab8b0226226..178e301636cc 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"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="2731163425081172638">"Chạm để thay đổi hoặc xóa mật khẩu dành cho bộ sao lưu toàn bộ tới máy tính"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 1378aaa1c5bc..d1d8937ab7cd 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"始终使用 HDCP 检查"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"关闭"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"关闭"</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="7346595473588765019">"每个日志缓冲区64K"</item>
- <item msgid="2822309747675758628">"每个日志缓冲区256K"</item>
- <item msgid="6699306198357496731">"每个日志缓冲区1M"</item>
- <item msgid="5748528643937500349">"每个日志缓冲区4M"</item>
- <item msgid="1978629051085111592">"每个日志缓冲区16M"</item>
+ <item msgid="6921048829791179331">"关闭"</item>
+ <item msgid="2969458029344750262">"每个日志缓冲区 64K"</item>
+ <item msgid="1342285115665698168">"每个日志缓冲区 256K"</item>
+ <item msgid="1314234299552254621">"每个日志缓冲区 1M"</item>
+ <item msgid="3606047780792894151">"每个日志缓冲区 4M"</item>
+ <item msgid="5431354956856655120">"每个日志缓冲区 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"关闭动画"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 509ff88de7d1..5b963832a61a 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"桌面备份密码"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌面完整备份当前未设置密码保护"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"触摸可更改或删除用于桌面完整备份的密码"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
index f15caff0cf56..a7b0031560fa 100644
--- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"永遠使用 HDCP 檢查"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"關閉"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"關閉"</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="7346595473588765019">"每個記錄緩衝區 64K"</item>
- <item msgid="2822309747675758628">"每個記錄緩衝區 256K"</item>
- <item msgid="6699306198357496731">"每個記錄緩衝區 1M"</item>
- <item msgid="5748528643937500349">"每個記錄緩衝區 4M"</item>
- <item msgid="1978629051085111592">"每個記錄緩衝區 16M"</item>
+ <item msgid="6921048829791179331">"關閉"</item>
+ <item msgid="2969458029344750262">"每個記錄緩衝區 64K"</item>
+ <item msgid="1342285115665698168">"每個記錄緩衝區 256K"</item>
+ <item msgid="1314234299552254621">"每個記錄緩衝區 1M"</item>
+ <item msgid="3606047780792894151">"每個記錄緩衝區 4M"</item>
+ <item msgid="5431354956856655120">"每個記錄緩衝區 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"關閉動畫"</item>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index f323667d67c3..db5f09b42068 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"桌面電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌上電腦的完整備份目前未受保護"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"輕觸即可更改或移除桌上電腦完整備份的密碼"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index 50bde80c2fd5..32a206536e62 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"一律使用 HDCP 檢查"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"關閉"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"關閉"</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="7346595473588765019">"每個紀錄緩衝區 64K"</item>
- <item msgid="2822309747675758628">"每個紀錄緩衝區 256K"</item>
- <item msgid="6699306198357496731">"每個紀錄緩衝區 1M"</item>
- <item msgid="5748528643937500349">"每個紀錄緩衝區 4M"</item>
- <item msgid="1978629051085111592">"每個紀錄緩衝區 16M"</item>
+ <item msgid="6921048829791179331">"關閉"</item>
+ <item msgid="2969458029344750262">"每個紀錄緩衝區 64K"</item>
+ <item msgid="1342285115665698168">"每個紀錄緩衝區 256K"</item>
+ <item msgid="1314234299552254621">"每個紀錄緩衝區 1M"</item>
+ <item msgid="3606047780792894151">"每個紀錄緩衝區 4M"</item>
+ <item msgid="5431354956856655120">"每個紀錄緩衝區 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"關閉動畫"</item>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index c6ad832ca826..787a44218917 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -247,6 +247,10 @@
<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>
+ <!-- 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">"電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"電腦完整備份目前未受保護"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"輕觸即可變更或移除電腦完整備份的密碼"</string>
diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml
index eaadce62e197..2bb849ff8496 100644
--- a/packages/SettingsLib/res/values-zu/arrays.xml
+++ b/packages/SettingsLib/res/values-zu/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Sebenzisa njalo ukuhlola kwe-HDPC"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Valiwe"</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="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Valiwe"</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="7346595473588765019">"64K ngebhafa yelogu ngayinye"</item>
- <item msgid="2822309747675758628">"256K ngebhafa yelogu ngayinye"</item>
- <item msgid="6699306198357496731">"1M ngebhafa yelogu ngayinye"</item>
- <item msgid="5748528643937500349">"4M ngebhafa yelogu ngayinye"</item>
- <item msgid="1978629051085111592">"16M ngebhafa yelogu ngayinye"</item>
+ <item msgid="6921048829791179331">"Valiwe"</item>
+ <item msgid="2969458029344750262">"64K ngebhafa yelogu ngayinye"</item>
+ <item msgid="1342285115665698168">"256K ngebhafa yelogu ngayinye"</item>
+ <item msgid="1314234299552254621">"1M ngebhafa yelogu ngayi"</item>
+ <item msgid="3606047780792894151">"4M ngebhafa yelogu ngayinye"</item>
+ <item msgid="5431354956856655120">"16M ngebhafa yelogu ngayinye"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Isithombe esinyakazayo sivliwe"</item>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index cb3670f06863..bf3addfa3327 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -247,6 +247,8 @@
<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="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="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>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Khetha ukushintsha noma ukususa iphasiwedi yokwenziwa kwezipele ngokugcwele kwideskithophu"</string>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 4e88c1c092a4..1bce7f9ac3ae 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -102,6 +102,7 @@
<!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
<string-array name="select_logd_size_titles">
+ <item>Off</item>
<item>64K</item>
<item>256K</item>
<item>1M</item>
@@ -111,6 +112,7 @@
<!-- Titles for logd limit size lowram selection preference. [CHAR LIMIT=14] -->
<string-array name="select_logd_size_lowram_titles">
+ <item>Off</item>
<item>64K</item>
<item>256K</item>
<item>1M</item>
@@ -118,6 +120,7 @@
<!-- Values for logd limit size selection preference. -->
<string-array name="select_logd_size_values" translatable="false" >
+ <item>32768</item>
<item>65536</item>
<item>262144</item>
<item>1048576</item>
@@ -125,8 +128,9 @@
<item>16777216</item>
</string-array>
- <!-- Summaries for logd limit size selection preference. [CHAR LIMIT=30]-->
+ <!-- Summaries for logd limit size selection preference. [CHAR LIMIT=50]-->
<string-array name="select_logd_size_summaries" >
+ <item>Off</item>
<item>64K per log buffer</item>
<item>256K per log buffer</item>
<item>1M per log buffer</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 7e2288133ab3..f7e25dbe5f6e 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -624,6 +624,11 @@
<!-- 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>
+ <!-- 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>
+
<!-- Local (desktop) backup password menu title [CHAR LIMIT=25] -->
<string name="local_backup_password_title">Desktop backup password</string>
<!-- Summary text of the "local backup password" setting when the user has not supplied a password -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index 344bf6228bf2..f6d9134c5e2b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -38,7 +38,7 @@ public class AppUtils {
String packageName = appEntry.info.packageName;
boolean hasPreferred = hasPreferredActivities(pm, packageName)
|| hasUsbDefaults(usbManager, packageName);
- int status = pm.getIntentVerificationStatus(packageName, UserHandle.myUserId());
+ int status = pm.getIntentVerificationStatusAsUser(packageName, UserHandle.myUserId());
// consider a visible current link-handling state to be any explicitly designated behavior
boolean hasDomainURLsPreference =
status != PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index e6fe447c8d98..d353f31e59b1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -316,7 +316,7 @@ public class ApplicationsState {
synchronized (mEntriesMap) {
AppEntry entry = mEntriesMap.get(userId).get(packageName);
if (entry != null) {
- mPm.getPackageSizeInfo(packageName, userId, mBackgroundHandler.mStatsObserver);
+ mPm.getPackageSizeInfoAsUser(packageName, userId, mBackgroundHandler.mStatsObserver);
}
if (DEBUG_LOCKING) Log.v(TAG, "...requestSize releasing lock");
}
@@ -906,7 +906,7 @@ public class ApplicationsState {
entry.sizeLoadStart = now;
mCurComputingSizePkg = entry.info.packageName;
mCurComputingSizeUserId = UserHandle.getUserId(entry.info.uid);
- mPm.getPackageSizeInfo(mCurComputingSizePkg,
+ mPm.getPackageSizeInfoAsUser(mCurComputingSizePkg,
mCurComputingSizeUserId, mStatsObserver);
}
if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES releasing: now computing");
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index 9790e6408cc2..3b818c851626 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -422,7 +422,7 @@ public class StorageMeasurement {
ActivityManager.getCurrentUser(), currentProfiles, finished, count);
for (UserInfo user : users) {
for (ApplicationInfo app : volumeApps) {
- packageManager.getPackageSizeInfo(app.packageName, user.id, observer);
+ packageManager.getPackageSizeInfoAsUser(app.packageName, user.id, observer);
}
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 1c4c0123e601..c6d9e98774d0 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -108,6 +108,7 @@
<uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
<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" />
<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 e01252ee7537..247ccfc3bd63 100644
--- a/packages/Shell/res/values-af/strings.xml
+++ b/packages/Shell/res/values-af/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Foutverslaglêer kon nie gelees word nie"</string>
<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_failed" msgid="5853049140806834601">"Kon nie skermkiekie neem nie."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Foutverslagbesonderhede"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Kort naam"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-reëlopsomming"</string>
diff --git a/packages/Shell/res/values-am/strings.xml b/packages/Shell/res/values-am/strings.xml
index a1c926d9a584..9f3615a1cc9b 100644
--- a/packages/Shell/res/values-am/strings.xml
+++ b/packages/Shell/res/values-am/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"የሳንካ ሪፖርት ፋይል ሊነበብ አልተቻለም"</string>
<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_failed" msgid="5853049140806834601">"ቅጽበታዊ ገጽ እይታ ሊነሳ አይችልም"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"የሳንካ ሪፖርት ዝርዝሮች"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"አጭር ስም"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"የ1 መስመር ማጠቃለያ"</string>
diff --git a/packages/Shell/res/values-ar/strings.xml b/packages/Shell/res/values-ar/strings.xml
index 069e5cae3120..b670e373e46a 100644
--- a/packages/Shell/res/values-ar/strings.xml
+++ b/packages/Shell/res/values-ar/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"تعذرت قراءة ملف تقرير الخطأ."</string>
<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_failed" msgid="5853049140806834601">"تعذر التقاط لقطة الشاشة."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"تفاصيل تقرير الخطأ"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"اسم مختصر"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"سطر الملخص الأول"</string>
diff --git a/packages/Shell/res/values-az-rAZ/strings.xml b/packages/Shell/res/values-az-rAZ/strings.xml
index b289776ce049..634d12338e07 100644
--- a/packages/Shell/res/values-az-rAZ/strings.xml
+++ b/packages/Shell/res/values-az-rAZ/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Baq hesabat faylı oxunmur"</string>
<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_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_name" msgid="5089191832271852826">"Qısa ad"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-sətrlik xülasə"</string>
diff --git a/packages/Shell/res/values-b+sr+Latn/strings.xml b/packages/Shell/res/values-b+sr+Latn/strings.xml
index dac1b7ab2921..41acb89ca455 100644
--- a/packages/Shell/res/values-b+sr+Latn/strings.xml
+++ b/packages/Shell/res/values-b+sr+Latn/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Datoteka izveštaja o grešci ne može da se pročita"</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">"Snimci ekrana"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snimanje ekrana je uspelo."</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_name" msgid="5089191832271852826">"Kratki naziv"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Rezime u jednom redu"</string>
diff --git a/packages/Shell/res/values-bg/strings.xml b/packages/Shell/res/values-bg/strings.xml
index 376360b0b409..661a0b65fc47 100644
--- a/packages/Shell/res/values-bg/strings.xml
+++ b/packages/Shell/res/values-bg/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Файлът със сигнал за програмна грешка не можа да бъде прочетен"</string>
<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_failed" msgid="5853049140806834601">"Екранната снимка не можа да бъде направена."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Подробности за сигнала за програмна грешка"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Кратко име"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Едноредово обобщение"</string>
diff --git a/packages/Shell/res/values-bn-rBD/strings.xml b/packages/Shell/res/values-bn-rBD/strings.xml
index 96098f22341b..e7256caef00a 100644
--- a/packages/Shell/res/values-bn-rBD/strings.xml
+++ b/packages/Shell/res/values-bn-rBD/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ত্রুটির প্রতিবেদনের ফাইলটি পড়া যায়নি"</string>
<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_failed" msgid="5853049140806834601">"স্ক্রীনশট নেওয়া যায়নি৷"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ত্রুটি প্রতিবেদনের বিবরণ"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"ছোট নাম"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"১-লাইনের সারসংক্ষেপ"</string>
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index e82f319e7b2b..a8c95536d599 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"No s\'ha pogut llegir el fitxer de l\'informe d\'errors"</string>
<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_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_name" msgid="5089191832271852826">"Nom curt"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Resum d\'una línia"</string>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index fc3c9b6d11d4..193501e27350 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Soubor chybové zprávy nelze načíst"</string>
<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_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_name" msgid="5089191832271852826">"Krátký název"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Shrnutí na jeden řádek"</string>
diff --git a/packages/Shell/res/values-da/strings.xml b/packages/Shell/res/values-da/strings.xml
index ec64efa10124..39758004c6ba 100644
--- a/packages/Shell/res/values-da/strings.xml
+++ b/packages/Shell/res/values-da/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Fejlrapportfilen kunne ikke læses"</string>
<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_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_name" msgid="5089191832271852826">"Kort navn"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Sammenfatning på én linje"</string>
diff --git a/packages/Shell/res/values-de/strings.xml b/packages/Shell/res/values-de/strings.xml
index d65d8cbfcbcd..b0450ddb34db 100644
--- a/packages/Shell/res/values-de/strings.xml
+++ b/packages/Shell/res/values-de/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Fehlerberichtdatei konnte nicht gelesen werden."</string>
<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_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_name" msgid="5089191832271852826">"Kurzname"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Zusammenfassung in einer Zeile"</string>
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
index 504944431cf7..ec5f3ac761e8 100644
--- a/packages/Shell/res/values-el/strings.xml
+++ b/packages/Shell/res/values-el/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Δεν ήταν δυνατή η ανάγνωση του αρχείου της αναφοράς σφαλμάτων"</string>
<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_failed" msgid="5853049140806834601">"Δεν ήταν δυνατή η λήψη του στιγμιότυπου οθόνης."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Λεπτομέρειες αναφοράς σφαλμάτων"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Υποκοριστικό"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Σύνοψη μίας σειράς"</string>
diff --git a/packages/Shell/res/values-en-rAU/strings.xml b/packages/Shell/res/values-en-rAU/strings.xml
index ee1ae6fecc3a..26a3d382b180 100644
--- a/packages/Shell/res/values-en-rAU/strings.xml
+++ b/packages/Shell/res/values-en-rAU/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Bug report file could not be read"</string>
<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_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_name" msgid="5089191832271852826">"Short name"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-line summary"</string>
diff --git a/packages/Shell/res/values-en-rGB/strings.xml b/packages/Shell/res/values-en-rGB/strings.xml
index ee1ae6fecc3a..26a3d382b180 100644
--- a/packages/Shell/res/values-en-rGB/strings.xml
+++ b/packages/Shell/res/values-en-rGB/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Bug report file could not be read"</string>
<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_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_name" msgid="5089191832271852826">"Short name"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-line summary"</string>
diff --git a/packages/Shell/res/values-en-rIN/strings.xml b/packages/Shell/res/values-en-rIN/strings.xml
index ee1ae6fecc3a..26a3d382b180 100644
--- a/packages/Shell/res/values-en-rIN/strings.xml
+++ b/packages/Shell/res/values-en-rIN/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Bug report file could not be read"</string>
<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_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_name" msgid="5089191832271852826">"Short name"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-line summary"</string>
diff --git a/packages/Shell/res/values-es-rUS/strings.xml b/packages/Shell/res/values-es-rUS/strings.xml
index 23704df8f07f..7f70feb1a83b 100644
--- a/packages/Shell/res/values-es-rUS/strings.xml
+++ b/packages/Shell/res/values-es-rUS/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"No se pudo leer el archivo de informe de errores"</string>
<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_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_name" msgid="5089191832271852826">"Nombre corto"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Resumen de una línea"</string>
diff --git a/packages/Shell/res/values-es/strings.xml b/packages/Shell/res/values-es/strings.xml
index fbaeab4b79e5..df080d23a4e1 100644
--- a/packages/Shell/res/values-es/strings.xml
+++ b/packages/Shell/res/values-es/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"No se ha podido leer el archivo del informe de errores"</string>
<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_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_name" msgid="5089191832271852826">"Nombre corto"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Resumen de 1 línea"</string>
diff --git a/packages/Shell/res/values-et-rEE/strings.xml b/packages/Shell/res/values-et-rEE/strings.xml
index 3b4aead6e409..94b4b89f46b8 100644
--- a/packages/Shell/res/values-et-rEE/strings.xml
+++ b/packages/Shell/res/values-et-rEE/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Veaaruande faili ei õnnestunud lugeda"</string>
<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_failed" msgid="5853049140806834601">"Ekraanipilti ei saanud teha."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Veaaruande üksikasjad"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Lühike nimi"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-realine kokkuvõte"</string>
diff --git a/packages/Shell/res/values-eu-rES/strings.xml b/packages/Shell/res/values-eu-rES/strings.xml
index 8852f9bca62a..cad55fc65498 100644
--- a/packages/Shell/res/values-eu-rES/strings.xml
+++ b/packages/Shell/res/values-eu-rES/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Ezin izan da irakurri akatsen txostena"</string>
<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_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_name" msgid="5089191832271852826">"Izen laburra"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Lerro bakarreko laburpena"</string>
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
index 73e91486ca7b..b619f105f7d7 100644
--- a/packages/Shell/res/values-fa/strings.xml
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"فایل گزارش اشکال خوانده نشد"</string>
<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_failed" msgid="5853049140806834601">"نمی‌توان عکس صفحه‌نمایش گرفت."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"جزئیات گزارش اشکال"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"نام مخفف"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"خلاصه یک خطی"</string>
diff --git a/packages/Shell/res/values-fi/strings.xml b/packages/Shell/res/values-fi/strings.xml
index 5376b8003493..a90ffb554f47 100644
--- a/packages/Shell/res/values-fi/strings.xml
+++ b/packages/Shell/res/values-fi/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Virheraporttitiedostoa ei voi lukea."</string>
<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_failed" msgid="5853049140806834601">"Kuvakaappauksen tallentaminen epäonnistui."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Virheraportin tiedot"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Lyhyt nimi"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Lyhyt tiivistelmä"</string>
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
index 7a986b4ae161..52be99db58ca 100644
--- a/packages/Shell/res/values-fr-rCA/strings.xml
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Impossible de lire le fichier du rapport de bogue"</string>
<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_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_name" msgid="5089191832271852826">"Nom abrégé"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Résumé d\'une ligne"</string>
diff --git a/packages/Shell/res/values-fr/strings.xml b/packages/Shell/res/values-fr/strings.xml
index 8446f6fdf080..e10e28e05a5b 100644
--- a/packages/Shell/res/values-fr/strings.xml
+++ b/packages/Shell/res/values-fr/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Impossible de lire le fichier de rapport de bug."</string>
<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_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_name" msgid="5089191832271852826">"Nom court"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Résumé d\'une ligne"</string>
diff --git a/packages/Shell/res/values-gl-rES/strings.xml b/packages/Shell/res/values-gl-rES/strings.xml
index 2a1a93b2d00f..20f8cdaab157 100644
--- a/packages/Shell/res/values-gl-rES/strings.xml
+++ b/packages/Shell/res/values-gl-rES/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Non se puido ler o ficheiro de informe de erros"</string>
<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_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_name" msgid="5089191832271852826">"Nome abreviado"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Resumo de 1 liña"</string>
diff --git a/packages/Shell/res/values-gu-rIN/strings.xml b/packages/Shell/res/values-gu-rIN/strings.xml
index f525b65d29f1..967d255126bc 100644
--- a/packages/Shell/res/values-gu-rIN/strings.xml
+++ b/packages/Shell/res/values-gu-rIN/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"બગ રીપોર્ટ ફાઇલ વાંચી શકાઇ નથી"</string>
<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_failed" msgid="5853049140806834601">"સ્ક્રીનશોટ લઇ શકાયો નથી."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"બગ રિપોર્ટની વિગતો"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"નાનું નામ"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-રેખાનો સારાંશ"</string>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index 26f975719024..70e4f38b8f44 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"बग रिपोर्ट फ़ाइल नहीं पढ़ी जा सकी"</string>
<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_failed" msgid="5853049140806834601">"स्क्रीनशॉट नहीं लिया जा सका."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"बग रिपोर्ट के विवरण"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"संक्षिप्त नाम"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-पंक्ति में सारांश"</string>
diff --git a/packages/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
index 606f46bced90..f38a281af377 100644
--- a/packages/Shell/res/values-hr/strings.xml
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Izvješće o programskoj pogrešci nije pročitano"</string>
<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_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_name" msgid="5089191832271852826">"Kratko ime"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Sažetak u jednom retku"</string>
diff --git a/packages/Shell/res/values-hu/strings.xml b/packages/Shell/res/values-hu/strings.xml
index 521c87c3321a..544c11773443 100644
--- a/packages/Shell/res/values-hu/strings.xml
+++ b/packages/Shell/res/values-hu/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"A hibajelentési fájlt nem sikerült beolvasni"</string>
<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_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_name" msgid="5089191832271852826">"Rövid név"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Egysoros összefoglalás"</string>
diff --git a/packages/Shell/res/values-hy-rAM/strings.xml b/packages/Shell/res/values-hy-rAM/strings.xml
index 2c0fe234e621..625994d89085 100644
--- a/packages/Shell/res/values-hy-rAM/strings.xml
+++ b/packages/Shell/res/values-hy-rAM/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Հնարավոր չէ կարդալ վրիպակների զեկույցի ֆայլը"</string>
<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_failed" msgid="5853049140806834601">"Չհաջողվեց ստանալ էկրանի պատկերը:"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Վրիպակի զեկույցի մանրամասները"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Կրճատ անուն"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Ամփոփագիր մեկ տողով"</string>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
index 928629486cba..747fecddaf6a 100644
--- a/packages/Shell/res/values-in/strings.xml
+++ b/packages/Shell/res/values-in/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"File laporan bug tidak dapat dibaca"</string>
<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_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_name" msgid="5089191832271852826">"Nama pendek"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Ringkasan 1 baris"</string>
diff --git a/packages/Shell/res/values-is-rIS/strings.xml b/packages/Shell/res/values-is-rIS/strings.xml
index 62f630245435..d0d3e6043c3a 100644
--- a/packages/Shell/res/values-is-rIS/strings.xml
+++ b/packages/Shell/res/values-is-rIS/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Ekki var hægt að lesa úr villuskýrslunni"</string>
<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_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_name" msgid="5089191832271852826">"Stutt heiti"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Einnar línu samantekt"</string>
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index cee41b6dc5e7..0511c5850f2d 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Impossibile leggere il file relativo alla segnalazione di bug"</string>
<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_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_name" msgid="5089191832271852826">"Nome breve"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Sintesi su una riga"</string>
diff --git a/packages/Shell/res/values-iw/strings.xml b/packages/Shell/res/values-iw/strings.xml
index 906e233f0322..b9bcaf986f87 100644
--- a/packages/Shell/res/values-iw/strings.xml
+++ b/packages/Shell/res/values-iw/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"לא ניתן היה לקרוא את קובץ הדוח על הבאג"</string>
<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_failed" msgid="5853049140806834601">"לא ניתן היה לצלם מסך."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"פרטי דוח על באג"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"כינוי"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"סיכום בשורה אחת"</string>
diff --git a/packages/Shell/res/values-ja/strings.xml b/packages/Shell/res/values-ja/strings.xml
index 2facb57d308c..05b95eb4e261 100644
--- a/packages/Shell/res/values-ja/strings.xml
+++ b/packages/Shell/res/values-ja/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"バグレポート ファイルを読み取ることができませんでした"</string>
<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_failed" msgid="5853049140806834601">"スクリーンショットを撮影できませんでした。"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"バグレポートの詳細"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"省略名"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1 行の概要"</string>
diff --git a/packages/Shell/res/values-ka-rGE/strings.xml b/packages/Shell/res/values-ka-rGE/strings.xml
index 7c67cc5fda3a..2cfd80accd4f 100644
--- a/packages/Shell/res/values-ka-rGE/strings.xml
+++ b/packages/Shell/res/values-ka-rGE/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ხარვეზების შესახებ ანგარიშის წაკითხვა ვერ მოხერხდა"</string>
<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_failed" msgid="5853049140806834601">"ეკრანის ანაბეჭდის გადაღება ვერ მოხერხდა."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ხარვეზის შესახებ ანგარიშის დეტალები"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"მოკლე სახელი"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-ხაზიანი რეზიუმე"</string>
diff --git a/packages/Shell/res/values-kk-rKZ/strings.xml b/packages/Shell/res/values-kk-rKZ/strings.xml
index 73092a6972f1..2829b9b2a449 100644
--- a/packages/Shell/res/values-kk-rKZ/strings.xml
+++ b/packages/Shell/res/values-kk-rKZ/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Қате туралы есеп файлын оқу мүмкін болмады"</string>
<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_failed" msgid="5853049140806834601">"Скриншот түсіру мүмкін болмады."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Қате туралы есептің мәліметтері"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Қысқа аты"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1 жолдық жиынтық мәліметтер"</string>
diff --git a/packages/Shell/res/values-km-rKH/strings.xml b/packages/Shell/res/values-km-rKH/strings.xml
index d4dd08d5d113..3573588b1277 100644
--- a/packages/Shell/res/values-km-rKH/strings.xml
+++ b/packages/Shell/res/values-km-rKH/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"មិនអាចអានឯកសាររបាយកាណ៍កំហុសបានទេ"</string>
<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_failed" msgid="5853049140806834601">"មិនអាចថតរូបថតអេក្រង់បានទេ"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ព័ត៌មានលម្អិតពីរបាយការណ៍កំហុស"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"ឈ្មោះ​ខ្លី"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"ការសង្ខេបមួយជួរ"</string>
diff --git a/packages/Shell/res/values-kn-rIN/strings.xml b/packages/Shell/res/values-kn-rIN/strings.xml
index 27e858211950..70712644840c 100644
--- a/packages/Shell/res/values-kn-rIN/strings.xml
+++ b/packages/Shell/res/values-kn-rIN/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ಬಗ್‌ ವರದಿ ಫೈಲ್‌‌ ಅನ್ನು ಓದಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
<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_failed" msgid="5853049140806834601">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ತೆಗೆದುಕೊಳ್ಳಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ಬಗ್ ವರದಿ ವಿವರಗಳು"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"ಚಿಕ್ಕ ಹೆಸರು"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-ಸಾಲಿನ ಸಾರಾಂಶ"</string>
diff --git a/packages/Shell/res/values-ko/strings.xml b/packages/Shell/res/values-ko/strings.xml
index 7e978e0f522b..4e3c3f446eb5 100644
--- a/packages/Shell/res/values-ko/strings.xml
+++ b/packages/Shell/res/values-ko/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"버그 신고 파일을 읽을 수 없습니다."</string>
<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_failed" msgid="5853049140806834601">"스크린샷을 찍을 수 없습니다."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"버그 신고 세부정보"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"짧은 이름"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"한 줄 요약"</string>
diff --git a/packages/Shell/res/values-ky-rKG/strings.xml b/packages/Shell/res/values-ky-rKG/strings.xml
index f2a688b2d255..051be3833833 100644
--- a/packages/Shell/res/values-ky-rKG/strings.xml
+++ b/packages/Shell/res/values-ky-rKG/strings.xml
@@ -27,8 +27,11 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Мүчүлүштүк тууралуу кабарлаган файл окулбай койду"</string>
<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_failed" msgid="5853049140806834601">"Скриншот тартылбай койду."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Мүчүлүштүктөр жөнүндө кабардын чоо-жайы"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Кыска аталышы"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1 саптык корутунду"</string>
- <string name="bugreport_info_description" msgid="4117088998733546784">"Кенен сүрөттөмөсү"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Кененирээк маалымат"</string>
</resources>
diff --git a/packages/Shell/res/values-lo-rLA/strings.xml b/packages/Shell/res/values-lo-rLA/strings.xml
index e3b66dfa800e..a04a35563e45 100644
--- a/packages/Shell/res/values-lo-rLA/strings.xml
+++ b/packages/Shell/res/values-lo-rLA/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ບໍ່ສາມາດອ່ານໄຟລ໌ລາຍງານຂໍ້ຜິດພາດໄດ້"</string>
<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_failed" msgid="5853049140806834601">"ບໍ່ສາມາດຖ່າຍພາບໜ້າຈໍໄດ້."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ລາຍ​ລະ​ອຽດ​ການລາຍງານບັນຫາ"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"ຊື່ສັ້ນ"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"ສະຫຼຸບ 1 ແຖວ"</string>
diff --git a/packages/Shell/res/values-lt/strings.xml b/packages/Shell/res/values-lt/strings.xml
index a8f0f2bfc750..8d8d31e58a65 100644
--- a/packages/Shell/res/values-lt/strings.xml
+++ b/packages/Shell/res/values-lt/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Nepavyko sukurti pranešimo apie riktą failo"</string>
<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_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_name" msgid="5089191832271852826">"Trumpasis pavadinimas"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1 eilutės suvestinė"</string>
diff --git a/packages/Shell/res/values-lv/strings.xml b/packages/Shell/res/values-lv/strings.xml
index 87380b122524..dba1ad322f4e 100644
--- a/packages/Shell/res/values-lv/strings.xml
+++ b/packages/Shell/res/values-lv/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Nevarēja nolasīt kļūdas pārskata failu."</string>
<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_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_name" msgid="5089191832271852826">"Saīsināts nosaukums"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Kopsavilkums 1 rindiņā"</string>
diff --git a/packages/Shell/res/values-mk-rMK/strings.xml b/packages/Shell/res/values-mk-rMK/strings.xml
index 25fdf1fff0cc..6e23ad8395bc 100644
--- a/packages/Shell/res/values-mk-rMK/strings.xml
+++ b/packages/Shell/res/values-mk-rMK/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Датотеката со извештај за грешка не можеше да се прочита"</string>
<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_failed" msgid="5853049140806834601">"Не може да се направи слика од екранот."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детали на извештајот за грешка"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Кратко име"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Резиме во 1 ред"</string>
diff --git a/packages/Shell/res/values-ml-rIN/strings.xml b/packages/Shell/res/values-ml-rIN/strings.xml
index 8a29f69ac6ea..73a4fff0eb7c 100644
--- a/packages/Shell/res/values-ml-rIN/strings.xml
+++ b/packages/Shell/res/values-ml-rIN/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ബഗ് റിപ്പോർട്ട് ഫയൽ വായിക്കാനായില്ല"</string>
<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_failed" msgid="5853049140806834601">"സ്ക്രീൻഷോട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ബഗ് റിപ്പോർട്ട് വിശദാംശങ്ങൾ"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"ഹ്രസ്വ നാമം"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"ഒരു വരി സംഗ്രഹം"</string>
diff --git a/packages/Shell/res/values-mn-rMN/strings.xml b/packages/Shell/res/values-mn-rMN/strings.xml
index 2a9127670ea5..1f4be4ab5845 100644
--- a/packages/Shell/res/values-mn-rMN/strings.xml
+++ b/packages/Shell/res/values-mn-rMN/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Алдааны тайлангийн файлыг уншиж чадахгүй байна"</string>
<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_failed" msgid="5853049140806834601">"Дэлгэцийн зураг авах боломжгүй."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Алдааны дэлгэрэнгүй тайлан"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Богино нэр"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-р шугамын хураангуй"</string>
diff --git a/packages/Shell/res/values-mr-rIN/strings.xml b/packages/Shell/res/values-mr-rIN/strings.xml
index 476a8870774e..6b06cf5fcd5d 100644
--- a/packages/Shell/res/values-mr-rIN/strings.xml
+++ b/packages/Shell/res/values-mr-rIN/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"दोष अहवाल फाईल वाचणे शक्य झाले नाही"</string>
<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_failed" msgid="5853049140806834601">"स्क्रीनशॉट घेणे शक्य झाले नाही."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"दोष अहवाल तपशील"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"लघु नाव"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-ओळीचा सारांश"</string>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
index c7cf3ac7fcc2..e22f880b60df 100644
--- a/packages/Shell/res/values-ms-rMY/strings.xml
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Fail laporan pepijat tidak dapat dibaca"</string>
<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_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_name" msgid="5089191832271852826">"Nama pendek"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Ringkasan 1 baris"</string>
diff --git a/packages/Shell/res/values-my-rMM/strings.xml b/packages/Shell/res/values-my-rMM/strings.xml
index e525cc4de216..727cdc9c33bc 100644
--- a/packages/Shell/res/values-my-rMM/strings.xml
+++ b/packages/Shell/res/values-my-rMM/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ချွတ်ယွင်းချက် အစီရင်ခံစာကို ဖတ်၍မရပါ"</string>
<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_failed" msgid="5853049140806834601">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံ မရိုက်နိုင်ပါ"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ချွတ်ယွင်းချက်အစီရင်ခံစာ အသေးစိတ်များ"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"အမည်အတိုကောက်"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"လိုင်း ၁ လိုင်းအကျဉ်းချုပ်"</string>
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index 2f04d32be7ef..c7702ef8af4a 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Feilrapportfilen kunne ikke leses"</string>
<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_failed" msgid="5853049140806834601">"Skjermdumpen kunne ikke tas."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detaljer om feilrapporten"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Kallenavn"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Sammendrag på én linje"</string>
diff --git a/packages/Shell/res/values-ne-rNP/strings.xml b/packages/Shell/res/values-ne-rNP/strings.xml
index 74e472af37da..732f39851fd2 100644
--- a/packages/Shell/res/values-ne-rNP/strings.xml
+++ b/packages/Shell/res/values-ne-rNP/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"बग रिपोर्ट फाइल पढ्न सकिएन"</string>
<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_failed" msgid="5853049140806834601">"स्क्रिनशट लिन सकिएन।"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"बग रिपोर्टको विवरण"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"छोटो नाम"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"१ लाइनको सारांश"</string>
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
index f5ac17b0a3ea..0378ca4ae1e3 100644
--- a/packages/Shell/res/values-nl/strings.xml
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Bestand met bugrapport kan niet worden gelezen"</string>
<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_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_name" msgid="5089191832271852826">"Korte naam"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Samenvatting van één regel"</string>
diff --git a/packages/Shell/res/values-pa-rIN/strings.xml b/packages/Shell/res/values-pa-rIN/strings.xml
index 89d6c608cf0d..720bde04c744 100644
--- a/packages/Shell/res/values-pa-rIN/strings.xml
+++ b/packages/Shell/res/values-pa-rIN/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ਬਗ ਰਿਪੋਰਟ ਫ਼ਾਈਲ ਪੜ੍ਹੀ ਨਹੀਂ ਜਾ ਸਕੀ"</string>
<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_failed" msgid="5853049140806834601">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨਹੀਂ ਲਿਆ ਜਾ ਸਕਿਆ।"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ਬੱਗ ਰਿਪੋਰਟ ਵੇਰਵੇ"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"ਛੋਟਾ ਨਾਮ"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-ਲਾਈਨ ਸਾਰਾਂਸ਼"</string>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index 9498428b76c7..d6715a52f4bd 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Nie można odczytać raportu o błędzie"</string>
<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_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_name" msgid="5089191832271852826">"Krótka nazwa"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Jednowierszowe podsumowanie"</string>
diff --git a/packages/Shell/res/values-pt-rBR/strings.xml b/packages/Shell/res/values-pt-rBR/strings.xml
index d588ef7186ec..fb16dd8c9c68 100644
--- a/packages/Shell/res/values-pt-rBR/strings.xml
+++ b/packages/Shell/res/values-pt-rBR/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Não foi possível ler o arquivo de relatório de bug"</string>
<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_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_name" msgid="5089191832271852826">"Apelido"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Resumo de uma linha"</string>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
index c0472d0e671b..07d319ec76cd 100644
--- a/packages/Shell/res/values-pt-rPT/strings.xml
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Não foi possível ler o ficheiro de relatório de erro"</string>
<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_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_name" msgid="5089191832271852826">"Nome abreviado"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Resumo de 1 linha"</string>
diff --git a/packages/Shell/res/values-pt/strings.xml b/packages/Shell/res/values-pt/strings.xml
index d588ef7186ec..fb16dd8c9c68 100644
--- a/packages/Shell/res/values-pt/strings.xml
+++ b/packages/Shell/res/values-pt/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Não foi possível ler o arquivo de relatório de bug"</string>
<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_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_name" msgid="5089191832271852826">"Apelido"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Resumo de uma linha"</string>
diff --git a/packages/Shell/res/values-ro/strings.xml b/packages/Shell/res/values-ro/strings.xml
index 40eac80f62f3..064dfaf7e648 100644
--- a/packages/Shell/res/values-ro/strings.xml
+++ b/packages/Shell/res/values-ro/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Fișierul cu raportul de eroare nu a putut fi citit"</string>
<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_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_name" msgid="5089191832271852826">"Nume scurt"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Rezumat de un rând"</string>
diff --git a/packages/Shell/res/values-ru/strings.xml b/packages/Shell/res/values-ru/strings.xml
index fd9fdf33da33..3350740cb670 100644
--- a/packages/Shell/res/values-ru/strings.xml
+++ b/packages/Shell/res/values-ru/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Не удалось открыть отчет об ошибке"</string>
<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_failed" msgid="5853049140806834601">"Не удалось сделать скриншот"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детали отчета об ошибке"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Краткое название"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Краткое описание ошибки"</string>
diff --git a/packages/Shell/res/values-si-rLK/strings.xml b/packages/Shell/res/values-si-rLK/strings.xml
index 83f04fb5b5da..d915109283ad 100644
--- a/packages/Shell/res/values-si-rLK/strings.xml
+++ b/packages/Shell/res/values-si-rLK/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"දෝෂ වාර්තා ගොනුව කියවීමට නොහැකි විය"</string>
<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_failed" msgid="5853049140806834601">"තිර රුවක් ගත නොහැකි විය."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"දෝෂ වාර්තා විස්තර"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"කෙටි නම"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"පේළි-1 සාරාංශය"</string>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index 46a6cea654a2..ec9003d88bbe 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Súbor s hlásením chyby sa nepodarilo prečítať"</string>
<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_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_name" msgid="5089191832271852826">"Skrátený názov"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Jednoriadkové zhrnutie"</string>
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index fb28bd21cf70..aa66ce94b8d4 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Datoteke s poročilom o napakah ni bilo mogoče prebrati"</string>
<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_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_name" msgid="5089191832271852826">"Ime"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Enovrstični povzetek"</string>
diff --git a/packages/Shell/res/values-sq-rAL/strings.xml b/packages/Shell/res/values-sq-rAL/strings.xml
index e5c42c6284d2..dd13f34a46fa 100644
--- a/packages/Shell/res/values-sq-rAL/strings.xml
+++ b/packages/Shell/res/values-sq-rAL/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Skedari i raportimit të defektit në kod nuk mund të lexohej."</string>
<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_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_name" msgid="5089191832271852826">"Emri shkurt"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Përmbledhje me 1 rresht"</string>
diff --git a/packages/Shell/res/values-sr/strings.xml b/packages/Shell/res/values-sr/strings.xml
index e46430e83219..1da7ecb03665 100644
--- a/packages/Shell/res/values-sr/strings.xml
+++ b/packages/Shell/res/values-sr/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Датотека извештаја о грешци не може да се прочита"</string>
<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_failed" msgid="5853049140806834601">"Снимање екрана није успело."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детаљи извештаја о грешци"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Кратки назив"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Резиме у једном реду"</string>
diff --git a/packages/Shell/res/values-sv/strings.xml b/packages/Shell/res/values-sv/strings.xml
index 6b600ebf23e6..8afa0a535114 100644
--- a/packages/Shell/res/values-sv/strings.xml
+++ b/packages/Shell/res/values-sv/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Det gick inte att läsa felrapporten"</string>
<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_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_name" msgid="5089191832271852826">"Kortnamn"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Sammanfattning på en rad"</string>
diff --git a/packages/Shell/res/values-sw/strings.xml b/packages/Shell/res/values-sw/strings.xml
index 2096b3649550..5b7026247abe 100644
--- a/packages/Shell/res/values-sw/strings.xml
+++ b/packages/Shell/res/values-sw/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Faili ya ripoti ya hitilafu haikusomwa"</string>
<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_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_name" msgid="5089191832271852826">"Jina fupi"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Muhtasari wa mstari mmoja"</string>
diff --git a/packages/Shell/res/values-ta-rIN/strings.xml b/packages/Shell/res/values-ta-rIN/strings.xml
index ae97cfe50527..91eb718e09c1 100644
--- a/packages/Shell/res/values-ta-rIN/strings.xml
+++ b/packages/Shell/res/values-ta-rIN/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"பிழை அறிக்கையைப் படிக்க முடியவில்லை"</string>
<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_failed" msgid="5853049140806834601">"ஸ்கிரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"பிழை அறிக்கை விவரங்கள்"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"சுருக்கப் பெயர்"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"சுருக்கவிவரம் (ஒரு வரியில்)"</string>
diff --git a/packages/Shell/res/values-te-rIN/strings.xml b/packages/Shell/res/values-te-rIN/strings.xml
index 7dd344c31e77..517dd5e8b2c1 100644
--- a/packages/Shell/res/values-te-rIN/strings.xml
+++ b/packages/Shell/res/values-te-rIN/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"బగ్ నివేదిక ఫైల్‌ను చదవడం సాధ్యపడలేదు"</string>
<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_failed" msgid="5853049140806834601">"స్క్రీన్‌షాట్‌ను తీయడం సాధ్యపడలేదు."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"బగ్ నివేదిక వివరాలు"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"చిన్న పేరు"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1-పంక్తి సారాంశం"</string>
diff --git a/packages/Shell/res/values-th/strings.xml b/packages/Shell/res/values-th/strings.xml
index af3fa3e64aab..b7340955dc7c 100644
--- a/packages/Shell/res/values-th/strings.xml
+++ b/packages/Shell/res/values-th/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ไม่สามารถอ่านไฟล์รายงานข้อบกพร่อง"</string>
<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_failed" msgid="5853049140806834601">"ไม่สามารถจับภาพหน้าจอได้"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"รายละเอียดรายงานข้อบกพร่อง"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"ชื่อย่อ"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"สรุป 1 บรรทัด"</string>
diff --git a/packages/Shell/res/values-tl/strings.xml b/packages/Shell/res/values-tl/strings.xml
index e93e399f69a4..bcce1db30ecd 100644
--- a/packages/Shell/res/values-tl/strings.xml
+++ b/packages/Shell/res/values-tl/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Hindi mabasa ang file ng pag-uulat ng bug"</string>
<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_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_name" msgid="5089191832271852826">"Maikling pangalan"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Buod na may 1 linya"</string>
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index 7ea3c77b6d2f..e1fdf10f966d 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Hata raporu dosyası okunamadı"</string>
<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_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_name" msgid="5089191832271852826">"Kısa ad"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1 satırlık özet"</string>
diff --git a/packages/Shell/res/values-uk/strings.xml b/packages/Shell/res/values-uk/strings.xml
index 4127deb9657f..dd43c4c32173 100644
--- a/packages/Shell/res/values-uk/strings.xml
+++ b/packages/Shell/res/values-uk/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Не вдалося прочитати звіт про помилки"</string>
<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_failed" msgid="5853049140806834601">"Не вдалося зробити знімок екрана."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Деталі повідомлення про помилку"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Коротка назва"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Підсумок одним рядком"</string>
diff --git a/packages/Shell/res/values-ur-rPK/strings.xml b/packages/Shell/res/values-ur-rPK/strings.xml
index d8cb00b7a2c6..b97c8b5fc66f 100644
--- a/packages/Shell/res/values-ur-rPK/strings.xml
+++ b/packages/Shell/res/values-ur-rPK/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"بگ رپورٹ فائل پڑھی نہیں جا سکی"</string>
<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_failed" msgid="5853049140806834601">"سکرین شاٹ نہیں لیا جا سکا۔"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"بگ رپورٹ کی تفصیلات"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"مختصر نام"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"1 لائن کا خلاصہ"</string>
diff --git a/packages/Shell/res/values-uz-rUZ/strings.xml b/packages/Shell/res/values-uz-rUZ/strings.xml
index 8e1f24f2c519..279c876dfedc 100644
--- a/packages/Shell/res/values-uz-rUZ/strings.xml
+++ b/packages/Shell/res/values-uz-rUZ/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Xatoliklar hisoboti faylini o‘qib bo‘lmadi"</string>
<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_failed" msgid="5853049140806834601">"Skrinshot olib bo‘lmadi."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Xatoliklar hisoboti tafsilotlari"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Qisqa nomi"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Xatolikning qisqacha ta’rifi"</string>
diff --git a/packages/Shell/res/values-vi/strings.xml b/packages/Shell/res/values-vi/strings.xml
index 03d40cf7e235..4e1ebc7d9df2 100644
--- a/packages/Shell/res/values-vi/strings.xml
+++ b/packages/Shell/res/values-vi/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Không thể đọc tệp báo cáo lỗi"</string>
<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_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_name" msgid="5089191832271852826">"Tên ngắn"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Tóm tắt 1 dòng"</string>
diff --git a/packages/Shell/res/values-zh-rCN/strings.xml b/packages/Shell/res/values-zh-rCN/strings.xml
index 130a0ade2743..b5ba7a927c52 100644
--- a/packages/Shell/res/values-zh-rCN/strings.xml
+++ b/packages/Shell/res/values-zh-rCN/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"无法读取错误报告文件"</string>
<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_failed" msgid="5853049140806834601">"无法截图。"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"错误报告详细信息"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"简称"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"简短摘要(1 行)"</string>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
index b4345f6201b0..896a920f2bb3 100644
--- a/packages/Shell/res/values-zh-rHK/strings.xml
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"無法讀取錯誤報告檔案"</string>
<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_failed" msgid="5853049140806834601">"無法擷取螢幕畫面。"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"錯誤報告詳情"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"簡稱"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"簡短摘要 (1 行)"</string>
diff --git a/packages/Shell/res/values-zh-rTW/strings.xml b/packages/Shell/res/values-zh-rTW/strings.xml
index 6b89ad9bd560..2bdf56186a05 100644
--- a/packages/Shell/res/values-zh-rTW/strings.xml
+++ b/packages/Shell/res/values-zh-rTW/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"無法讀取錯誤報告檔案"</string>
<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_failed" msgid="5853049140806834601">"無法拍攝螢幕擷取畫面。"</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"錯誤報告詳細資料"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"簡稱"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"簡短摘要"</string>
diff --git a/packages/Shell/res/values-zu/strings.xml b/packages/Shell/res/values-zu/strings.xml
index f30c4f6aecfe..652105a9659e 100644
--- a/packages/Shell/res/values-zu/strings.xml
+++ b/packages/Shell/res/values-zu/strings.xml
@@ -27,6 +27,9 @@
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Ifayela lombiko wesiphazamso alikwazanga ukufundwa"</string>
<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_failed" msgid="5853049140806834601">"Isithombe-skrini asikwazanga ukuthathwa."</string>
<string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Imininingwane yombiko wesiphazamisi"</string>
<string name="bugreport_info_name" msgid="5089191832271852826">"Igama elifishane"</string>
<string name="bugreport_info_title" msgid="127167853370557175">"Isifinyezo somugqa ongu-1"</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index d31088ce308c..f7a2d75a216f 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -449,6 +449,11 @@ public class BugreportProgressService extends Service {
.addAction(cancelAction)
.build();
+ if (info.finished) {
+ Log.w(TAG, "Not sending progress notification because bugreport has finished already ("
+ + info + ")");
+ return;
+ }
NotificationManager.from(mContext).notify(TAG, info.pid, notification);
}
@@ -628,7 +633,12 @@ public class BugreportProgressService extends Service {
synchronized (BugreportProgressService.this) {
mTakingScreenshot = flag;
for (int i = 0; i < mProcesses.size(); i++) {
- updateProgress(mProcesses.valueAt(i));
+ final BugreportInfo info = mProcesses.valueAt(i);
+ if (info.finished) {
+ Log.d(TAG, "Not updating progress because share notification was already sent");
+ continue;
+ }
+ updateProgress(info);
}
}
}
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 6bee767e4706..8e8924ae6bf3 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -142,6 +142,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
public void testProgress() throws Exception {
resetProperties();
sendBugreportStarted(1000);
+ waitForScreenshotButtonEnabled(true);
assertProgressNotification(NAME, "0.00%");
@@ -157,7 +158,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
Bundle extras =
sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, ZIP_FILE,
- null, 1);
+ null, 1, true);
assertServiceNotRunning();
}
@@ -174,7 +175,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
Bundle extras =
sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, ZIP_FILE,
- null, 2);
+ null, 2, true);
assertServiceNotRunning();
}
@@ -182,6 +183,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
public void testProgress_changeDetails() throws Exception {
resetProperties();
sendBugreportStarted(1000);
+ waitForScreenshotButtonEnabled(true);
DetailsUi detailsUi = new DetailsUi(mUiBot);
@@ -218,14 +220,33 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath,
mScreenshotPath);
assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NEW_NAME, TITLE,
- mDescription, 1);
+ mDescription, 1, true);
assertServiceNotRunning();
}
+ /**
+ * Tests the scenario where the initial screenshot and dumpstate are finished while the user
+ * is changing the info in the details screen.
+ */
+ public void testProgress_bugreportAndScreenshotFinishedWhileChangingDetails() throws Exception {
+ bugreportFinishedWhileChangingDetailsTest(false);
+ }
+
+ /**
+ * Tests the scenario where dumpstate is finished while the user is changing the info in the
+ * details screen, but the initial screenshot finishes afterwards.
+ */
public void testProgress_bugreportFinishedWhileChangingDetails() throws Exception {
+ bugreportFinishedWhileChangingDetailsTest(true);
+ }
+
+ private void bugreportFinishedWhileChangingDetailsTest(boolean waitScreenshot) throws Exception {
resetProperties();
sendBugreportStarted(1000);
+ if (waitScreenshot) {
+ waitForScreenshotButtonEnabled(true);
+ }
DetailsUi detailsUi = new DetailsUi(mUiBot);
@@ -233,7 +254,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
detailsUi.nameField.setText(NEW_NAME);
sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath);
- // Wait until the share notifcation is received...
+ // Wait until the share notification is received...
mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title));
// ...then close notification bar.
mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
@@ -250,7 +271,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
// Finally, share bugreport.
Bundle extras = acceptBugreportAndGetSharedIntent();
assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, TITLE,
- mDescription, 1);
+ mDescription, 1, waitScreenshot);
assertServiceNotRunning();
}
@@ -406,7 +427,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
private void assertActionSendMultiple(Bundle extras, String bugreportContent,
String screenshotContent) throws IOException {
assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, null, ZIP_FILE,
- null, 0);
+ null, 0, false);
}
/**
@@ -420,10 +441,11 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
* @param title bugreport name as provided by the user (or received by dumpstate)
* @param description bugreport description as provided by the user
* @param numberScreenshots expected number of screenshots taken by Shell.
+ * @param renamedScreenshots whether the screenshots are expected to be renamed
*/
private void assertActionSendMultiple(Bundle extras, String bugreportContent,
String screenshotContent, int pid, String name, String title, String description,
- int numberScreenshots) throws IOException {
+ int numberScreenshots, boolean renamedScreenshots) throws IOException {
String body = extras.getString(Intent.EXTRA_TEXT);
assertContainsRegex("missing build info",
SystemProperties.get("ro.build.description"), body);
@@ -480,7 +502,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
// Check internal screenshots.
SortedSet<String> expectedNames = new TreeSet<>();
for (int i = 1 ; i <= numberScreenshots; i++) {
- String prefix = name != null ? name : Integer.toString(pid);
+ String prefix = renamedScreenshots ? name : Integer.toString(pid);
String expectedName = "screenshot-" + prefix + "-" + i + ".png";
expectedNames.add(expectedName);
}
@@ -592,7 +614,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
private UiObject waitForScreenshotButtonEnabled(boolean expectedEnabled) throws Exception {
UiObject screenshotButton = getScreenshotButton();
- int maxAttempts = SCREENSHOT_DELAY_SECONDS + 2;
+ int maxAttempts = SCREENSHOT_DELAY_SECONDS + 5;
int i = 0;
do {
boolean enabled = screenshotButton.isEnabled();
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
new file mode 100644
index 000000000000..f3be2ee1ecb0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/assist_orb.xml b/packages/SystemUI/res/layout/assist_orb.xml
index ab0a0a5b8ffb..0036ed6abaf1 100644
--- a/packages/SystemUI/res/layout/assist_orb.xml
+++ b/packages/SystemUI/res/layout/assist_orb.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2012, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/docked_stack_divider.xml b/packages/SystemUI/res/layout/docked_stack_divider.xml
index 22ed216de570..7ea5027b78f4 100644
--- a/packages/SystemUI/res/layout/docked_stack_divider.xml
+++ b/packages/SystemUI/res/layout/docked_stack_divider.xml
@@ -24,10 +24,9 @@
android:id="@+id/docked_divider_background"
android:background="@color/docked_divider_background"/>
- <ImageButton
+ <com.android.systemui.stackdivider.DividerHandleView
style="@style/DockedDividerHandle"
android:id="@+id/docked_divider_handle"
- android:background="@null"
- android:src="@drawable/docked_divider_handle"/>
+ android:background="@null"/>
</com.android.systemui.stackdivider.DividerView>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 6ae5cf3ee3c8..a20ec8e7623d 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2011, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index d58664f76ab4..8498a4f08e8f 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2011, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 3cdee640dd26..071b7c8a6da8 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -29,25 +29,22 @@
android:background="@color/notification_guts_text_color" >
<!-- header -->
- <FrameLayout
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingBottom="8dp" >
+ android:paddingBottom="8dp"
+ android:paddingTop="8dp"
+ android:id="@+id/notification_guts_header"
+ android:orientation="horizontal"
+ android:layout_gravity="center_vertical|start">
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/notification_guts_header"
- android:orientation="horizontal"
- android:layout_gravity="center_vertical|start"
- android:layout_marginEnd="52dp">
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="18dp"
- android:layout_height="18dp"
- android:layout_marginEnd="3dp"
- android:src="@android:drawable/arrow_down_float" />
- <TextView
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="18dp"
+ android:layout_height="18dp"
+ android:layout_marginEnd="3dp"
+ android:src="@android:drawable/arrow_down_float" />
+ <TextView
android:id="@+id/pkgname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -55,7 +52,7 @@
android:layout_marginStart="3dp"
android:layout_marginEnd="4dp"
android:textColor="@color/notification_guts_title_color" />
- <TextView
+ <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/debug_info"
@@ -64,18 +61,7 @@
android:layout_gravity="bottom|start"
android:visibility="gone"
android:textColor="#ffffff" />
- </LinearLayout>
-
- <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
- android:id="@+id/notification_inspect_item"
- android:layout_width="52dp"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:gravity="center"
- android:layout_gravity="center_vertical|end"
- android:contentDescription="@string/status_bar_notification_inspect_item_title"
- android:src="@drawable/ic_settings" />
- </FrameLayout>
+ </LinearLayout>
<!-- Importance slider -->
<LinearLayout
android:layout_width="match_parent"
@@ -157,4 +143,34 @@
android:visibility="gone"/>
</RadioGroup>
</LinearLayout>
+ <!-- buttons -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:paddingTop="8dp"
+ android:paddingBottom="16dp" >
+
+ <TextView
+ android:id="@+id/more_settings"
+ android:text="@string/notification_more_settings"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.NotificationGuts"
+ android:background="@drawable/btn_borderless_rect"
+ android:gravity="center"
+ android:paddingEnd="24dp"
+ android:paddingStart="12dp"
+ android:focusable="true" />
+
+ <TextView
+ android:id="@+id/done"
+ android:text="@string/notification_done"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.NotificationGuts"
+ android:background="@drawable/btn_borderless_rect"
+ android:gravity="center"
+ android:focusable="true"/>
+ </LinearLayout>
</com.android.systemui.statusbar.NotificationGuts>
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 a995ec778972..237768422e2a 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -96,14 +96,14 @@
<LinearLayout
android:id="@+id/date_time_group"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="28dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:orientation="horizontal">
<include layout="@layout/split_clock_view"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginTop="2dp"
android:id="@+id/clock" />
@@ -111,28 +111,28 @@
<com.android.systemui.statusbar.policy.DateView
android:id="@+id/date"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_marginStart="6dp"
android:layout_marginTop="8dp"
- android:layout_alignParentTop="true"
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"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
+ android:layout_height="match_parent"
+ android:layout_marginTop="8dp"
android:drawablePadding="6dp"
android:drawableStart="@drawable/ic_access_alarms_small"
android:textColor="#64ffffff"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
- android:minHeight="36dp"
android:paddingStart="6dp"
+ android:gravity="top"
android:background="?android:attr/selectableItemBackground"
android:visibility="gone" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 2b82b05cab86..5b44c178f872 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -34,9 +34,10 @@
android:layout_gravity="bottom|right"
android:layout_marginRight="15dp"
android:layout_marginBottom="15dp"
- android:translationZ="2dp"
+ android:translationZ="4dp"
android:contentDescription="@string/recents_lock_to_app_button_label"
- android:background="@drawable/recents_lock_to_task_button_bg">
+ android:background="@drawable/recents_lock_to_task_button_bg"
+ android:visibility="invisible">
<ImageView
android:layout_width="@dimen/recents_lock_to_app_icon_size"
android:layout_height="@dimen/recents_lock_to_app_icon_size"
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index f8bd6fdc4fbb..198e65834046 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2011, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index a5b3a8344465..aaa5a0968adb 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2006, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index bfa13e2be9b4..12cf1372d7ca 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2006, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml b/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
index 16757732cfc7..adfaed13e0a1 100644
--- a/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
+++ b/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2011, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index f126ba8b4578..01879935ee6b 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 6910dd422292..503a76709648 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"ተግብር"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ቅንብሮችን ያረጋግጡ"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"አንዳንድ የቀለም ቅንብሮች ይህን መሣሪያ የማይጠቅም ሊያደርጉት ይችላሉ። እነዚህን የቀለም ቅንብሮች ለማረጋገጥ እሺ የሚለውን ጠቅ ያድርጉ፣ አለበለዚያ እነዚህ ቅንብሮች ከ10 ሰከንዶች በኋላ ዳግም ይጀምራሉ።"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 40e3d6ae82d0..d89d0362be2d 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -464,4 +464,16 @@
<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_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_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_apply" msgid="9212602012641034283">"تطبيق"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"تأكيد الإعدادات"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"يمكن أن تتسبب بعض إعدادات الألوان في تعطيل إمكانية استخدام الجهاز. يمكنك النقر على \"موافق\" لتأكيد إعدادات الألوان هذه، وإلا فستتم إعادة تعيين هذه الإعدادات بعد 10 ثوانٍ."</string>
</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index a202ab69748a..55f08419dca6 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 31608e000494..4056963c8e6a 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -455,10 +455,22 @@
<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">"Najveća 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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index a9d596f9dfbf..93c26a4dacfa 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"Прилагане"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Потвърждаване на настройките"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Някои настройки за цветовете могат да направят това устройство неизползваемо. За да ги потвърдите, кликнете върху „OK“. В противен случай те ще бъдат нулирани след 10 секунди."</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index d535bdcb7354..939465b64d29 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"প্রয়োগ করুন"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"সেটিংস নিশ্চিত করুন"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"কিছু রঙের সেটিংস এই ডিভাইসকে ব্যবহারের অযোগ্য করে দিতে পারে৷ এই রঙের সেটিংস নিশ্চিত করতে ওকে এ ক্লিক করুন, অন্যথায় ১০ সেকেন্ড পরে এই সেটিংস পুনরায় সেট হবে৷"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2b38473716cd..e19aa0efe6e2 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4bf573079b43..b1cd561f63c8 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -462,4 +462,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 2b0998f2c4b5..2100c57a2b48 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 1bce9fe897cb..1ad5b26eb543 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index eebb78c6e944..f56d63016128 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"Εφαρμογή"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Επιβεβαίωση ρυθμίσεων"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Ορισμένες ρυθμίσεις χρωμάτων μπορεί να μην επιτρέπουν τη χρήση αυτής της συσκευής. Κάντε κλικ στην επιλογή OK για να επιβεβαιώσετε αυτές τις ρυθμίσεις χρωμάτων, διαφορετικά θα γίνει επαναφορά αυτών των ρυθμίσεων μετά από 10 δευτερόλεπτα."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 79e95fa0244c..f6fc9976d4fb 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 79e95fa0244c..f6fc9976d4fb 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 79e95fa0244c..f6fc9976d4fb 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index df467fbf24c5..fd59418c3048 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a35809b5ba2c..223e684e3a0f 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index a08d06b968aa..f50e78cba01c 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index d9c74898dbb5..c481f521362b 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -456,8 +456,20 @@
<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"</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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 170acddc5e4e..3dee7c9be11b 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"اعمال‌ کردن"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"تأیید تنظیمات"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"بعضی از تنظیمات رنگ می‌توانند این دستگاه را غیرقابل استفاده کنند. برای تأیید این تنظیمات رنگ روی «تأیید» کلیک کنید، در غیر این صورت این تغییرات بعد از ۱۰ ثانیه بازنشانی می‌شوند."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index a47253f7fe88..4a5c3026bd84 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 705f335518f6..2a4f4d9835c2 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 3cfddf5f8c97..928a8b30579e 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 55b65654923a..2a951f726808 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 3e9f2c23d47e..f331ef90cdcb 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"લાગુ કરો"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"સેટિંગ્સની પુષ્ટિ કરો"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"કેટલીક રંગ સેટિંગ્સ આ ઉપકરણને બિનઉપયોગી બનાવી શકે છે. આ રંગ સેટિંગ્સની પુષ્ટિ કરવા માટે ઑકે ક્લિક કરો, અન્યથા 10 સેકંડ પછી આ સેટિંગ્સ ફરીથી સેટ થશે."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index bf0a30580e93..b31c1e0fd251 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"लागू करें"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"से‍ेटिंग की पुष्टि करें"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"कुछ रंग सेटिंग इस डिवाइस को अनुपयोगी बना सकती हैं. इन रंग सेटिंग की पुष्टि करने के लिए ठीक क्लिक करें, अन्यथा 10 सेकंड के बाद ये सेटिंग रीसेट हो जाएंगी."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index cb9e6c65c56c..3bef6e993024 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -461,4 +461,16 @@
<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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 9defa3167520..8dc9a193ae66 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -451,13 +451,25 @@
<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="blocked_importance" msgid="5198578988978234161">"Letiltva"</string>
- <string name="low_importance" msgid="4109929986107147930">"Alacsony fontossági szint"</string>
- <string name="default_importance" msgid="8192107689995742653">"Normál fontossági szint"</string>
- <string name="high_importance" msgid="1527066195614050263">"Magas fontossági szint"</string>
- <string name="max_importance" msgid="5089005872719563894">"Sürgős értesítés"</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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index f8b7c211e162..99d6980ae77c 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"Կիրառել"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Հաստատել կարգավորումները"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Գունային որոշ կարգավորումները կարող են այս սարքը օգտագործման համար ոչ պիտանի դարձնել: Սեղմեք Լավ կոճակը՝ գունային այս կարգավորումները հաստատելու համար: Հակառակ դեպքում այս կարգավորումները կվերակայվեն 10 վայրկյան հետո:"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index f4df6855a535..f6124db7f133 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -448,16 +448,28 @@
<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 <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifikasi"</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>
- <string name="blocked_importance" msgid="5198578988978234161">"Dicekal"</string>
- <string name="low_importance" msgid="4109929986107147930">"Kepentingan rendah"</string>
- <string name="default_importance" msgid="8192107689995742653">"Kepentingan normal"</string>
- <string name="high_importance" msgid="1527066195614050263">"Kepentingan tinggi"</string>
- <string name="max_importance" msgid="5089005872719563894">"Kepentingan darurat"</string>
- <string name="notification_importance_blocked" msgid="2397192642657872872">"Jangan pernah menunjukkan notifikasi ini"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Diblokir"</string>
+ <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 membunyikan suara"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Muncul di layar dan bunyikan suara"</string>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index bb8a9015173a..7ea1746b40e6 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 9006d626742a..b395f8b2a55d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 8394d1c97763..2c894f567267 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -462,4 +462,16 @@
<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_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_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_apply" msgid="9212602012641034283">"החל"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"אישור הגדרות"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"הגדרות צבע מסוימות עלולות להפוך את המכשיר הזה לבלתי שמיש. לחץ על אישור כדי לאשר את הגדרות הצבע האלה, אחרת הגדרות אלה יתאפסו לאחר 10 שניות."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 6f9a00dfbe52..580d995a4957 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -456,8 +456,20 @@
<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_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_high" msgid="3222680136612408223">"通知リストの先頭に表示し、音声でも知らせる"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"画面に数秒間表示し、音声でも知らせる"</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_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_apply" msgid="9212602012641034283">"適用"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"設定の確認"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"一部の色設定を適用すると、この端末を使用できなくなることがあります。この色設定を確認するには、[OK] をクリックしてください。確認しない場合、10 秒後に設定はリセットされます。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index d3497552ecdf..7a51668f09ae 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"გამოყენება"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"პარამეტრების დადასტურება"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ფერთა ზოგიერთ პარამეტრს ამ მოწყობილობასთან მუშაობის გართულება შეუძლია. ფერთა ამჟამინდელი პარამეტრების დასადასტურებლად, დააწკაპუნეთ „კარგი“-ზე. წინააღმდეგ შემთხვევაში, პარამეტრები 10 წამის შემდეგ ჩამოიყრება."</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index b692f787e418..eb8995e0ab7c 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"Қолдану"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Параметрлерді растау"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Кейбір түс параметрлері бұл құрылғыны пайдалану мүмкін емес етуі мүмкін. Бұл түс параметрлерін растау үшін OK түймесін басыңыз, әйтпесе параметрлер 10 секундтан кейін ысырылады."</string>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 637cdddcd6e1..5c102131b9e7 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"អនុវត្ត"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"បញ្ជាក់ការកំណត់"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ការកំណត់ពណ៌មួយចំនួនអាចធ្វើឲ្យឧបករណ៍នេះមិនអាចប្រើបាន។ សូមចុច យល់ព្រម ដើម្បីបញ្ជាក់ការកំណត់ពណ៌ទាំងនេះ បើមិនដូច្នេះទេការកំណត់ទាំងនេះនឹងកំណត់ឡើងវិញក្នុងរយៈពេល 10 វិនាទីបន្ទាប់។"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index d40f160ce0ac..28b2de55f406 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"ಅನ್ವಯಿಸು"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಖಚಿತಪಡಿಸಿ"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ಕೆಲವು ಬಣ್ಣ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಈ ಸಾಧನವನ್ನು ಅನುಪಯುಕ್ತಗೊಳಿಸಬಹುದು. ಈ ಬಣ್ಣ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಖಚಿತಪಡಿಸಲು ಸರಿ ಕ್ಲಿಕ್ ಮಾಡಿ, ಇಲ್ಲವಾದರೆ ಈ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು 10 ಸೆಕೆಂಡುಗಳ ನಂತರ ಮರುಹೊಂದಿಸಿ."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ec34677743a2..110376fb04f7 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"적용"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"설정 확인"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"일부 색상 설정으로 인해 이 기기를 사용하지 못할 수 있습니다. 확인을 클릭하여 이러한 색상 설정을 확인하지 않으면 10초 후에 설정이 초기화됩니다."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index c0e63079e01b..ee2ef5d78e27 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"Колдонуу"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Жөндөөлөрдү ырастоо"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Айрым түс жөндөөлөрү бул түзмөктү колдонулгус кылып коюшу мүмкүн. Бул түс жөндөөлөрүн ырастоо үчүн OK баскычын чыкылдатыңыз, болбосо бул жөндөөлөр 10 секунддан кийин баштапкы абалына келтирилет."</string>
</resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 456391d61216..c75a89fa4b31 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -24,5 +24,5 @@
<integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
<dimen name="docked_divider_handle_width">2dp</dimen>
- <dimen name="docked_divider_handle_height">24dp</dimen>
+ <dimen name="docked_divider_handle_height">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml
index 96d8fb8a02dd..b711faa30280 100644
--- a/packages/SystemUI/res/values-land/styles.xml
+++ b/packages/SystemUI/res/values-land/styles.xml
@@ -20,7 +20,7 @@
</style>
<style name="DockedDividerBackground">
- <item name="android:layout_width">12dp</item>
+ <item name="android:layout_width">10dp</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_gravity">center_horizontal</item>
</style>
@@ -28,7 +28,7 @@
<style name="DockedDividerHandle">
<item name="android:layout_gravity">center_vertical</item>
<item name="android:layout_width">48dp</item>
- <item name="android:layout_height">64dp</item>
+ <item name="android:layout_height">96dp</item>
</style>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index a2cf6fc3e954..ed103ea4d089 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"ນຳໃຊ້"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ຢືນ​ຢັນ​ການ​ຕັ້ງ​ຄ່າ"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ບາງການຕັ້ງຄ່າສີສາມາດເຮັດໃຫ້ອຸປະກອນນີ້ບໍ່ສາມາດໃຊ້ໄດ້. ຄລິກ ຕົກລົງ ເພື່ອຢືນຢັນການຕັ້ງຄ່າສີເຫຼົ່ານີ້, ຖ້າບໍ່ດັ່ງນັ້ນ ການຕັ້ງຄ່າເຫຼົ່ານີ້ຈະຕັ້ງຄືນໃໝ່ ຫຼັງຈາກ 10 ວິນາທີ."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index aa5699a15869..ba98e2b1df9e 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -462,4 +462,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 98761b0f7395..0143fea7c7bb 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -461,4 +461,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 023792bff158..c57313936b6f 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -42,7 +42,7 @@
<string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Дали да се вклучи штедачот на батерија?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Вклучи"</string>
<string name="battery_saver_start_action" msgid="5576697451677486320">"Вклучете го штедачот на батерија"</string>
- <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Подесувања"</string>
+ <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Поставки"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Автоматско ротирање на екранот"</string>
<string name="status_bar_settings_mute_label" msgid="554682549917429396">"ИСКЛ."</string>
@@ -151,7 +151,7 @@
<string name="accessibility_no_sims" msgid="3957997018324995781">"Нема СИМ-картичка"</string>
<string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Променување на мрежата на операторот."</string>
<string name="accessibility_battery_level" msgid="7451474187113371965">"Батерија <xliff:g id="NUMBER">%d</xliff:g> проценти."</string>
- <string name="accessibility_settings_button" msgid="799583911231893380">"Подесувања на систем."</string>
+ <string name="accessibility_settings_button" msgid="799583911231893380">"Поставки на систем."</string>
<string name="accessibility_notifications_button" msgid="4498000369779421892">"Известувања"</string>
<string name="accessibility_remove_notification" msgid="3603099514902182350">"Избриши известување."</string>
<string name="accessibility_gps_enabled" msgid="3511469499240123019">"ГПС е овозможен."</string>
@@ -260,7 +260,7 @@
<string name="quick_settings_media_device_label" msgid="1302906836372603762">"Медиумски уред"</string>
<string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Само итни повици"</string>
- <string name="quick_settings_settings_label" msgid="5326556592578065401">"Подесувања"</string>
+ <string name="quick_settings_settings_label" msgid="5326556592578065401">"Поставки"</string>
<string name="quick_settings_time_label" msgid="4635969182239736408">"Време"</string>
<string name="quick_settings_user_label" msgid="5238995632130897840">"Јас"</string>
<string name="quick_settings_user_title" msgid="4467690427642392403">"Корисник"</string>
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"Примени"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Потврдете ги поставките"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Некои поставки на боите може да го направат уредот неупотреблив. Кликнете на Во ред за да ги потврдите овие поставки на боите, инаку тие поставки ќе се ресетираат по 10 секунди."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 9e0e409a4e93..c6a08e600e17 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"ബാധകമാക്കുക"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ക്രമീകരണം സ്ഥിരീകരിക്കുക"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ചില വർണ്ണ ക്രമീകരണത്തിന് ഈ ഉപകരണത്തെ ഉപയോഗരഹിതമാക്കാനാകും. ഈ വർണ്ണ ക്രമീകരണം സ്ഥിരീകരിക്കുന്നതിന് ശരി എന്നതിൽ ക്ലിക്കുചെയ്യുക, അല്ലെങ്കിൽ 10 സെക്കൻഡിന് ശേഷം ഈ ക്രമീകരണം പുനഃക്രമീകരിക്കപ്പെടും."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 445c2fd5c069..91c817a5caf4 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -455,7 +455,19 @@
<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_default" msgid="4926529615920610817">"Эдгээр мэдэгдлийг дуугүй харуулах"</string>
<string name="notification_importance_high" msgid="3222680136612408223">"Мэдэгдлийг жагсаалтын эхэнд дуутай харуулах"</string>
<string name="notification_importance_max" msgid="5236987171904756134">"Дэлгэцэнд яаралтайгаар дуутай гаргах"</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_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_apply" msgid="9212602012641034283">"Хэрэгжүүлэх"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Тохиргоог баталгаажуулах"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Зарим өнгөний тохиргоо энэ төхөөрөмжийг ашиглах боломжгүй болгож болзошгүй. OK товчлуурыг дарж эдгээр өнгөний тохиргоог зөвшөөрөхгүй бол энэ тохиргоо нь 10 секундын дараа шинэчлэгдэх болно."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 3a45fb90c2ea..5d3a96f7721e 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"लागू करा"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"सेटिंग्जची पुष्टी करा"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"काही रंग सेटिंग्ज या डिव्हाइसला निरुपयोगी करू शकतात. या रंग सेटिंग्जची पुष्टी करण्‍यासाठी ठीक आहे दाबा अन्यथा या सेटिंग्ज 10 सेकंदांनंतर रीसेट होतील."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index e3a68406891e..f0a013c4f93a 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 0043eb87b110..75008cbd5004 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"အသုံးပြုပါ"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ဆက်တင်များကို အတည်ပြုပါ"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"အချို့သော အရောင်ဆက်တက်များက ဤကိရိယာကို သုံးမရအောင် လုပ်ပစ်နိုင်ပါသည်။ ဤအရောင် ဆက်တင်များကို အတည်ပြုရန် အိုကေကို နှိပ်ပါ၊ သို့မဟုတ် ဤဆက်တင်များကို ၁၀ စက္ကန့် အကြာတွင် ပြန်ညှိလိုက်ပါမည်။"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 967388b736c6..295a49a8f555 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 658ee92de53a..d0aa5103532a 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -449,15 +449,27 @@
<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="apply_to_app" msgid="363016783939815960">"यो अनुप्रयोगका सबै सूचनाहरूमा लागू गर्नुहोस्"</string>
<string name="blocked_importance" msgid="5198578988978234161">"रोकियो"</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="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_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_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_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_apply" msgid="9212602012641034283">"लागू गर्नुहोस्"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"सेटिङहरूको पुष्टि गर्नुहोस्"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"केही रङ सेटिङहरूले यस यन्त्रलाई अनुपयोगी बनाउन सक्छन्। यी रङ सेटिङहरू पुष्टि गर्न ठीक छ मा क्लिक गर्नुहोस्, अन्यथा यी सेटिङहरू १० सेकेण्डपछि रिसेट हुनेछन्।"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index d5ea047a8fb1..75812ad3e2ca 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -405,7 +405,7 @@
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Verbergen"</string>
<string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> wil het volumedialoogvenster zijn."</string>
<string name="volumeui_prompt_allow" msgid="7954396902482228786">"Toestaan"</string>
- <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Afwijzen"</string>
+ <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Weigeren"</string>
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is het volumedialoogvenster"</string>
<string name="volumeui_notification_text" msgid="1826889705095768656">"Tik hierop om het origineel te herstellen."</string>
<string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
@@ -460,4 +460,16 @@
<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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index ad66640b2cb0..fc5a3eaa44ed 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"ਲਾਗੂ ਕਰੋ"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ਸੈਟਿੰਗਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ਕੁਝ ਰੰਗ ਸੈਟਿੰਗਾਂ ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਬੇਕਾਰ ਕਰ ਸਕਦੀਆਂ ਹਨ। ਇਹਨਾਂ ਰੰਗ ਸੈਟਿੰਗਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਠੀਕ \'ਤੇ ਕਲਿੱਕ ਕਰੋ, ਨਹੀਂ ਤਾਂ ਇਹ ਸੈਟਿੰਗਾਂ 10 ਸਕਿੰਟ ਬਾਅਦ ਮੁੜ-ਸੈੱਟ ਹੋ ਜਾਣਗੀਆਂ।"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 8cf8785494fd..8ef50c993d5b 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -454,7 +454,7 @@
<string name="apply_to_app" msgid="363016783939815960">"Zastosuj do wszystkich powiadomień z tej aplikacji"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Zablokowane"</string>
<string name="low_importance" msgid="4109929986107147930">"Mało ważne"</string>
- <string name="default_importance" msgid="8192107689995742653">"Mniej 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>
@@ -462,4 +462,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 72a93f0fea2e..8f614781c84f 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 9b4b93e6a26d..8a727a1e4024 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -425,7 +425,7 @@
<string name="status_bar_airplane" msgid="7057575501472249002">"Modo de avião"</string>
<string name="add_tile" msgid="2995389510240786221">"Adicionar mosaico"</string>
<string name="broadcast_tile" msgid="3894036511763289383">"Mosaico de transmissão"</string>
- <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Só vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g> se desativar esta funcionalidade antes dessa hora"</string>
+ <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Só vai ouvir o próximo alarme (<xliff:g id="WHEN">%1$s</xliff:g>) se desativar esta funcionalidade antes dessa hora"</string>
<string name="zen_alarm_warning" msgid="444533119582244293">"Não vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="3980063409350522735">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="4242179982586714810">"em <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -450,14 +450,26 @@
<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>
- <string name="blocked_importance" msgid="5198578988978234161">"Bloqueada"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloqueado"</string>
<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 urgente"</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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 72a93f0fea2e..8f614781c84f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 3877a4394098..3ab8bf2a534f 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -461,4 +461,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 5002ad2e2705..6ffd3330822e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -462,4 +462,16 @@
<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_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_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_apply" msgid="9212602012641034283">"Применить"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Подтвердите настройки"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Некоторые цветовые настройки могут затруднить работу с устройством. Чтобы применить выбранные параметры, нажмите \"ОК\". В противном случае они будут сброшены через 10 секунд."</string>
</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index cdc749d3807b..efbc0423e1dc 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"යොදන්න"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"සැකසීම් තහවුරු කරන්න"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"සමහර වර්ණ සැකසීම් මෙම උපාංගය භාවිත කළ නොහැකි තත්ත්වයට පත් කළ හැකිය. මෙම වර්ණ සැකසීම් තහවුරු කිරීමට හරි ක්ලික් කරන්න, නැතහොත් මෙම සැකසීම් තත්පර 10කට පසුව යළි සකසනු ඇත."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 1dca386d275f..31985b4e9624 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -462,4 +462,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index a3a868247555..7c8d443ba66b 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -462,4 +462,16 @@
<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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 1cf34a612f38..c8add9497b31 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index f429e15d0bb8..bec1fd4d4217 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -455,10 +455,22 @@
<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="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_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_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_apply" msgid="9212602012641034283">"Примени"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Потврдите подешавања"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Нека подешавања боја могу да учине уређај неупотребљивим. Кликните на Потврди да бисте потврдили ова подешавања боја, пошто ће се у супротном ова подешавања ресетовати након 10 секунди."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 3420f09927a7..d4a9cdc31b3e 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 4bc5ba971ef2..2ffbf2ba3c19 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index effcb9dd6115..168a11b4f07a 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"பயன்படுத்து"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"அமைப்புகளை உறுதிப்படுத்து"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"சில வண்ண அமைப்புகள் இந்தச் சாதனத்தைப் பயன்படுத்த முடியாதபடி செய்யலாம். இந்த வண்ண அமைப்புகளை உறுதிப்படுத்த, சரி என்பதைக் கிளிக் செய்யவும், இல்லையெனில் இந்த அமைப்புகள் 10 வினாடிகளுக்குப் பின் மீட்டமைக்கப்படும்."</string>
</resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index fc7cabe5dda1..086dede50a14 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"వర్తింపజేయి"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"సెట్టింగ్‌లను నిర్ధారించండి"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"కొన్ని రంగు సెట్టింగ్‌ల వలన ఈ పరికరం ఉపయోగించలేని విధంగా అయిపోవచ్చు. ఈ రంగు సెట్టింగ్‌లను నిర్ధారించడానికి సరే క్లిక్ చేయండి లేదంటే ఈ సెట్టింగ్‌లు 10 సెకన్ల తర్వాత రీసెట్ చేయబడతాయి."</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 28e7d681bb84..8c1a7d35f680 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"ใช้"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ยืนยันการตั้งค่า"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"การตั้งค่าสีบางอย่างอาจทำให้อุปกรณ์นี้ใช้งานไม่ได้ คลิกตกลงเพื่อยืนยันการตั้งค่าสีเหล่านี้ มิฉะนั้นระบบจะรีเซ็ตการตั้งค่าหลังจาก 10 วินาที"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 9602f300fd7c..4bee3eab3b26 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index dbe450f4130f..c0ecc780f36e 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 35d1e5868ae8..31094033aa66 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -462,4 +462,16 @@
<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_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_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_apply" msgid="9212602012641034283">"Застосувати"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Підтвердити налаштування"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Деякі налаштування кольорів можуть зробити цей пристрій непридатним для використання. Натисніть OK, щоб підтвердити налаштування, інакше їх буде скинуто через 10 секунд."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 32908facd3ca..52aa58032c8a 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"لاگو کریں"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ترتیبات کی توثیق کریں"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"رنگوں کی کچھ ترتیبات اس آلے کو ناقابل استعمال بنا سکتی ہیں۔ رنگوں کی ان ترتیبات کی توثیق کرنے کیلئے ٹھیک ہے پر کلک کریں، بصورت دیگر 10 سیکنڈ بعد یہ ترتیبات ری سیٹ ہو جائیں گی۔"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 885412fa340b..a849cfc6de21 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 3e0f65322c28..fa835ba0153e 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 3eedd49a86eb..bb8f4adf70e1 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -413,7 +413,7 @@
<string name="system_ui_tuner" msgid="708224127392452018">"系统界面调谐器"</string>
<string name="show_battery_percentage" msgid="5444136600512968798">"嵌入式显示电池电量百分比 显示嵌入的电池电量百分比"</string>
<string name="show_battery_percentage_summary" msgid="3215025775576786037">"未充电时在状态栏图标内显示电池电量百分比"</string>
- <string name="quick_settings" msgid="10042998191725428">"快速设置"</string>
+ <string name="quick_settings" msgid="10042998191725428">"快捷设置"</string>
<string name="status_bar" msgid="4877645476959324760">"状态栏"</string>
<string name="overview" msgid="4018602013895926956">"概览"</string>
<string name="demo_mode" msgid="2389163018533514619">"演示模式"</string>
@@ -429,7 +429,7 @@
<string name="zen_alarm_warning" msgid="444533119582244293">"您在<xliff:g id="WHEN">%1$s</xliff:g>将不会听到下次闹钟响铃"</string>
<string name="alarm_template" msgid="3980063409350522735">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="4242179982586714810">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"快速设置,<xliff:g id="TITLE">%s</xliff:g>。"</string>
+ <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"快捷设置,<xliff:g id="TITLE">%s</xliff:g>。"</string>
<string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"热点"</string>
<string name="accessibility_managed_profile" msgid="6613641363112584120">"工作资料"</string>
<string name="tuner_warning_title" msgid="7094689930793031682">"是否有趣完全取决于个人感觉"</string>
@@ -442,34 +442,36 @@
<string name="activity_not_found" msgid="348423244327799974">"您的设备中未安装此应用"</string>
<string name="clock_seconds" msgid="7689554147579179507">"显示时钟的秒数"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
- <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速设置"</string>
- <string name="show_brightness" msgid="6613930842805942519">"在快速设置中显示亮度栏"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快捷设置"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"在快捷设置中显示亮度栏"</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>
- <!-- no translation found for apply_to_topic (3641403489318659666) -->
+ <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="blocked_importance" msgid="5198578988978234161">"屏蔽"</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>
+ <!-- no translation found for notification_more_settings (816306283396553571) -->
<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) -->
+ <!-- no translation found for notification_done (5279426047273930175) -->
<skip />
+ <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_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_apply" msgid="9212602012641034283">"应用"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"确认设置"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"部分颜色设置可能会导致此设备无法使用。请点击“确定”确认这些颜色设置,否则,系统将在 10 秒后重置这些设置。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index fc82a709c7dd..0782354a619d 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -454,10 +454,22 @@
<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="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_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_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_apply" msgid="9212602012641034283">"套用"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"確認設定"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"部分顏色設定會令此裝置無法使用。請按一下 [確定] 加以確認,否則這些顏色設定將於 10 秒後重設。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 66ffa0f9d9d1..29520f6f38fc 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -460,4 +460,16 @@
<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_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_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_apply" msgid="9212602012641034283">"套用"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"確認設定"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"部分顏色設定可能會造成這部裝置無法使用。請按一下 [確定] 來確認您要使用這類顏色設定,否則系統將在 10 秒後重設這些設定。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 279f76502815..3ee46eaa1ef2 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -460,4 +460,16 @@
<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>
+ <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_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_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>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 24cc6bf1589a..035f56485287 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -583,9 +583,9 @@
<dimen name="qs_header_neg_padding">-8dp</dimen>
<!-- How high we lift the divider when touching -->
- <dimen name="docked_stack_divider_lift_elevation">6dp</dimen>
+ <dimen name="docked_stack_divider_lift_elevation">4dp</dimen>
- <dimen name="docked_divider_handle_width">24dp</dimen>
+ <dimen name="docked_divider_handle_width">16dp</dimen>
<dimen name="docked_divider_handle_height">2dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 45ddd509e96d..876c21efe1a8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1228,6 +1228,11 @@
<!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
<string name="notification_importance_max">Peek onto the screen and make 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>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index a9176e0c393c..527b6380d2f3 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -299,13 +299,13 @@
<style name="DockedDividerBackground">
<item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">12dp</item>
+ <item name="android:layout_height">10dp</item>
<item name="android:layout_gravity">center_vertical</item>
</style>
<style name="DockedDividerHandle">
<item name="android:layout_gravity">center_horizontal</item>
- <item name="android:layout_width">64dp</item>
+ <item name="android:layout_width">96dp</item>
<item name="android:layout_height">48dp</item>
</style>
@@ -317,4 +317,12 @@
<item name="@dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
</style>
+ <style name="TextAppearance.NotificationGuts">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@color/notification_guts_btn_color</item>
+ <item name="android:textAllCaps">true</item>
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="android:gravity">center</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index d931856a822b..481b91805108 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -70,17 +70,19 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
// time for us to receive the signal that it's starting.
private static final long BLUETOOTH_START_DELAY_MILLIS = 10 * 1000;
+ // We will be scanning up to 30 seconds, after which we'll stop.
+ private static final long BLUETOOTH_SCAN_TIMEOUT_MILLIS = 30 * 1000;
+
private static final int STATE_NOT_ENABLED = -1;
private static final int STATE_UNKNOWN = 0;
private static final int STATE_WAITING_FOR_BOOT_COMPLETED = 1;
private static final int STATE_WAITING_FOR_TABLET_MODE_EXIT = 2;
private static final int STATE_WAITING_FOR_DEVICE_DISCOVERY = 3;
private static final int STATE_WAITING_FOR_BLUETOOTH = 4;
- private static final int STATE_WAITING_FOR_STATE_PAIRED = 5;
- private static final int STATE_PAIRING = 6;
- private static final int STATE_PAIRED = 7;
- private static final int STATE_USER_CANCELLED = 8;
- private static final int STATE_DEVICE_NOT_FOUND = 9;
+ private static final int STATE_PAIRING = 5;
+ private static final int STATE_PAIRED = 6;
+ private static final int STATE_USER_CANCELLED = 7;
+ private static final int STATE_DEVICE_NOT_FOUND = 8;
private static final int MSG_INIT = 0;
private static final int MSG_ON_BOOT_COMPLETED = 1;
@@ -92,6 +94,7 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
private static final int MSG_ON_BLE_SCAN_FAILED = 7;
private static final int MSG_SHOW_BLUETOOTH_DIALOG = 8;
private static final int MSG_DISMISS_BLUETOOTH_DIALOG = 9;
+ private static final int MSG_BLE_ABORT_SCAN = 10;
private volatile KeyboardHandler mHandler;
private volatile KeyboardUIHandler mUIHandler;
@@ -107,6 +110,7 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
private long mBootCompletedTime;
private int mInTabletMode = InputManager.SWITCH_STATE_UNKNOWN;
+ private int mScanAttempt = 0;
private ScanCallback mScanCallback;
private BluetoothDialog mDialog;
@@ -328,6 +332,9 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
.build();
mScanCallback = new KeyboardScanCallback();
scanner.startScan(Arrays.asList(filter), settings, mScanCallback);
+
+ Message abortMsg = mHandler.obtainMessage(MSG_BLE_ABORT_SCAN, ++mScanAttempt, 0);
+ mHandler.sendMessageDelayed(abortMsg, BLUETOOTH_SCAN_TIMEOUT_MILLIS);
}
private void stopScanning() {
@@ -338,6 +345,19 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
}
// Should only be called on the handler thread
+ private void bleAbortScanInternal(int scanAttempt) {
+ if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY && scanAttempt == mScanAttempt) {
+ if (DEBUG) {
+ Slog.d(TAG, "Bluetooth scan timed out");
+ }
+ stopScanning();
+ // FIXME: should we also try shutting off bluetooth if we enabled
+ // it in the first place?
+ mState = STATE_DEVICE_NOT_FOUND;
+ }
+ }
+
+ // Should only be called on the handler thread
private void onDeviceAddedInternal(CachedBluetoothDevice d) {
if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY && d.getName().equals(mKeyboardName)) {
stopScanning();
@@ -425,6 +445,12 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
} else {
mState = STATE_USER_CANCELLED;
}
+ break;
+ }
+ case MSG_BLE_ABORT_SCAN: {
+ int scanAttempt = msg.arg1;
+ bleAbortScanInternal(scanAttempt);
+ break;
}
case MSG_ON_BLUETOOTH_STATE_CHANGED: {
int bluetoothState = msg.arg1;
@@ -555,8 +581,6 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
return "STATE_WAITING_FOR_DEVICE_DISCOVERY";
case STATE_WAITING_FOR_BLUETOOTH:
return "STATE_WAITING_FOR_BLUETOOTH";
- case STATE_WAITING_FOR_STATE_PAIRED:
- return "STATE_WAITING_FOR_STATE_PAIRED";
case STATE_PAIRING:
return "STATE_PAIRING";
case STATE_PAIRED:
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index b56ad76ec2b4..01eb5f941fee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -75,7 +75,8 @@ public class QSIconView extends ViewGroup {
iv.setTag(R.id.qs_icon_tag, state.icon);
if (d instanceof Animatable) {
Animatable a = (Animatable) d;
- if (state.icon instanceof QSTile.AnimationIcon && !iv.isShown()) {
+ a.start();
+ if (!iv.isShown()) {
a.stop(); // skip directly to end state
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 39f0c5578e8e..1a36abd3f1c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -19,8 +19,6 @@ package com.android.systemui.qs;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.Animatable;
-import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
@@ -29,9 +27,20 @@ import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
-
import com.android.systemui.qs.QSTile.State;
-import com.android.systemui.statusbar.policy.*;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.Listenable;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
import java.util.Collection;
import java.util.Objects;
@@ -389,11 +398,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
@Override
public Drawable getDrawable(Context context) {
- Drawable d = context.getDrawable(mResId);
- if (d instanceof Animatable) {
- ((Animatable) d).start();
- }
- return d;
+ return context.getDrawable(mResId);
}
@Override
@@ -408,41 +413,14 @@ public abstract class QSTile<TState extends State> implements Listenable {
}
protected class AnimationIcon extends ResourceIcon {
- private boolean mAllowAnimation;
-
public AnimationIcon(int resId) {
super(resId);
}
- public void setAllowAnimation(boolean allowAnimation) {
- mAllowAnimation = allowAnimation;
- }
-
@Override
public Drawable getDrawable(Context context) {
// workaround: get a clean state for every new AVD
- final AnimatedVectorDrawable d = (AnimatedVectorDrawable) context.getDrawable(mResId)
- .getConstantState().newDrawable();
- d.start();
- if (mAllowAnimation) {
- mAllowAnimation = false;
- } else {
- d.stop(); // skip directly to end state
- }
- return d;
- }
- }
-
- protected enum UserBoolean {
- USER_TRUE(true, true),
- USER_FALSE(true, false),
- BACKGROUND_TRUE(false, true),
- BACKGROUND_FALSE(false, false);
- public final boolean value;
- public final boolean userInitiated;
- private UserBoolean(boolean userInitiated, boolean value) {
- this.value = value;
- this.userInitiated = userInitiated;
+ return context.getDrawable(mResId).getConstantState().newDrawable();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java
deleted file mode 100644
index a5e1fd55c8f0..000000000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.android.systemui.qs;
-
-import android.os.IBinder;
-import android.service.quicksettings.IQSTileService;
-import android.service.quicksettings.Tile;
-import android.util.Log;
-
-
-public class QSTileServiceWrapper implements IQSTileService {
- private static final String TAG = "IQSTileServiceWrapper";
-
- private final IQSTileService mService;
-
- public QSTileServiceWrapper(IQSTileService service) {
- mService = service;
- }
-
- @Override
- public IBinder asBinder() {
- return mService.asBinder();
- }
-
- @Override
- public void setQSTile(Tile tile) {
- try {
- mService.setQSTile(tile);
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-
- @Override
- public void onTileAdded() {
- try {
- mService.onTileAdded();
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-
- @Override
- public void onTileRemoved() {
- try {
- mService.onTileRemoved();
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-
- @Override
- public void onStartListening() {
- try {
- mService.onStartListening();
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-
- @Override
- public void onStopListening() {
- try {
- mService.onStopListening();
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-
- @Override
- public void onClick(IBinder token) {
- try {
- mService.onClick(token);
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index bda46756e1aa..5fa38c6e0304 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -49,6 +49,11 @@ public class QuickQSPanel extends QSPanel {
mQsContainer.addView((View) mTileLayout, 1 /* Between brightness and footer */);
}
+ @Override
+ protected void createCustomizePanel() {
+ // No customizing from the header.
+ }
+
public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
mFullPanel = fullPanel;
mHeader = header;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
index 87c2973592b6..7448493b4880 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
@@ -16,32 +16,28 @@
package com.android.systemui.qs.customize;
import android.app.ActivityManager;
-import android.app.Service;
import android.content.ClipData;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
+import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings.Secure;
-import android.service.quicksettings.IQSTileService;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
-
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileServiceWrapper;
-import com.android.systemui.qs.tiles.CustomTile;
+import com.android.systemui.qs.external.CustomTile;
+import com.android.systemui.qs.external.TileLifecycleManager;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.tuner.TunerService;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
/**
@@ -52,8 +48,9 @@ import java.util.List;
public class CustomQSPanel extends QSPanel {
private static final String TAG = "CustomQSPanel";
+ private static final boolean DEBUG = false;
- private List<String> mSavedTiles;
+ private List<String> mSavedTiles = Collections.emptyList();
private ArrayList<String> mStash;
private List<String> mTiles = new ArrayList<>();
@@ -67,17 +64,25 @@ public class CustomQSPanel extends QSPanel {
((NonPagedTileLayout) mTileLayout).setCustomQsPanel(this);
removeView(mFooter.getView());
+ if (DEBUG) Log.d(TAG, "new CustomQSPanel", new Throwable());
TunerService.get(mContext).addTunable(this, QSTileHost.TILES_SETTING);
}
@Override
+ protected void onDetachedFromWindow() {
+ // Don't allow the super to unregister the tunable.
+ }
+
+ @Override
public void onTuningChanged(String key, String newValue) {
if (key.equals(QS_SHOW_BRIGHTNESS)) {
// No Brightness for you.
super.onTuningChanged(key, "0");
}
if (QSTileHost.TILES_SETTING.equals(key)) {
- mSavedTiles = QSTileHost.loadTileSpecs(mContext, newValue);
+ mSavedTiles = Collections.unmodifiableList(
+ QSTileHost.loadTileSpecs(mContext, newValue));
+ if (DEBUG) Log.d(TAG, "New saved tiles " + TextUtils.join(",", mSavedTiles));
}
}
@@ -106,6 +111,7 @@ public class CustomQSPanel extends QSPanel {
}
public void setSavedTiles() {
+ if (DEBUG) Log.d(TAG, "setSavedTiles " + TextUtils.join(",", mSavedTiles));
setTiles(mSavedTiles);
}
@@ -114,47 +120,26 @@ public class CustomQSPanel extends QSPanel {
String tileSpec = mSavedTiles.get(i);
if (!tileSpec.startsWith(CustomTile.PREFIX)) continue;
if (!mTiles.contains(tileSpec)) {
- mContext.bindServiceAsUser(
- new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec)),
- new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- QSTileServiceWrapper wrapper = new QSTileServiceWrapper(
- IQSTileService.Stub.asInterface(service));
- wrapper.onStopListening();
- wrapper.onTileRemoved();
- mContext.unbindService(this);
- }
- }, Service.BIND_AUTO_CREATE,
- new UserHandle(ActivityManager.getCurrentUser()));
+ Intent intent = new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec));
+ TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
+ mContext, intent, new UserHandle(ActivityManager.getCurrentUser()));
+ lifecycleManager.onStopListening();
+ lifecycleManager.onTileRemoved();
+ lifecycleManager.flushMessagesAndUnbind();
}
}
for (int i = 0; i < mTiles.size(); i++) {
String tileSpec = mTiles.get(i);
if (!tileSpec.startsWith(CustomTile.PREFIX)) continue;
if (!mSavedTiles.contains(tileSpec)) {
- mContext.bindServiceAsUser(
- new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec)),
- new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- QSTileServiceWrapper wrapper = new QSTileServiceWrapper(
- IQSTileService.Stub.asInterface(service));
- wrapper.onTileAdded();
- mContext.unbindService(this);
- }
- }, Service.BIND_AUTO_CREATE,
- new UserHandle(ActivityManager.getCurrentUser()));
+ Intent intent = new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec));
+ TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
+ mContext, intent, new UserHandle(ActivityManager.getCurrentUser()));
+ lifecycleManager.onTileAdded();
+ lifecycleManager.flushMessagesAndUnbind();
}
}
+ if (DEBUG) Log.d(TAG, "saveCurrentTiles " + mTiles);
Secure.putStringForUser(getContext().getContentResolver(), QSTileHost.TILES_SETTING,
TextUtils.join(",", mTiles), ActivityManager.getCurrentUser());
}
@@ -173,30 +158,37 @@ public class CustomQSPanel extends QSPanel {
}
private void setTilesInternal() {
+ if (DEBUG) Log.d(TAG, "Set tiles internal");
for (int i = 0; i < mCurrentTiles.size(); i++) {
mCurrentTiles.get(i).destroy();
}
mCurrentTiles.clear();
for (int i = 0; i < mTiles.size(); i++) {
if (mTiles.get(i).startsWith(CustomTile.PREFIX)) {
- mCurrentTiles.add(BlankCustomTile.create(mHost, mTiles.get(i)));
+ QSTile<?> tile = BlankCustomTile.create(mHost, mTiles.get(i));
+ tile.setTileSpec(mTiles.get(i));
+ mCurrentTiles.add(tile);
} else {
QSTile<?> tile = mHost.createTile(mTiles.get(i));
if (tile != null) {
+ tile.setTileSpec(mTiles.get(i));
mCurrentTiles.add(tile);
+ } else {
+ if (DEBUG) Log.d(TAG, "Skipping " + mTiles.get(i));
}
}
- mCurrentTiles.get(mCurrentTiles.size() - 1).setTileSpec(mTiles.get(i));
}
super.setTiles(mCurrentTiles);
}
public void addTile(String spec) {
+ if (DEBUG) Log.d(TAG, "addTile " + spec);
mTiles.add(spec);
setTilesInternal();
}
public void moveTo(String from, String to) {
+ if (DEBUG) Log.d(TAG, "moveTo " + from + " " + to);
int fromIndex = mTiles.indexOf(from);
if (fromIndex < 0) {
Log.e(TAG, "Unknown from tile " + from);
@@ -220,6 +212,7 @@ public class CustomQSPanel extends QSPanel {
}
public void setTiles(List<String> tiles) {
+ if (DEBUG) Log.d(TAG, "Set tiles " + TextUtils.join(",", tiles));
mTiles = new ArrayList<>(tiles);
setTilesInternal();
}
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 6706c7aace12..a6a71439dbae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -41,7 +41,7 @@ import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTile.Icon;
-import com.android.systemui.qs.tiles.CustomTile;
+import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.tuner.QSPagingSwitch;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index bb74f341b89d..2e5a0b277552 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -11,32 +11,26 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
*/
+package com.android.systemui.qs.external;
-package com.android.systemui.qs.tiles;
-
-import android.app.ActivityManager;
-import android.app.Service;
import android.content.ComponentName;
-import android.content.Intent;
-import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
import android.util.Log;
import android.view.IWindowManager;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileServiceWrapper;
import com.android.systemui.statusbar.phone.QSTileHost;
public class CustomTile extends QSTile<QSTile.State> {
@@ -52,8 +46,9 @@ public class CustomTile extends QSTile<QSTile.State> {
private final Tile mTile;
private final IWindowManager mWindowManager;
private final IBinder mToken = new Binder();
+ private final IQSTileService mService;
+ private final TileServiceManager mServiceManager;
- private QSTileServiceWrapper mService;
private boolean mListening;
private boolean mBound;
private boolean mIsTokenGranted;
@@ -63,7 +58,9 @@ public class CustomTile extends QSTile<QSTile.State> {
super(host);
mWindowManager = WindowManagerGlobal.getWindowManagerService();
mComponent = ComponentName.unflattenFromString(action);
- mTile = new Tile(mComponent, host);
+ mServiceManager = host.getTileServices().getTileWrapper(this);
+ mService = mServiceManager.getTileService();
+ mTile = new Tile(mComponent);
try {
PackageManager pm = mContext.getPackageManager();
ServiceInfo info = pm.getServiceInfo(mComponent, 0);
@@ -72,6 +69,11 @@ public class CustomTile extends QSTile<QSTile.State> {
mTile.setLabel(info.loadLabel(pm));
} catch (Exception e) {
}
+ try {
+ mService.setQSTile(mTile);
+ } catch (RemoteException e) {
+ // Called through wrapper, won't happen here.
+ }
}
public ComponentName getComponent() {
@@ -96,42 +98,33 @@ public class CustomTile extends QSTile<QSTile.State> {
public void setListening(boolean listening) {
if (mListening == listening) return;
mListening = listening;
- if (listening) {
- mHandler.removeCallbacks(mUnbind);
- if (!mBound) {
- // TODO: Guarantee re-bind on user-switch.
- mContext.bindServiceAsUser(new Intent().setComponent(mComponent),
- mServiceConnection, Service.BIND_AUTO_CREATE,
- new UserHandle(ActivityManager.getCurrentUser()));
- mBound = true;
- } else {
- if (mService != null) {
+ try {
+ if (listening) {
+ if (mServiceManager.getType() == TileService.TILE_MODE_PASSIVE) {
+ mServiceManager.setBindRequested(true);
mService.onStartListening();
- } else {
- Log.d(TAG, "Can't start service listening");
}
- }
- } else {
- if (mService != null) {
+ } else {
mService.onStopListening();
- }
- if (mIsTokenGranted && !mIsShowingDialog) {
- try {
- if (DEBUG) Log.d(TAG, "Removing token");
- mWindowManager.removeWindowToken(mToken);
- } catch (RemoteException e) {
+ if (mIsTokenGranted && !mIsShowingDialog) {
+ try {
+ if (DEBUG) Log.d(TAG, "Removing token");
+ mWindowManager.removeWindowToken(mToken);
+ } catch (RemoteException e) {
+ }
+ mIsTokenGranted = false;
}
- mIsTokenGranted = false;
+ mIsShowingDialog = false;
+ mServiceManager.setBindRequested(false);
}
- mIsShowingDialog = false;
- mHandler.postDelayed(mUnbind, UNBIND_DELAY);
+ } catch (RemoteException e) {
+ // Called through wrapper, won't happen here.
}
}
@Override
protected void handleDestroy() {
super.handleDestroy();
- mHandler.removeCallbacks(mUnbind);
if (mIsTokenGranted) {
try {
if (DEBUG) Log.d(TAG, "Removing token");
@@ -139,7 +132,6 @@ public class CustomTile extends QSTile<QSTile.State> {
} catch (RemoteException e) {
}
}
- mUnbind.run();
}
@Override
@@ -154,16 +146,20 @@ public class CustomTile extends QSTile<QSTile.State> {
@Override
protected void handleClick() {
- if (mService != null) {
- try {
- if (DEBUG) Log.d(TAG, "Adding token");
- mWindowManager.addWindowToken(mToken, WindowManager.LayoutParams.TYPE_QS_DIALOG);
- mIsTokenGranted = true;
- } catch (RemoteException e) {
+ try {
+ if (DEBUG) Log.d(TAG, "Adding token");
+ mWindowManager.addWindowToken(mToken, WindowManager.LayoutParams.TYPE_QS_DIALOG);
+ mIsTokenGranted = true;
+ } catch (RemoteException e) {
+ }
+ try {
+ if (mServiceManager.getType() == TileService.TILE_MODE_ACTIVE) {
+ mServiceManager.setBindRequested(true);
+ mService.onStartListening();
}
mService.onClick(mToken);
- } else {
- Log.e(TAG, "Click with no service " + getTileSpec());
+ } catch (RemoteException e) {
+ // Called through wrapper, won't happen here.
}
MetricsLogger.action(mContext, getMetricsCategory(), mComponent.getPackageName());
}
@@ -187,34 +183,9 @@ public class CustomTile extends QSTile<QSTile.State> {
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_INTENT;
+ return MetricsLogger.QS_CUSTOM;
}
- private final ServiceConnection mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mService = new QSTileServiceWrapper(IQSTileService.Stub.asInterface(service));
- if (mListening) {
- mService.setQSTile(mTile);
- mService.onStartListening();
- } else {
- mService.onStopListening();
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
- };
-
- private final Runnable mUnbind = new Runnable() {
- @Override
- public void run() {
- mContext.unbindService(mServiceConnection);
- mBound = false;
- }
- };
-
public static ComponentName getComponentFromSpec(String spec) {
final String action = spec.substring(PREFIX.length(), spec.length() - 1);
if (action.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
new file mode 100644
index 000000000000..d41cdde37958
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
@@ -0,0 +1,107 @@
+/*
+ * 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.qs.external;
+
+import android.os.IBinder;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.util.Log;
+
+
+public class QSTileServiceWrapper {
+ private static final String TAG = "IQSTileServiceWrapper";
+
+ private final IQSTileService mService;
+
+ public QSTileServiceWrapper(IQSTileService service) {
+ mService = service;
+ }
+
+ public IBinder asBinder() {
+ return mService.asBinder();
+ }
+
+ public boolean setQSTile(Tile tile) {
+ try {
+ mService.setQSTile(tile);
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean onTileAdded() {
+ try {
+ mService.onTileAdded();
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean onTileRemoved() {
+ try {
+ mService.onTileRemoved();
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean onStartListening() {
+ try {
+ mService.onStartListening();
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean onStopListening() {
+ try {
+ mService.onStopListening();
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean onClick(IBinder token) {
+ try {
+ mService.onClick(token);
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean setQSService(IQSService service) {
+ try {
+ mService.setQSService(service);
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
new file mode 100644
index 000000000000..8c5e87e1a0f6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -0,0 +1,360 @@
+/*
+ * 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.qs.external;
+
+import android.app.AppGlobals;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.support.annotation.VisibleForTesting;
+import android.util.ArraySet;
+import android.util.Log;
+import libcore.util.Objects;
+
+import java.util.Set;
+
+/**
+ * Manages the lifecycle of a TileService.
+ * <p>
+ * Will keep track of all calls on the IQSTileService interface and will relay those calls to the
+ * TileService as soon as it is bound. It will only bind to the service when it is allowed to
+ * ({@link #setBindService(boolean)}) and when the service is available.
+ */
+public class TileLifecycleManager extends BroadcastReceiver implements
+ IQSTileService, ServiceConnection, IBinder.DeathRecipient {
+ public static final boolean DEBUG = false;
+
+ private static final String TAG = "TileLifecycleManager";
+
+ private static final int MSG_ON_ADDED = 0;
+ private static final int MSG_ON_REMOVED = 1;
+ private static final int MSG_ON_CLICK = 2;
+
+ // Bind retry control.
+ private static final int MAX_BIND_RETRIES = 5;
+ private static final int BIND_RETRY_DELAY = 1000;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Intent mIntent;
+ private final UserHandle mUser;
+
+ private Set<Integer> mQueuedMessages = new ArraySet<>();
+ private QSTileServiceWrapper mWrapper;
+ private boolean mListening;
+ private Tile mTile;
+ private IBinder mClickBinder;
+
+ private int mBindTryCount;
+ private boolean mBound;
+ @VisibleForTesting
+ boolean mReceiverRegistered;
+ private IQSService mService;
+ private boolean mUnbindImmediate;
+
+ public TileLifecycleManager(Handler handler, Context context, Intent intent, UserHandle user) {
+ mContext = context;
+ mHandler = handler;
+ mIntent = intent;
+ mUser = user;
+ }
+
+ public ComponentName getComponent() {
+ return mIntent.getComponent();
+ }
+
+ public boolean hasPendingClick() {
+ synchronized (mQueuedMessages) {
+ return mQueuedMessages.contains(MSG_ON_CLICK);
+ }
+ }
+
+ /**
+ * Binds just long enough to send any queued messages, then unbinds.
+ */
+ public void flushMessagesAndUnbind() {
+ mUnbindImmediate = true;
+ setBindService(true);
+ }
+
+ public void setBindService(boolean bind) {
+ mBound = bind;
+ if (bind) {
+ if (mBindTryCount == MAX_BIND_RETRIES) {
+ // Too many failures, give up on this tile until an update.
+ startPackageListening();
+ return;
+ }
+ if (!checkComponentState()) {
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "Binding service " + mIntent);
+ mBindTryCount++;
+ mContext.bindServiceAsUser(mIntent, this,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+ mUser);
+ } else {
+ if (DEBUG) Log.d(TAG, "Unbinding service " + mIntent);
+ // Give it another chance next time it needs to be bound, out of kindness.
+ mBindTryCount = 0;
+ mWrapper = null;
+ mContext.unbindService(this);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) Log.d(TAG, "onServiceConnected " + name);
+ // Got a connection, set the binding count to 0.
+ mBindTryCount = 0;
+ mWrapper = new QSTileServiceWrapper(Stub.asInterface(service));
+ try {
+ service.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ }
+ setQSService(mService);
+ setQSTile(mTile);
+ handlePendingMessages();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.d(TAG, "onServiceDisconnected " + name);
+ mWrapper = null;
+ }
+
+ private void handlePendingMessages() {
+ // This ordering is laid out manually to make sure we preserve the TileService
+ // lifecycle.
+ ArraySet<Integer> queue;
+ synchronized (mQueuedMessages) {
+ queue = new ArraySet<>(mQueuedMessages);
+ mQueuedMessages.clear();
+ }
+ if (queue.contains(MSG_ON_ADDED)) {
+ if (DEBUG) Log.d(TAG, "Handling pending onAdded");
+ onTileAdded();
+ }
+ if (mListening) {
+ if (DEBUG) Log.d(TAG, "Handling pending onStartListening");
+ onStartListening();
+ }
+ if (queue.contains(MSG_ON_CLICK)) {
+ if (DEBUG) Log.d(TAG, "Handling pending onClick");
+ if (!mListening) {
+ Log.w(TAG, "Managed to get click on non-listening state...");
+ // Skipping click since lost click privileges.
+ } else {
+ onClick(mClickBinder);
+ }
+ }
+ if (queue.contains(MSG_ON_REMOVED)) {
+ if (DEBUG) Log.d(TAG, "Handling pending onRemoved");
+ if (mListening) {
+ Log.w(TAG, "Managed to get remove in listening state...");
+ onStopListening();
+ }
+ onTileRemoved();
+ }
+ if (mUnbindImmediate) {
+ mUnbindImmediate = false;
+ setBindService(false);
+ }
+ }
+
+ public void handleDestroy() {
+ if (DEBUG) Log.d(TAG, "handleDestroy");
+ if (mReceiverRegistered) {
+ stopPackageListening();
+ }
+ }
+
+ private void handleDeath() {
+ if (mWrapper == null) return;
+ mWrapper = null;
+ if (!mBound) return;
+ if (DEBUG) Log.d(TAG, "handleDeath");
+ if (checkComponentState()) {
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (mBound) {
+ // Retry binding.
+ setBindService(true);
+ }
+ }
+ }, BIND_RETRY_DELAY);
+ }
+ }
+
+ @Override
+ public void setQSTile(Tile tile) {
+ if (DEBUG) Log.d(TAG, "setQSTile " + tile);
+ mTile = tile;
+ if (mWrapper != null && !mWrapper.setQSTile(tile)) {
+ handleDeath();
+ }
+ }
+
+ private boolean checkComponentState() {
+ PackageManager pm = mContext.getPackageManager();
+ if (!isPackageAvailable(pm) || !isComponentAvailable(pm)) {
+ startPackageListening();
+ return false;
+ }
+ return true;
+ }
+
+ private void startPackageListening() {
+ if (DEBUG) Log.d(TAG, "startPackageListening");
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addDataScheme("package");
+ mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler);
+ mReceiverRegistered = true;
+ }
+
+ private void stopPackageListening() {
+ if (DEBUG) Log.d(TAG, "stopPackageListening");
+ mContext.unregisterReceiver(this);
+ mReceiverRegistered = false;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) Log.d(TAG, "onReceive: " + intent);
+ Uri data = intent.getData();
+ String pkgName = data.getEncodedSchemeSpecificPart();
+ if (!Objects.equal(pkgName, mIntent.getComponent().getPackageName())) {
+ return;
+ }
+ stopPackageListening();
+ if (mBound) {
+ // Trying to bind again will check the state of the package before bothering to bind.
+ if (DEBUG) Log.d(TAG, "Trying to rebind");
+ setBindService(true);
+ }
+ }
+
+ private boolean isComponentAvailable(PackageManager pm) {
+ String packageName = mIntent.getComponent().getPackageName();
+ try {
+ ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(mIntent.getComponent(),
+ 0, mUser.getIdentifier());
+ if (DEBUG && si == null) Log.d(TAG, "Can't find component " + mIntent.getComponent());
+ return si != null;
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ }
+ return false;
+ }
+
+ private boolean isPackageAvailable(PackageManager pm) {
+ String packageName = mIntent.getComponent().getPackageName();
+ try {
+ pm.getPackageInfoAsUser(packageName, 0, mUser.getIdentifier());
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ if (DEBUG) Log.d(TAG, "Package not available: " + packageName, e);
+ else Log.d(TAG, "Package not available: " + packageName);
+ }
+ return false;
+ }
+
+ private void queueMessage(int message) {
+ synchronized (mQueuedMessages) {
+ mQueuedMessages.add(message);
+ }
+ }
+
+ @Override
+ public void setQSService(IQSService service) {
+ mService = service;
+ if (mWrapper == null || !mWrapper.setQSService(service)) {
+ handleDeath();
+ }
+ }
+
+ @Override
+ public void onTileAdded() {
+ if (DEBUG) Log.d(TAG, "onTileAdded");
+ if (mWrapper == null || !mWrapper.onTileAdded()) {
+ queueMessage(MSG_ON_ADDED);
+ handleDeath();
+ }
+ }
+
+ @Override
+ public void onTileRemoved() {
+ if (DEBUG) Log.d(TAG, "onTileRemoved");
+ if (mWrapper == null || !mWrapper.onTileRemoved()) {
+ queueMessage(MSG_ON_REMOVED);
+ handleDeath();
+ }
+ }
+
+ @Override
+ public void onStartListening() {
+ if (DEBUG) Log.d(TAG, "onStartListening");
+ mListening = true;
+ if (mWrapper != null && !mWrapper.onStartListening()) {
+ handleDeath();
+ }
+ }
+
+ @Override
+ public void onStopListening() {
+ if (DEBUG) Log.d(TAG, "onStopListening");
+ mListening = false;
+ if (mWrapper != null && !mWrapper.onStopListening()) {
+ handleDeath();
+ }
+ }
+
+ @Override
+ public void onClick(IBinder iBinder) {
+ if (DEBUG) Log.d(TAG, "onClick " + iBinder);
+ if (mWrapper == null || !mWrapper.onClick(iBinder)) {
+ mClickBinder = iBinder;
+ queueMessage(MSG_ON_CLICK);
+ handleDeath();
+ }
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return mWrapper != null ? mWrapper.asBinder() : null;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DEBUG) Log.d(TAG, "binderDeath");
+ handleDeath();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
new file mode 100644
index 000000000000..2f77a303c36c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -0,0 +1,197 @@
+/*
+ * 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.qs.external;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.TileService;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+/**
+ * Manages the priority which lets {@link TileServices} make decisions about which tiles
+ * to bind. Also holds on to and manages the {@link TileLifecycleManager}, informing it
+ * of when it is allowed to bind based on decisions frome the {@link TileServices}.
+ */
+public class TileServiceManager {
+
+ private static final long MIN_BIND_TIME = 5000;
+ private static final long UNBIND_DELAY = 30000;
+
+ public static final boolean DEBUG = true;
+
+ private static final String TAG = "TileServiceManager";
+
+ @VisibleForTesting
+ static final String PREFS_FILE = "CustomTileModes";
+
+ private final TileServices mServices;
+ private final TileLifecycleManager mStateManager;
+ private final Handler mHandler;
+ private boolean mBindRequested;
+ private boolean mBindAllowed;
+ private boolean mBound;
+ private int mPriority;
+ private boolean mJustBound;
+ private long mLastUpdate;
+ private int mType;
+
+ TileServiceManager(TileServices tileServices, Handler handler, ComponentName component) {
+ this(tileServices, handler, new TileLifecycleManager(handler,
+ tileServices.getContext(), new Intent().setComponent(component),
+ new UserHandle(ActivityManager.getCurrentUser())));
+ }
+
+ @VisibleForTesting
+ TileServiceManager(TileServices tileServices, Handler handler,
+ TileLifecycleManager tileLifecycleManager) {
+ mServices = tileServices;
+ mHandler = handler;
+ mStateManager = tileLifecycleManager;
+ mType = tileServices.getContext().getSharedPreferences(PREFS_FILE, 0)
+ .getInt(tileLifecycleManager.getComponent().flattenToString(),
+ TileService.TILE_MODE_UNSET);
+ mStateManager.setQSService(tileServices);
+ if (mType == TileService.TILE_MODE_UNSET) {
+ bindService();
+ mStateManager.onTileAdded();
+ }
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ public void setType(int type) {
+ mServices.getContext().getSharedPreferences(PREFS_FILE, 0).edit()
+ .putInt(mStateManager.getComponent().flattenToString(), type).commit();
+ mType = type;
+ mServices.recalculateBindAllowance();
+ }
+
+ public IQSTileService getTileService() {
+ return mStateManager;
+ }
+
+ public void setBindRequested(boolean bindRequested) {
+ if (mBindRequested == bindRequested) return;
+ mBindRequested = bindRequested;
+ if (mBindAllowed && mBindRequested && !mBound) {
+ mHandler.removeCallbacks(mUnbind);
+ bindService();
+ } else {
+ mServices.recalculateBindAllowance();
+ }
+ if (mBound && !mBindRequested) {
+ mHandler.postDelayed(mUnbind, UNBIND_DELAY);
+ }
+ }
+
+ public void setLastUpdate(long lastUpdate) {
+ mLastUpdate = lastUpdate;
+ if (mBound && mType == TileService.TILE_MODE_ACTIVE) {
+ mStateManager.onStopListening();
+ setBindRequested(false);
+ }
+ mServices.recalculateBindAllowance();
+ }
+
+ public void handleDestroy() {
+ mStateManager.handleDestroy();
+ }
+
+ public void setBindAllowed(boolean allowed) {
+ if (mBindAllowed == allowed) return;
+ mBindAllowed = allowed;
+ if (!mBindAllowed && mBound) {
+ unbindService();
+ } else if (mBindAllowed && mBindRequested && !mBound) {
+ bindService();
+ }
+ }
+
+ private void bindService() {
+ if (mBound) {
+ Log.e(TAG, "Service already bound");
+ return;
+ }
+ mBound = true;
+ mJustBound = true;
+ mHandler.postDelayed(mJustBoundOver, MIN_BIND_TIME);
+ mStateManager.setBindService(true);
+ }
+
+ private void unbindService() {
+ if (!mBound) {
+ Log.e(TAG, "Service not bound");
+ return;
+ }
+ mBound = false;
+ mJustBound = false;
+ mStateManager.setBindService(false);
+ }
+
+ public void calculateBindPriority(long currentTime) {
+ if (mStateManager.hasPendingClick()) {
+ // Pending click is the most important thing, need to put this service at the top of
+ // the list to be bound.
+ mPriority = Integer.MAX_VALUE;
+ } else if (mJustBound) {
+ // If we just bound, lets not thrash on binding/unbinding too much, this is second most
+ // important.
+ mPriority = Integer.MAX_VALUE - 1;
+ } else if (!mBindRequested) {
+ // Don't care about binding right now, put us last.
+ mPriority = Integer.MIN_VALUE;
+ } else {
+ // Order based on whether this was just updated.
+ long timeSinceUpdate = currentTime - mLastUpdate;
+ // Fit compare into integer space for simplicity. Make sure to leave MAX_VALUE and
+ // MAX_VALUE - 1 for the more important states above.
+ if (timeSinceUpdate > Integer.MAX_VALUE - 2) {
+ mPriority = Integer.MAX_VALUE - 2;
+ } else {
+ mPriority = (int) timeSinceUpdate;
+ }
+ }
+ }
+
+ public int getBindPriority() {
+ return mPriority;
+ }
+
+ private final Runnable mUnbind = new Runnable() {
+ @Override
+ public void run() {
+ if (mBound && !mBindRequested) {
+ unbindService();
+ }
+ }
+ };
+
+ @VisibleForTesting
+ final Runnable mJustBoundOver = new Runnable() {
+ @Override
+ public void run() {
+ mJustBound = false;
+ mServices.recalculateBindAllowance();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
new file mode 100644
index 000000000000..7403ae0321bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -0,0 +1,208 @@
+/*
+ * 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.qs.external;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+import android.util.ArrayMap;
+import android.util.Log;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+/**
+ * Runs the day-to-day operations of which tiles should be bound and when.
+ */
+public class TileServices extends IQSService.Stub {
+ static final int DEFAULT_MAX_BOUND = 3;
+ static final int REDUCED_MAX_BOUND = 1;
+
+ private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>();
+ private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
+ private final Context mContext;
+ private final Handler mHandler;
+ private final QSTileHost mHost;
+
+ private int mMaxBound = DEFAULT_MAX_BOUND;
+
+ public TileServices(QSTileHost host, Looper looper) {
+ mHost = host;
+ mContext = mHost.getContext();
+ mContext.registerReceiver(mRequestListeningReceiver,
+ new IntentFilter(TileService.ACTION_REQUEST_LISTENING));
+ mHandler = new Handler(looper);
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public TileServiceManager getTileWrapper(CustomTile tile) {
+ ComponentName component = tile.getComponent();
+ TileServiceManager service = onCreateTileService(component);
+ synchronized (mServices) {
+ mServices.put(tile, service);
+ mTiles.put(component, tile);
+ }
+ return service;
+ }
+
+ protected TileServiceManager onCreateTileService(ComponentName component) {
+ return new TileServiceManager(this, mHandler, component);
+ }
+
+ public void freeService(CustomTile tile, TileServiceManager service) {
+ synchronized (mServices) {
+ service.setBindAllowed(false);
+ mServices.remove(tile);
+ mTiles.remove(tile.getComponent());
+ }
+ }
+
+ public void setMemoryPressure(boolean memoryPressure) {
+ mMaxBound = memoryPressure ? REDUCED_MAX_BOUND : DEFAULT_MAX_BOUND;
+ recalculateBindAllowance();
+ }
+
+ public void recalculateBindAllowance() {
+ final ArrayList<TileServiceManager> services;
+ synchronized (mServices) {
+ services = new ArrayList<>(mServices.values());
+ }
+ final int N = services.size();
+ if (N > mMaxBound) {
+ long currentTime = System.currentTimeMillis();
+ // Precalculate the priority of services for binding.
+ for (int i = 0; i < N; i++) {
+ services.get(i).calculateBindPriority(currentTime);
+ }
+ // Sort them so we can bind the most important first.
+ Collections.sort(services, SERVICE_SORT);
+ }
+ int i;
+ // Allow mMaxBound items to bind.
+ for (i = 0; i < mMaxBound && i < N; i++) {
+ services.get(i).setBindAllowed(true);
+ }
+ // The rest aren't allowed to bind for now.
+ while (i < N) {
+ services.get(i).setBindAllowed(false);
+ i++;
+ }
+ }
+
+ private void verifyCaller(String packageName) {
+ try {
+ int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
+ Binder.getCallingUserHandle().getIdentifier());
+ if (Binder.getCallingUid() != uid) {
+ throw new SecurityException("Component outside caller's uid");
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new SecurityException(e);
+ }
+ }
+
+ private void requestListening(ComponentName component) {
+ synchronized (mServices) {
+ CustomTile customTile = getTileForComponent(component);
+ if (customTile == null) {
+ Log.d("TileServices", "Couldn't find tile for " + component);
+ return;
+ }
+ TileServiceManager service = mServices.get(customTile);
+ if (service.getType() != TileService.TILE_MODE_ACTIVE) {
+ return;
+ }
+ service.setBindRequested(true);
+ try {
+ service.getTileService().onStartListening();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ @Override
+ public void setTileMode(ComponentName component, int mode) {
+ verifyCaller(component.getPackageName());
+ CustomTile customTile = getTileForComponent(component);
+ if (customTile != null) {
+ synchronized (mServices) {
+ mServices.get(customTile).setType(mode);
+ }
+ }
+ }
+
+ @Override
+ public void updateQsTile(Tile tile) {
+ verifyCaller(tile.getComponentName().getPackageName());
+ CustomTile customTile = getTileForComponent(tile.getComponentName());
+ if (customTile != null) {
+ synchronized (mServices) {
+ mServices.get(customTile).setLastUpdate(System.currentTimeMillis());
+ }
+ customTile.updateState(tile);
+ customTile.refreshState();
+ }
+ }
+
+ @Override
+ public void onShowDialog(Tile tile) {
+ verifyCaller(tile.getComponentName().getPackageName());
+ CustomTile customTile = getTileForComponent(tile.getComponentName());
+ if (customTile != null) {
+ customTile.onDialogShown();
+ mHost.collapsePanels();
+ }
+ }
+
+ private CustomTile getTileForComponent(ComponentName component) {
+ synchronized (mServices) {
+ return mTiles.get(component);
+ }
+ }
+
+ private final BroadcastReceiver mRequestListeningReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (TileService.ACTION_REQUEST_LISTENING.equals(intent.getAction())) {
+ requestListening(
+ (ComponentName) intent.getParcelableExtra(TileService.EXTRA_COMPONENT));
+ }
+ }
+ };
+
+ private static final Comparator<TileServiceManager> SERVICE_SORT =
+ new Comparator<TileServiceManager>() {
+ @Override
+ public int compare(TileServiceManager left, TileServiceManager right) {
+ return -Integer.compare(left.getBindPriority(), right.getBindPriority());
+ }
+ };
+}
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 fc802dde9797..c696f886e33f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -58,8 +58,6 @@ public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
public void handleClick() {
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
setEnabled(!mState.value);
- mEnable.setAllowAnimation(true);
- mDisable.setAllowAnimation(true);
}
private void setEnabled(boolean enabled) {
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 f73ee354443d..23a15b9d68ab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -71,8 +71,6 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
protected void handleClick() {
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
mSetting.setValue(mState.value ? 0 : 1);
- mEnable.setAllowAnimation(true);
- mDisable.setAllowAnimation(true);
}
@Override
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 d96f735301e5..4f9f46df7d26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -107,8 +107,6 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
Toast.LENGTH_LONG).show();
return;
}
- mDisable.setAllowAnimation(true);
- mDisableTotalSilence.setAllowAnimation(true);
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
if (mState.value) {
mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
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 12c12980b065..39d9da12d4a1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -64,7 +64,7 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
}
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
boolean newState = !mState.value;
- refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
+ refreshState(newState);
mFlashlightController.setFlashlight(newState);
}
@@ -73,8 +73,8 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
// TODO: Flashlight available handling...
// state.visible = mFlashlightController.isAvailable();
state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
- if (arg instanceof UserBoolean) {
- boolean value = ((UserBoolean) arg).value;
+ if (arg instanceof Boolean) {
+ boolean value = (Boolean) arg;
if (value == state.value) {
return;
}
@@ -83,7 +83,6 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
state.value = mFlashlightController.isEnabled();
}
final AnimationIcon icon = state.value ? mEnable : mDisable;
- icon.setAllowAnimation(arg instanceof UserBoolean && ((UserBoolean) arg).userInitiated);
state.icon = icon;
int onOrOffId = state.value
? R.string.accessibility_quick_settings_flashlight_on
@@ -107,12 +106,12 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
@Override
public void onFlashlightChanged(boolean enabled) {
- refreshState(enabled ? UserBoolean.BACKGROUND_TRUE : UserBoolean.BACKGROUND_FALSE);
+ refreshState(enabled);
}
@Override
public void onFlashlightError() {
- refreshState(UserBoolean.BACKGROUND_FALSE);
+ refreshState(false);
}
@Override
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 250d5674bb6e..55aa32bb0db9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -59,8 +59,6 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
final boolean isEnabled = (Boolean) mState.value;
MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
mController.setHotspotEnabled(!isEnabled);
- mEnable.setAllowAnimation(true);
- mDisable.setAllowAnimation(true);
}
@Override
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 08540f69ff6e..e79aabfb8bf8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -67,8 +67,6 @@ public class LocationTile extends QSTile<QSTile.BooleanState> {
mHost.openPanels();
MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
mController.setLocationEnabled(!wasEnabled);
- mEnable.setAllowAnimation(true);
- mDisable.setAllowAnimation(true);
}
});
return;
@@ -76,8 +74,6 @@ public class LocationTile extends QSTile<QSTile.BooleanState> {
final boolean wasEnabled = (Boolean) mState.value;
MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
mController.setLocationEnabled(!wasEnabled);
- mEnable.setAllowAnimation(true);
- mDisable.setAllowAnimation(true);
}
@Override
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 d85cf605c851..7bce54b33d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -63,15 +63,14 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
final boolean newState = !mState.value;
mController.setRotationLocked(newState);
- refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
+ refreshState(newState);
}
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
if (mController == null) return;
- final boolean rotationLocked = arg != null ? ((UserBoolean) arg).value
+ final boolean rotationLocked = arg != null ? (Boolean) arg
: mController.isRotationLocked();
- final boolean userInitiated = arg != null ? ((UserBoolean) arg).userInitiated : false;
// TODO: Handle accessibility rotation lock and whatnot.
// state.visible = mController.isRotationLockAffordanceVisible();
if (state.value == rotationLocked && state.contentDescription != null) {
@@ -80,18 +79,15 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
}
state.value = rotationLocked;
final boolean portrait = isCurrentOrientationLockPortrait();
- final AnimationIcon icon;
if (rotationLocked) {
final int label = portrait ? R.string.quick_settings_rotation_locked_portrait_label
: R.string.quick_settings_rotation_locked_landscape_label;
state.label = mContext.getString(label);
- icon = portrait ? mAutoToPortrait : mAutoToLandscape;
+ state.icon = portrait ? mAutoToPortrait : mAutoToLandscape;
} else {
state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
- icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
+ state.icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
}
- icon.setAllowAnimation(userInitiated);
- state.icon = icon;
state.contentDescription = getAccessibilityString(rotationLocked,
R.string.accessibility_rotation_lock_on_portrait,
R.string.accessibility_rotation_lock_on_landscape,
@@ -145,8 +141,7 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() {
@Override
public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
- refreshState(rotationLocked ? UserBoolean.BACKGROUND_TRUE
- : UserBoolean.BACKGROUND_FALSE);
+ refreshState(rotationLocked);
}
};
}
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 07915f8dc56e..255f29f285c4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -93,12 +93,7 @@ public class WorkModeTile extends QSTile<QSTile.BooleanState> {
}
private void refreshQuietModeState(boolean backgroundRefresh) {
- if (backgroundRefresh) {
- refreshState(isWorkModeEnabled() ? UserBoolean.BACKGROUND_TRUE
- : UserBoolean.BACKGROUND_FALSE);
- } else {
- refreshState(isWorkModeEnabled() ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
- }
+ refreshState(isWorkModeEnabled());
}
@Override
@@ -108,28 +103,22 @@ public class WorkModeTile extends QSTile<QSTile.BooleanState> {
return;
}
- final boolean userInitialized;
- if (arg instanceof UserBoolean) {
- state.value = ((UserBoolean) arg).value;
- userInitialized = ((UserBoolean) arg).userInitiated;
+ if (arg instanceof Boolean) {
+ state.value = (Boolean) arg;
} else {
state.value = isWorkModeEnabled();
- userInitialized = false;
}
- final AnimationIcon icon;
state.label = mContext.getString(R.string.quick_settings_work_mode_label);
if (state.value) {
- icon = mEnable;
+ state.icon = mEnable;
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_work_mode_on);
} else {
- icon = mDisable;
+ state.icon = mDisable;
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_work_mode_off);
}
- icon.setAllowAnimation(userInitialized);
- state.icon = icon;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index ffcc805c4e74..57074df392db 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -77,6 +77,7 @@ import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.recents.views.ViewAnimation;
+import com.android.systemui.statusbar.BaseStatusBar;
import java.util.ArrayList;
@@ -298,12 +299,23 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
*/
void dismissRecentsToHome(boolean animated) {
if (animated) {
- ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(null,
- mFinishLaunchHomeRunnable, null);
+ ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger();
+ exitTrigger.increment();
+ exitTrigger.addLastDecrementRunnable(mFinishLaunchHomeRunnable);
+ exitTrigger.addLastDecrementRunnable(new Runnable() {
+ @Override
+ public void run() {
+ Recents.getSystemServices().sendCloseSystemWindows(
+ BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+ }
+ });
mRecentsView.startExitToHomeAnimation(
new ViewAnimation.TaskViewExitContext(exitTrigger));
+ exitTrigger.decrement();
} else {
mFinishLaunchHomeRunnable.run();
+ Recents.getSystemServices().sendCloseSystemWindows(
+ BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
}
}
@@ -343,7 +355,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
// Initialize the widget host (the host id is static and does not change)
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
mAppWidgetHost = new RecentsAppWidgetHost(this, RecentsAppWidgetHost.HOST_ID);
}
mPackageMonitor = new RecentsPackageMonitor();
@@ -368,14 +380,14 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
// Bind the search app widget when we first start up
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
}
// Register the broadcast receiver to handle messages when the screen is turned off
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
}
registerReceiver(mSystemBroadcastReceiver, filter);
@@ -475,7 +487,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
mPackageMonitor.unregister();
// Stop listening for widget package changes if there was one bound
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
mAppWidgetHost.stopListening();
}
@@ -656,8 +668,8 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
ReferenceCountedTrigger t = new ReferenceCountedTrigger();
ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t);
ctx.postAnimationTrigger.increment();
- if (mSearchWidgetInfo != null) {
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
+ if (mSearchWidgetInfo != null) {
ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
@Override
public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 7547570fadb2..cfbd1cb13ab9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -74,9 +74,6 @@ public class RecentsConfiguration {
public int svelteLevel;
public int searchBarSpaceHeightPx;
- /** Dev options and global settings */
- public boolean lockToAppEnabled;
-
public RecentsConfiguration(Context context) {
// Load only resources that can not change after the first load either through developer
// settings or via multi window
@@ -106,12 +103,7 @@ public class RecentsConfiguration {
/**
* Updates the configuration based on the current state of the system
*/
- void update(Context context, SystemServicesProxy ssp, Rect windowRect) {
- // Only update resources that can change after the first load, either through developer
- // settings or via multi window
- lockToAppEnabled = !ssp.hasFreeformWorkspaceSupport() &&
- ssp.getSystemSetting(context, Settings.System.LOCK_TO_APP_ENABLED) != 0;
-
+ void update(Rect windowRect) {
// Recompute some values based on the given state, since we can not rely on the resource
// system to get certain values.
boolean isLandscape = windowRect.width() > windowRect.height();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index 40c84baf7fd6..c323522013d4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -32,8 +32,8 @@ public class RecentsDebugFlags implements TunerService.Tunable {
public static class Static {
// Enables debug drawing for the transition thumbnail
public static final boolean EnableTransitionThumbnailDebugMode = false;
- // This disables the search bar integration
- public static final boolean DisableSearchBar = true;
+ // This enables the search bar integration
+ public static final boolean EnableSearchBar = false;
// This disables the bitmap and icon caches
public static final boolean DisableBackgroundCache = false;
// Enables the simulated task affiliations
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 949fb86d281b..fd00289b0248 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -19,6 +19,7 @@ package com.android.systemui.recents;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ITaskStackListener;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
@@ -60,6 +61,7 @@ import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
import com.android.systemui.recents.views.TaskStackView;
import com.android.systemui.recents.views.TaskViewHeader;
import com.android.systemui.recents.views.TaskViewTransform;
+import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.util.ArrayList;
@@ -104,6 +106,10 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
mHandler.post(this);
}
+ @Override
+ public void onActivityPinned() {
+ }
+
/** Preloads the next task */
public void run() {
// TODO: Temporarily skip this if multi stack is enabled
@@ -360,6 +366,9 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
// Otherwise, start the recents activity
startRecentsActivity(topTask, isTopTaskHome.value, true /* animate */);
+
+ // Only close the other system windows if we are actually showing recents
+ ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
mLastToggleTime = SystemClock.elapsedRealtime();
}
} catch (ActivityNotFoundException e) {
@@ -572,9 +581,9 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
Rect windowRect = ssp.getWindowRect();
// Update the configuration for the current state
- config.update(mContext, ssp, ssp.getWindowRect());
+ config.update(windowRect);
- if (!RecentsDebugFlags.Static.DisableSearchBar && tryAndBindSearchWidget) {
+ if (RecentsDebugFlags.Static.EnableSearchBar && tryAndBindSearchWidget) {
// Try and pre-emptively bind the search widget on startup to ensure that we
// have the right thumbnail bounds to animate to.
// Note: We have to reload the widget id before we get the task stack bounds below
@@ -850,11 +859,19 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
if (!useThumbnailTransition) {
// If there is no thumbnail transition, but is launching from home into recents, then
// use a quick home transition and do the animation from home
- if (!RecentsDebugFlags.Static.DisableSearchBar && hasRecentTasks) {
+ if (hasRecentTasks) {
SystemServicesProxy ssp = Recents.getSystemServices();
String homeActivityPackage = ssp.getHomeActivityPackageName();
- String searchWidgetPackage = Prefs.getString(mContext,
- Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
+ String searchWidgetPackage = null;
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
+ searchWidgetPackage = Prefs.getString(mContext,
+ Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
+ } else {
+ AppWidgetProviderInfo searchWidgetInfo = ssp.resolveSearchAppWidget();
+ if (searchWidgetInfo != null) {
+ searchWidgetPackage = searchWidgetInfo.provider.getPackageName();
+ }
+ }
// Determine whether we are coming from a search owned home activity
boolean fromSearchHome = (homeActivityPackage != null) &&
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 35e53f69a151..108029d68805 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -58,7 +58,7 @@ import android.util.Log;
import android.util.MutableBoolean;
import android.util.Pair;
import android.view.Display;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
@@ -68,6 +68,7 @@ import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.RecentsImpl;
+import com.android.systemui.statusbar.BaseStatusBar;
import java.io.IOException;
import java.util.ArrayList;
@@ -79,6 +80,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.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
/**
* Acts as a shim around the real system services that we need to access data from, and provides
@@ -128,7 +130,9 @@ public class SystemServicesProxy {
mDisplay = mWm.getDefaultDisplay();
mRecentsPackage = context.getPackageName();
mHasFreeformWorkspaceSupport =
- mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+ mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT) ||
+ Settings.Global.getInt(context.getContentResolver(),
+ DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
// Get the dummy thumbnail width/heights
Resources res = context.getResources();
@@ -310,7 +314,8 @@ public class SystemServicesProxy {
try {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setDockCreateMode(createMode);
- mIam.startActivityFromRecents(taskId, DOCKED_STACK_ID, options.toBundle());
+ options.setLaunchStackId(DOCKED_STACK_ID);
+ mIam.startActivityFromRecents(taskId, options.toBundle());
} catch (RemoteException e) {
e.printStackTrace();
}
@@ -498,6 +503,18 @@ public class SystemServicesProxy {
}
/**
+ * Sends a message to close other system windows.
+ */
+ public void sendCloseSystemWindows(String reason) {
+ if (ActivityManagerNative.isSystemReady()) {
+ try {
+ ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ /**
* Returns the activity info for a given component name.
*
* @param cn The component name of the activity.
@@ -634,7 +651,7 @@ public class SystemServicesProxy {
if (mPm == null) return null;
if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return null;
- ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
+ ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
ComponentName defaultHomeActivity = mPm.getHomeActivities(homeActivities);
if (defaultHomeActivity != null) {
return defaultHomeActivity.getPackageName();
@@ -722,7 +739,7 @@ public class SystemServicesProxy {
/**
* Returns the first Recents widget from the same package as the global assist activity.
*/
- private AppWidgetProviderInfo resolveSearchAppWidget() {
+ public AppWidgetProviderInfo resolveSearchAppWidget() {
if (mAssistComponent == null) return null;
List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders(
AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
@@ -836,8 +853,7 @@ public class SystemServicesProxy {
ActivityOptions options) {
if (mIam != null) {
try {
- mIam.startActivityFromRecents(
- taskId, INVALID_STACK_ID, options == null ? null : options.toBundle());
+ mIam.startActivityFromRecents(taskId, options == null ? null : options.toBundle());
return true;
} catch (Exception e) {
Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e);
@@ -879,12 +895,11 @@ public class SystemServicesProxy {
}
}
- public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+ public void registerDockedStackListener(IDockedStackListener listener) {
if (mWm == null) return;
try {
- WindowManagerGlobal.getWindowManagerService().registerDockDividerVisibilityListener(
- listener);
+ WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(listener);
} catch (Exception e) {
e.printStackTrace();
}
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 7a92b2ae0a21..d6262ac3da44 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -155,7 +155,7 @@ public class RecentsTaskLoadPlan {
// Add the task to the stack
Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
thumbnail, title, contentDescription, activityColor, !isStackTask,
- (i == (taskCount - 1)), config.lockToAppEnabled, t.bounds, t.taskDescription);
+ t.bounds, t.taskDescription);
allTasks.add(task);
}
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 34a0e5256652..d030fc1a906e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -131,8 +131,6 @@ public class Task {
*/
public boolean isLaunchTarget;
public boolean isHistorical;
- public boolean lockToThisTask;
- public boolean lockToTaskEnabled;
private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
@@ -142,8 +140,8 @@ public class Task {
public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
Bitmap thumbnail, String title, String contentDescription, int colorPrimary,
- boolean isHistorical, boolean lockToThisTask, boolean lockToTaskEnabled,
- Rect bounds, ActivityManager.TaskDescription taskDescription) {
+ boolean isHistorical, Rect bounds,
+ ActivityManager.TaskDescription taskDescription) {
boolean isInAffiliationGroup = (affiliationTaskId != key.id);
boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
this.key = key;
@@ -159,8 +157,6 @@ public class Task {
this.bounds = bounds;
this.taskDescription = taskDescription;
this.isHistorical = isHistorical;
- this.lockToThisTask = lockToTaskEnabled && lockToThisTask;
- this.lockToTaskEnabled = lockToTaskEnabled;
}
/** Copies the other task. */
@@ -178,8 +174,6 @@ public class Task {
this.bounds = o.bounds;
this.isLaunchTarget = o.isLaunchTarget;
this.isHistorical = o.isHistorical;
- this.lockToThisTask = o.lockToThisTask;
- this.lockToTaskEnabled = o.lockToTaskEnabled;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 6f003ab63282..5e720cba36c7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -427,8 +427,6 @@ public class TaskStack {
removeGroup(group);
}
}
- // Update the lock-to-app state
- t.lockToThisTask = false;
}
/** Removes a task */
@@ -437,9 +435,6 @@ public class TaskStack {
boolean wasFrontMostTask = (getStackFrontMostTask() == t);
removeTaskImpl(mStackTaskList, t);
Task newFrontMostTask = getStackFrontMostTask();
- if (newFrontMostTask != null && newFrontMostTask.lockToTaskEnabled) {
- newFrontMostTask.lockToThisTask = true;
- }
if (mCb != null) {
// Notify that a task has been removed
mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask);
@@ -524,10 +519,21 @@ public class TaskStack {
mAffinitiesGroups.clear();
}
- /** Gets the front task */
+ /**
+ * Gets the front-most task in the stack.
+ */
public Task getStackFrontMostTask() {
- if (mStackTaskList.size() == 0) return null;
- return mStackTaskList.getTasks().get(mStackTaskList.size() - 1);
+ ArrayList<Task> stackTasks = mStackTaskList.getTasks();
+ if (stackTasks.isEmpty()) {
+ return null;
+ }
+ for (int i = stackTasks.size() - 1; i >= 0; i--) {
+ Task task = stackTasks.get(i);
+ if (!task.isFreeformTask()) {
+ return task;
+ }
+ }
+ return null;
}
/** Gets the task keys */
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 9b1315a2220f..c95c73bc4f89 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -317,7 +317,7 @@ public class RecentsView extends FrameLayout {
* Hides the task stack and shows the empty view.
*/
public void showEmptyView() {
- if (!RecentsDebugFlags.Static.DisableSearchBar && (mSearchBar != null)) {
+ if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
mSearchBar.setVisibility(View.INVISIBLE);
}
mTaskStackView.setVisibility(View.INVISIBLE);
@@ -332,7 +332,7 @@ public class RecentsView extends FrameLayout {
public void hideEmptyView() {
mEmptyView.setVisibility(View.INVISIBLE);
mTaskStackView.setVisibility(View.VISIBLE);
- if (!RecentsDebugFlags.Static.DisableSearchBar && (mSearchBar != null)) {
+ if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
mSearchBar.setVisibility(View.VISIBLE);
}
mTaskStackView.bringToFront();
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 10df15609e0f..9d391b0c8c86 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -333,7 +333,6 @@ public class TaskStackLayoutAlgorithm {
* including the search bar.
*/
public void initialize(Rect taskStackBounds, StackState state) {
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
RecentsConfiguration config = Recents.getConfiguration();
int widthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
int heightPadding = mContext.getResources().getDimensionPixelSize(
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 830d60799717..94fae1381d85 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -28,6 +28,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.Parcelable;
+import android.provider.Settings;
import android.util.IntProperty;
import android.util.Log;
import android.util.Property;
@@ -149,7 +150,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
List<TaskView> mImmutableTaskViews = new ArrayList<>();
List<TaskView> mTmpTaskViews = new ArrayList<>();
LayoutInflater mInflater;
+
boolean mTouchExplorationEnabled;
+ boolean mScreenPinningEnabled;
Interpolator mFastOutSlowInInterpolator;
@@ -224,6 +227,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
protected void onAttachedToWindow() {
SystemServicesProxy ssp = Recents.getSystemServices();
mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
+ mScreenPinningEnabled = ssp.getSystemSetting(getContext(),
+ Settings.System.LOCK_TO_APP_ENABLED) != 0;
EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
super.onAttachedToWindow();
}
@@ -1023,8 +1028,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
launchTargetTask);
hideTask = launchTargetTask.isFreeformTask() && task.isFreeformTask();
}
- tv.prepareEnterRecentsAnimation(task.isLaunchTarget, hideTask, occludesLaunchTarget,
- offscreenY);
+ tv.prepareEnterRecentsAnimation(hideTask, occludesLaunchTarget, offscreenY);
}
// If the enter animation started already and we haven't completed a layout yet, do the
@@ -1087,6 +1091,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
ctx.currentTaskRect = mLayoutAlgorithm.mTaskRect;
ctx.currentTaskOccludesLaunchTarget = (launchTargetTask != null) &&
launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
+ ctx.isScreenPinningEnabled = mScreenPinningEnabled;
ctx.updateListener = mRequestUpdateClippingListener;
mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
ctx.currentTaskTransform, null);
@@ -1271,13 +1276,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
requestSynchronizeStackViewsWithModel(DEFAULT_SYNC_STACK_DURATION);
}
- // Update the new front most task
- if (newFrontMostTask != null) {
+ // Update the new front most task's action button
+ if (mScreenPinningEnabled && newFrontMostTask != null) {
TaskView frontTv = getChildViewForTask(newFrontMostTask);
if (frontTv != null) {
- frontTv.onTaskBound(newFrontMostTask);
- frontTv.fadeInActionButton(getResources().getInteger(
- R.integer.recents_task_enter_from_app_duration));
+ frontTv.showActionButton(true /* fadeIn */, DEFAULT_SYNC_STACK_DURATION);
}
}
@@ -1304,7 +1307,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
@Override
public void prepareViewToEnterPool(TaskView tv) {
- Task task = tv.getTask();
+ final Task task = tv.getTask();
// Report that this tasks's data is no longer being used
Recents.getTaskLoader().unloadTaskData(task);
@@ -1314,14 +1317,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// Update the task views list after removing the task view
updateTaskViewsList();
- // Reset the view properties
+ // Reset the view properties and view state
tv.resetViewProperties();
-
- // Reset the focused view state
tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
-
- // Reset the clip state of the task view
tv.setClipViewInStack(false);
+ if (mScreenPinningEnabled) {
+ tv.hideActionButton();
+ }
}
@Override
@@ -1362,6 +1364,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
if (mFocusedTask == task) {
tv.setFocusedState(true, false /* animated */, false /* requestViewFocus */);
}
+
+ // Restore the action button visibility if it is the front most task view
+ if (mScreenPinningEnabled && tv.getTask() == mStack.getStackFrontMostTask()) {
+ tv.showActionButton(false /* fadeIn */, 0 /* fadeInDuration */);
+ }
}
@Override
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 a3e8b2d72d56..14909c50ef94 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -138,6 +138,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
setBackground(new FakeShadowDrawable(res, config));
}
setOutlineProvider(mViewBounds);
+ setOnLongClickListener(this);
}
/** Set callback */
@@ -175,8 +176,10 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
public void getOutline(View view, Outline outline) {
// Set the outline to match the FAB background
outline.setOval(0, 0, mActionButtonView.getWidth(), mActionButtonView.getHeight());
+ outline.setAlpha(0.35f);
}
});
+ mActionButtonView.setOnClickListener(this);
mActionButtonTranslationZ = mActionButtonView.getTranslationZ();
}
@@ -293,8 +296,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
/** Prepares this task view for the enter-recents animations. This is called earlier in the
* first layout because the actual animation into recents may take a long time. */
- void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask, boolean hideTask,
- boolean occludesLaunchTarget, int offscreenY) {
+ void prepareEnterRecentsAnimation(boolean hideTask, boolean occludesLaunchTarget,
+ int offscreenY) {
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
int initialDim = getDim();
@@ -303,7 +306,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
} else if (launchState.launchedHasConfigurationChanged) {
// Just load the views as-is
} else if (launchState.launchedFromAppWithThumbnail) {
- if (isTaskViewLaunchTargetTask) {
+ if (mTask.isLaunchTarget) {
// Set the dim to 0 so we can animate it in
initialDim = 0;
// Hide the action button
@@ -342,11 +345,15 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
if (launchState.launchedFromAppWithThumbnail) {
if (mTask.isLaunchTarget) {
ctx.postAnimationTrigger.increment();
- // Immediately start the dim animation
+ // Start the dim animation
animateDimToProgress(taskViewEnterFromAppDuration,
ctx.postAnimationTrigger.decrementOnAnimationEnd());
- // Animate the action button in
- fadeInActionButton(taskViewEnterFromAppDuration);
+
+ // Start the action button animation
+ if (ctx.isScreenPinningEnabled) {
+ showActionButton(true /* fadeIn */,
+ taskViewEnterFromAppDuration /* fadeInDuration */);
+ }
} else {
// Animate the task up if it was occluding the launch target
if (ctx.currentTaskOccludesLaunchTarget) {
@@ -413,17 +420,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
animate().cancel();
}
- public void fadeInActionButton(int duration) {
- // Hide the action button
- mActionButtonView.setAlpha(0f);
-
- // Animate the action button in
- mActionButtonView.animate().alpha(1f)
- .setDuration(duration)
- .setInterpolator(PhoneStatusBar.ALPHA_IN)
- .start();
- }
-
/** Animates this task view as it leaves recents by pressing home. */
void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
int taskViewExitToHomeDuration = getResources().getInteger(
@@ -468,8 +464,9 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
.alpha(0f)
.setStartDelay(0)
.setDuration(taskViewExitToAppDuration)
- .setInterpolator(mFastOutLinearInInterpolator)
+ .setInterpolator(PhoneStatusBar.ALPHA_OUT)
.withEndAction(postAnimRunnable)
+ .withLayer()
.start();
} else {
// Hide the dismiss button
@@ -644,8 +641,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
setDim(getDimFromTaskProgress());
}
- /**** View focus state ****/
-
/**
* Explicitly sets the focused state of this task.
*/
@@ -672,19 +667,42 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
}
}
+ /**
+ * Shows the action button.
+ * @param fadeIn whether or not to animate the action button in.
+ * @param fadeInDuration the duration of the action button animation, only used if
+ * {@param fadeIn} is true.
+ */
+ public void showActionButton(boolean fadeIn, int fadeInDuration) {
+ mActionButtonView.setVisibility(View.VISIBLE);
+
+ if (fadeIn) {
+ if (mActionButtonView.getAlpha() < 1f) {
+ mActionButtonView.setAlpha(0f);
+ mActionButtonView.animate().alpha(1f)
+ .setDuration(fadeInDuration)
+ .setInterpolator(PhoneStatusBar.ALPHA_IN)
+ .withLayer()
+ .start();
+ }
+ } else {
+ mActionButtonView.setAlpha(1f);
+ }
+ }
+
+ /**
+ * Immediately hides the action button.
+ */
+ public void hideActionButton() {
+ mActionButtonView.setVisibility(View.INVISIBLE);
+ }
+
/**** TaskCallbacks Implementation ****/
/** Binds this task view to the task */
public void onTaskBound(Task t) {
mTask = t;
mTask.addCallback(this);
-
- // Hide the action button if lock to app is disabled for this view
- int lockButtonVisibility = (!t.lockToTaskEnabled || !t.lockToThisTask) ? GONE : VISIBLE;
- if (mActionButtonView.getVisibility() != lockButtonVisibility) {
- mActionButtonView.setVisibility(lockButtonVisibility);
- requestLayout();
- }
}
@Override
@@ -693,10 +711,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
// Bind each of the views to the new task data
mThumbnailView.rebindToTask(mTask);
mHeaderView.rebindToTask(mTask);
-
- // Rebind any listeners
- mActionButtonView.setOnClickListener(this);
- setOnLongClickListener(this);
}
mTaskDataLoaded = true;
}
@@ -708,8 +722,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
mTask.removeCallback(this);
mThumbnailView.unbindFromTask();
mHeaderView.unbindFromTask();
- // Unbind any listeners
- mActionButtonView.setOnClickListener(null);
}
mTaskDataLoaded = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
index e1d80fdcfa68..eaef51c4869a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
@@ -33,6 +33,8 @@ public class ViewAnimation {
// These following properties are updated for each task view we start the enter animation on
+ // Whether or not screen pinning is enabled
+ boolean isScreenPinningEnabled;
// Whether or not the current task occludes the launch target
boolean currentTaskOccludesLaunchTarget;
// The task rect for the current stack
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 6ff7a3e08159..189e651b7dca 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -17,7 +17,8 @@
package com.android.systemui.stackdivider;
import android.content.res.Configuration;
-import android.view.IDockDividerVisibilityListener;
+import android.os.RemoteException;
+import android.view.IDockedStackListener;
import android.view.LayoutInflater;
import android.view.View;
@@ -49,7 +50,7 @@ public class Divider extends SystemUI {
putComponent(Divider.class, this);
mDockDividerVisibilityListener = new DockDividerVisibilityListener();
SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.registerDockDividerVisibilityListener(mDockDividerVisibilityListener);
+ ssp.registerDockedStackListener(mDockDividerVisibilityListener);
}
@Override
@@ -94,10 +95,15 @@ public class Divider extends SystemUI {
});
}
- class DockDividerVisibilityListener extends IDockDividerVisibilityListener.Stub {
+ class DockDividerVisibilityListener extends IDockedStackListener.Stub {
+
@Override
- public void onDockDividerVisibilityChanged(boolean visible) {
+ public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
updateVisibility(visible);
}
+
+ @Override
+ public void onDockedStackExistsChanged(boolean exists) throws RemoteException {
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
new file mode 100644
index 000000000000..5ef56f3312dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
@@ -0,0 +1,142 @@
+/*
+ * 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.stackdivider;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.Property;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageButton;
+
+import com.android.systemui.R;
+
+/**
+ * View for the handle in the docked stack divider.
+ */
+public class DividerHandleView extends ImageButton {
+
+ private final static Property<DividerHandleView, Integer> WIDTH_PROPERTY
+ = new Property<DividerHandleView, Integer>(Integer.class, "width") {
+
+ @Override
+ public Integer get(DividerHandleView object) {
+ return object.mCurrentWidth;
+ }
+
+ @Override
+ public void set(DividerHandleView object, Integer value) {
+ object.mCurrentWidth = value;
+ object.invalidate();
+ }
+ };
+
+ private final static Property<DividerHandleView, Integer> HEIGHT_PROPERTY
+ = new Property<DividerHandleView, Integer>(Integer.class, "height") {
+
+ @Override
+ public Integer get(DividerHandleView object) {
+ return object.mCurrentHeight;
+ }
+
+ @Override
+ public void set(DividerHandleView object, Integer value) {
+ object.mCurrentHeight = value;
+ object.invalidate();
+ }
+ };
+
+ private final Paint mPaint = new Paint();
+ private final int mWidth;
+ private final int mHeight;
+ private final int mCircleDiameter;
+ private final Interpolator mFastOutSlowInInterpolator;
+ private int mCurrentWidth;
+ private int mCurrentHeight;
+ private AnimatorSet mAnimator;
+
+ public DividerHandleView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ mPaint.setColor(getResources().getColor(R.color.docked_divider_handle, null));
+ mPaint.setAntiAlias(true);
+ mWidth = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_width);
+ mHeight = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_height);
+ mCurrentWidth = mWidth;
+ mCurrentHeight = mHeight;
+ mCircleDiameter = (mWidth + mHeight) / 3;
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+ android.R.interpolator.fast_out_slow_in);
+ }
+
+ public void setTouching(boolean touching, boolean animate) {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ mAnimator = null;
+ }
+ if (!animate) {
+ if (touching) {
+ mCurrentWidth = mCircleDiameter;
+ mCurrentHeight = mCircleDiameter;
+ } else {
+ mCurrentWidth = mWidth;
+ mCurrentHeight = mHeight;
+ }
+ invalidate();
+ } else {
+ animateToTarget(touching ? mCircleDiameter : mWidth,
+ touching ? mCircleDiameter : mHeight, touching);
+ }
+ }
+
+ private void animateToTarget(int targetWidth, int targetHeight, boolean touching) {
+ ObjectAnimator widthAnimator = ObjectAnimator.ofInt(this, WIDTH_PROPERTY,
+ mCurrentWidth, targetWidth);
+ ObjectAnimator heightAnimator = ObjectAnimator.ofInt(this, HEIGHT_PROPERTY,
+ mCurrentHeight, targetHeight);
+ mAnimator = new AnimatorSet();
+ mAnimator.playTogether(widthAnimator, heightAnimator);
+ mAnimator.setDuration(touching
+ ? DividerView.TOUCH_ANIMATION_DURATION
+ : DividerView.TOUCH_RELEASE_ANIMATION_DURATION);
+ mAnimator.setInterpolator(touching
+ ? DividerView.TOUCH_RESPONSE_INTERPOLATOR
+ : mFastOutSlowInInterpolator);
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimator = null;
+ }
+ });
+ mAnimator.start();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int left = getWidth() / 2 - mCurrentWidth / 2;
+ int top = getHeight() / 2 - mCurrentHeight / 2;
+ int radius = Math.min(mCurrentWidth, mCurrentHeight) / 2;
+ canvas.drawRoundRect(left, top, left + mCurrentWidth, top + mCurrentHeight,
+ radius, radius, mPaint);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
index 69e90cc724f3..e43d531c7a5c 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
@@ -17,25 +17,42 @@
package com.android.systemui.stackdivider;
import android.content.Context;
-import android.util.DisplayMetrics;
-import android.view.DisplayInfo;
+import android.graphics.Rect;
import com.android.systemui.statusbar.FlingAnimationUtils;
import java.util.ArrayList;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-
/**
* Calculates the snap targets and the snap position given a position and a velocity. All positions
* here are to be interpreted as the left/top edge of the divider rectangle.
*/
public class DividerSnapAlgorithm {
+ /**
+ * 3 snap targets: left/top has 16:9 ratio (for videos), 1:1, and right/bottom has 16:9 ratio
+ */
+ private static final int SNAP_MODE_16_9 = 0;
+
+ /**
+ * 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
+ */
+ private static final int SNAP_FIXED_RATIO = 1;
+
+ /**
+ * 1 snap target: 1:1
+ */
+ private static final int SNAP_ONLY_1_1 = 2;
+
private final Context mContext;
private final FlingAnimationUtils mFlingAnimationUtils;
+ private final int mDisplayWidth;
+ private final int mDisplayHeight;
private final int mDividerSize;
- private final ArrayList<SnapTarget> mTargets;
+ private final ArrayList<SnapTarget> mTargets = new ArrayList<>();
+ private final Rect mInsets = new Rect();
+ private final int mSnapMode;
+ private final float mFixedRatio;
/** The first target which is still splitting the screen */
private final SnapTarget mFirstSplitTarget;
@@ -47,11 +64,19 @@ public class DividerSnapAlgorithm {
private final SnapTarget mDismissEndTarget;
public DividerSnapAlgorithm(Context ctx, FlingAnimationUtils flingAnimationUtils,
- int dividerSize, boolean isHorizontalDivision) {
+ int displayWidth, int displayHeight, int dividerSize, boolean isHorizontalDivision,
+ Rect insets) {
mContext = ctx;
mFlingAnimationUtils = flingAnimationUtils;
mDividerSize = dividerSize;
- mTargets = calculateTargets(isHorizontalDivision);
+ mDisplayWidth = displayWidth;
+ mDisplayHeight = displayHeight;
+ mInsets.set(insets);
+ mSnapMode = ctx.getResources().getInteger(
+ com.android.internal.R.integer.config_dockedStackDividerSnapMode);
+ mFixedRatio = ctx.getResources().getFraction(
+ com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1);
+ calculateTargets(isHorizontalDivision);
mFirstSplitTarget = mTargets.get(1);
mLastSplitTarget = mTargets.get(mTargets.size() - 2);
mDismissStartTarget = mTargets.get(0);
@@ -75,6 +100,40 @@ public class DividerSnapAlgorithm {
}
}
+ public float calculateDismissingFraction(int position) {
+ if (position < mFirstSplitTarget.position) {
+ return 1f - (float) position / mFirstSplitTarget.position;
+ } else if (position > mLastSplitTarget.position) {
+ return (float) (position - mLastSplitTarget.position)
+ / (mDismissEndTarget.position - mLastSplitTarget.position);
+ }
+ return 0f;
+ }
+
+ public SnapTarget getClosestDismissTarget(int position) {
+ if (position - mDismissStartTarget.position < mDismissEndTarget.position - position) {
+ return mDismissStartTarget;
+ } else {
+ return mDismissEndTarget;
+ }
+ }
+
+ public SnapTarget getFirstSplitTarget() {
+ return mFirstSplitTarget;
+ }
+
+ public SnapTarget getLastSplitTarget() {
+ return mLastSplitTarget;
+ }
+
+ public SnapTarget getDismissStartTarget() {
+ return mDismissStartTarget;
+ }
+
+ public SnapTarget getDismissEndTarget() {
+ return mDismissEndTarget;
+ }
+
private SnapTarget snap(int position) {
int minIndex = -1;
int minDistance = Integer.MAX_VALUE;
@@ -89,22 +148,61 @@ public class DividerSnapAlgorithm {
return mTargets.get(minIndex);
}
- private ArrayList<SnapTarget> calculateTargets(boolean isHorizontalDivision) {
- ArrayList<SnapTarget> targets = new ArrayList<>();
- DisplayMetrics info = mContext.getResources().getDisplayMetrics();
+ private void calculateTargets(boolean isHorizontalDivision) {
+ mTargets.clear();
int dividerMax = isHorizontalDivision
- ? info.heightPixels
- : info.widthPixels;
+ ? mDisplayHeight
+ : mDisplayWidth;
+ mTargets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
+ switch (mSnapMode) {
+ case SNAP_MODE_16_9:
+ addRatio16_9Targets(isHorizontalDivision);
+ break;
+ case SNAP_FIXED_RATIO:
+ addFixedDivisionTargets(isHorizontalDivision);
+ break;
+ case SNAP_ONLY_1_1:
+ addMiddleTarget(isHorizontalDivision);
+ break;
+ }
+ mTargets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
+ }
- // TODO: Better calculation
- targets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
- targets.add(new SnapTarget((int) (0.38f * dividerMax) - mDividerSize / 2,
+ private void addFixedDivisionTargets(boolean isHorizontalDivision) {
+ int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+ int end = isHorizontalDivision
+ ? mDisplayHeight - mInsets.bottom
+ : mDisplayWidth - mInsets.right;
+ mTargets.add(new SnapTarget((int) (start + mFixedRatio * (end - start)) - mDividerSize / 2,
SnapTarget.FLAG_NONE));
- targets.add(new SnapTarget(dividerMax / 2 - mDividerSize / 2, SnapTarget.FLAG_NONE));
- targets.add(new SnapTarget((int) (0.62f * dividerMax) - mDividerSize / 2,
+ addMiddleTarget(isHorizontalDivision);
+ mTargets.add(new SnapTarget((int) (start + (1 - mFixedRatio) * (end - start))
+ - mDividerSize / 2, SnapTarget.FLAG_NONE));
+ }
+
+ private void addRatio16_9Targets(boolean isHorizontalDivision) {
+ int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+ int end = isHorizontalDivision
+ ? mDisplayHeight - mInsets.bottom
+ : mDisplayWidth - mInsets.right;
+ int startOther = isHorizontalDivision ? mInsets.left : mInsets.top;
+ int endOther = isHorizontalDivision
+ ? mDisplayWidth - mInsets.right
+ : mDisplayHeight - mInsets.bottom;
+ float size = 9.0f / 16.0f * (endOther - startOther);
+ int sizeInt = (int) Math.floor(size);
+ mTargets.add(new SnapTarget(start + sizeInt, SnapTarget.FLAG_NONE));
+ addMiddleTarget(isHorizontalDivision);
+ mTargets.add(new SnapTarget(end - sizeInt - mDividerSize, SnapTarget.FLAG_NONE));
+ }
+
+ private void addMiddleTarget(boolean isHorizontalDivision) {
+ int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+ int end = isHorizontalDivision
+ ? mDisplayHeight - mInsets.bottom
+ : mDisplayWidth - mInsets.right;
+ mTargets.add(new SnapTarget(start + (end - start) / 2 - mDividerSize / 2,
SnapTarget.FLAG_NONE));
- targets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
- return targets;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index c01f1703dab6..109cf4726101 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -21,12 +21,14 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
+import android.app.ActivityManager.StackId;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region.Op;
import android.hardware.display.DisplayManager;
import android.util.AttributeSet;
+import android.util.MathUtils;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.MotionEvent;
@@ -34,8 +36,11 @@ import android.view.PointerIcon;
import android.view.VelocityTracker;
import android.view.View;
import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+import android.view.Window;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -56,15 +61,29 @@ import static android.view.PointerIcon.STYLE_VERTICAL_DOUBLE_ARROW;
public class DividerView extends FrameLayout implements OnTouchListener,
OnComputeInternalInsetsListener {
+ static final long TOUCH_ANIMATION_DURATION = 150;
+ static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
+ static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
+ new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
private static final String TAG = "DividerView";
- private ImageButton mHandle;
+ private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
+ private static final float DIM_START_FRACTION = 0.5f;
+ private static final float DIM_DAMP_FACTOR = 1.7f;
+
+ private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
+ new PathInterpolator(0.5f, 1f, 0.5f, 1f);
+
+ private DividerHandleView mHandle;
private View mBackground;
private int mStartX;
private int mStartY;
private int mStartPosition;
private int mDockSide;
private final int[] mTempInt2 = new int[2];
+ private boolean mMoving;
+ private int mTouchSlop;
private int mDividerInsets;
private int mDisplayWidth;
@@ -73,15 +92,20 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private int mDividerSize;
private int mTouchElevation;
- private final Rect mTmpRect = new Rect();
+ private final Rect mDockedRect = new Rect();
+ private final Rect mDockedTaskRect = new Rect();
+ private final Rect mOtherTaskRect = new Rect();
+ private final Rect mOtherRect = new Rect();
+ private final Rect mDockedInsetRect = new Rect();
+ private final Rect mOtherInsetRect = new Rect();
private final Rect mLastResizeRect = new Rect();
private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance();
private Interpolator mFastOutSlowInInterpolator;
- private final Interpolator mTouchResponseInterpolator =
- new PathInterpolator(0.3f, 0f, 0.1f, 1f);
private DividerWindowManager mWindowManager;
private VelocityTracker mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
+ private DividerSnapAlgorithm mSnapAlgorithm;
+ private final Rect mStableInsets = new Rect();
public DividerView(Context context) {
super(context);
@@ -103,7 +127,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mHandle = (ImageButton) findViewById(R.id.docked_divider_handle);
+ mHandle = (DividerHandleView) findViewById(R.id.docked_divider_handle);
mBackground = findViewById(R.id.docked_divider_background);
mHandle.setOnTouchListener(this);
mDividerWindowWidth = getResources().getDimensionPixelSize(
@@ -115,6 +139,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
R.dimen.docked_stack_divider_lift_elevation);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_slow_in);
+ mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.3f);
updateDisplayInfo();
boolean landscape = getResources().getConfiguration().orientation
@@ -124,6 +149,13 @@ public class DividerView extends FrameLayout implements OnTouchListener,
getViewTreeObserver().addOnComputeInternalInsetsListener(this);
}
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+ insets.getStableInsetRight(), insets.getStableInsetBottom());
+ return super.onApplyWindowInsets(insets);
+ }
+
public void setWindowManager(DividerWindowManager windowManager) {
mWindowManager = windowManager;
}
@@ -132,8 +164,11 @@ public class DividerView extends FrameLayout implements OnTouchListener,
return mWindowManagerProxy;
}
- public boolean startDragging() {
+ public boolean startDragging(boolean animate) {
+ mHandle.setTouching(true, animate);
mDockSide = mWindowManagerProxy.getDockSide();
+ mSnapAlgorithm = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils, mDisplayWidth,
+ mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
if (mDockSide != WindowManager.DOCKED_INVALID) {
mWindowManagerProxy.setResizing(true);
mWindowManager.setSlippery(false);
@@ -145,11 +180,16 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
public void stopDragging(int position, float velocity) {
+ mHandle.setTouching(false, true /* animate */);
fling(position, velocity);
mWindowManager.setSlippery(true);
releaseBackground();
}
+ public DividerSnapAlgorithm getSnapAlgorithm() {
+ return mSnapAlgorithm;
+ }
+
@Override
public boolean onTouch(View v, MotionEvent event) {
convertToScreenCoordinates(event);
@@ -161,19 +201,31 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mStartX = (int) event.getX();
mStartY = (int) event.getY();
getLocationOnScreen(mTempInt2);
- boolean result = startDragging();
+ boolean result = startDragging(true /* animate */);
if (isHorizontalDivision()) {
mStartPosition = mTempInt2[1] + mDividerInsets;
} else {
mStartPosition = mTempInt2[0] + mDividerInsets;
}
+ mMoving = false;
return result;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
int x = (int) event.getX();
int y = (int) event.getY();
- if (mDockSide != WindowManager.DOCKED_INVALID) {
- resizeStack(calculatePosition(x, y));
+ boolean exceededTouchSlop =
+ isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop
+ || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop);
+ if (!mMoving && exceededTouchSlop) {
+ mStartX = x;
+ mStartY = y;
+ mMoving = true;
+ }
+ if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
+ int position = calculatePosition(x, y);
+ SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position,
+ 0 /* velocity */);
+ resizeStack(calculatePosition(x, y), snapTarget.position, snapTarget);
}
break;
case MotionEvent.ACTION_UP:
@@ -187,6 +239,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
int position = calculatePosition(x, y);
stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
: mVelocityTracker.getXVelocity());
+ mMoving = false;
break;
}
return true;
@@ -197,14 +250,16 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
private void fling(int position, float velocity) {
- final SnapTarget snapTarget = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils,
- mDividerSize, isHorizontalDivision()).calculateSnapTarget(position, velocity);
+ final SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
anim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- resizeStack((Integer) animation.getAnimatedValue());
+ resizeStack((Integer) animation.getAnimatedValue(),
+ animation.getAnimatedFraction() == 1f
+ ? TASK_POSITION_SAME
+ : snapTarget.position, snapTarget);
}
});
anim.addListener(new AnimatorListenerAdapter() {
@@ -236,38 +291,43 @@ public class DividerView extends FrameLayout implements OnTouchListener,
} else {
mWindowManagerProxy.maximizeDockedStack();
}
+ mWindowManagerProxy.setResizeDimLayer(false, -1, 0f);
}
private void liftBackground() {
if (isHorizontalDivision()) {
- mBackground.animate().scaleY(1.5f);
+ mBackground.animate().scaleY(1.4f);
} else {
- mBackground.animate().scaleX(1.5f);
+ mBackground.animate().scaleX(1.4f);
}
mBackground.animate()
- .setInterpolator(mTouchResponseInterpolator)
- .setDuration(150)
- .translationZ(mTouchElevation);
+ .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR)
+ .setDuration(TOUCH_ANIMATION_DURATION)
+ .translationZ(mTouchElevation)
+ .start();
// Lift handle as well so it doesn't get behind the background, even though it doesn't
// cast shadow.
mHandle.animate()
- .setInterpolator(mTouchResponseInterpolator)
- .setDuration(150)
- .translationZ(mTouchElevation);
+ .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR)
+ .setDuration(TOUCH_ANIMATION_DURATION)
+ .translationZ(mTouchElevation)
+ .start();
}
private void releaseBackground() {
mBackground.animate()
.setInterpolator(mFastOutSlowInInterpolator)
- .setDuration(200)
+ .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
.translationZ(0)
.scaleX(1f)
- .scaleY(1f);
+ .scaleY(1f)
+ .start();
mHandle.animate()
.setInterpolator(mFastOutSlowInInterpolator)
- .setDuration(200)
- .translationZ(0);
+ .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
+ .translationZ(0)
+ .start();
}
@Override
@@ -332,17 +392,184 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
}
- public void resizeStack(int position) {
- calculateBoundsForPosition(position, mDockSide, mTmpRect);
- if (mTmpRect.equals(mLastResizeRect)) {
+ private 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;
+ default:
+ return WindowManager.DOCKED_INVALID;
+ }
+ }
+
+ private void alignTopLeft(Rect containingRect, Rect rect) {
+ int width = rect.width();
+ int height = rect.height();
+ rect.set(containingRect.left, containingRect.top,
+ containingRect.left + width, containingRect.top + height);
+ }
+
+ private void alignBottomRight(Rect containingRect, Rect rect) {
+ int width = rect.width();
+ int height = rect.height();
+ rect.set(containingRect.right - width, containingRect.bottom - height,
+ containingRect.right, containingRect.bottom);
+ }
+
+ public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
+ calculateBoundsForPosition(position, mDockSide, mDockedRect);
+
+ if (mDockedRect.equals(mLastResizeRect)) {
return;
}
// Make sure shadows are updated
mBackground.invalidate();
- mLastResizeRect.set(mTmpRect);
- mWindowManagerProxy.resizeDockedStack(mTmpRect);
+ mLastResizeRect.set(mDockedRect);
+ if (taskPosition != TASK_POSITION_SAME) {
+ calculateBoundsForPosition(position, invertDockSide(mDockSide), mOtherRect);
+ int dockSideInverted = invertDockSide(mDockSide);
+ int taskPositionDocked =
+ restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
+ int taskPositionOther =
+ restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
+ calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
+ calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
+ alignTopLeft(mDockedRect, mDockedTaskRect);
+ alignTopLeft(mOtherRect, mOtherTaskRect);
+ mDockedInsetRect.set(mDockedTaskRect);
+ mOtherInsetRect.set(mOtherTaskRect);
+ if (dockSideTopLeft(mDockSide)) {
+ alignTopLeft(mDockedRect, mDockedInsetRect);
+ alignBottomRight(mOtherRect, mOtherInsetRect);
+ } else {
+ alignBottomRight(mDockedRect, mDockedInsetRect);
+ alignTopLeft(mOtherRect, mOtherInsetRect);
+ }
+ applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
+ taskPositionDocked);
+ applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
+ taskPositionOther);
+ mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect,
+ mOtherTaskRect, mOtherInsetRect);
+ } else {
+ mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null);
+ }
+ float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
+ fraction = Math.max(0,
+ Math.min((fraction / DIM_START_FRACTION - 1f) / DIM_DAMP_FACTOR, 1f));
+ mWindowManagerProxy.setResizeDimLayer(fraction != 0f,
+ getStackIdForDismissTarget(mSnapAlgorithm.getClosestDismissTarget(position)),
+ fraction);
+ }
+
+ /**
+ * When the snap target is dismissing one side, make sure that the dismissing side doesn't get
+ * 0 size.
+ */
+ private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
+ SnapTarget snapTarget) {
+ if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
+ return mSnapAlgorithm.getFirstSplitTarget().position;
+ } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
+ && dockSideBottomRight(dockSide)) {
+ return mSnapAlgorithm.getLastSplitTarget().position;
+ } else {
+ return taskPosition;
+ }
+ }
+
+ /**
+ * Applies a parallax to the task when dismissing.
+ */
+ private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
+ int position, int taskPosition) {
+ float fraction = Math.min(1, Math.max(0,
+ mSnapAlgorithm.calculateDismissingFraction(position)));
+ SnapTarget dismissTarget = null;
+ SnapTarget splitTarget = null;
+ if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_START
+ || snapTarget == mSnapAlgorithm.getFirstSplitTarget())
+ && dockSideTopLeft(dockSide)) {
+ dismissTarget = mSnapAlgorithm.getDismissStartTarget();
+ splitTarget = mSnapAlgorithm.getFirstSplitTarget();
+ } else if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_END
+ || snapTarget == mSnapAlgorithm.getLastSplitTarget())
+ && dockSideBottomRight(dockSide)) {
+ dismissTarget = mSnapAlgorithm.getDismissEndTarget();
+ splitTarget = mSnapAlgorithm.getLastSplitTarget();
+ }
+ if (dismissTarget != null && fraction > 0f
+ && isDismissing(splitTarget, position, dockSide)) {
+ fraction = calculateParallaxDismissingFraction(fraction);
+ int offsetPosition = (int) (taskPosition +
+ fraction * (dismissTarget.position - splitTarget.position));
+ int width = taskRect.width();
+ int height = taskRect.height();
+ switch (dockSide) {
+ case WindowManager.DOCKED_LEFT:
+ taskRect.left = offsetPosition - width;
+ taskRect.right = offsetPosition;
+ break;
+ case WindowManager.DOCKED_RIGHT:
+ taskRect.left = offsetPosition + mDividerSize;
+ taskRect.right = offsetPosition + width + mDividerSize;
+ break;
+ case WindowManager.DOCKED_TOP:
+ taskRect.top = offsetPosition - height;
+ taskRect.bottom = offsetPosition;
+ break;
+ case WindowManager.DOCKED_BOTTOM:
+ taskRect.top = offsetPosition + mDividerSize;
+ taskRect.bottom = offsetPosition + height + mDividerSize;
+ break;
+ }
+ }
+ }
+
+ /**
+ * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
+ * slowing down parallax effect
+ */
+ private static float calculateParallaxDismissingFraction(float fraction) {
+ return SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
+ }
+
+ private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
+ if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
+ return position < snapTarget.position;
+ } else {
+ return position > snapTarget.position;
+ }
+ }
+
+ private int getStackIdForDismissTarget(SnapTarget dismissTarget) {
+ if (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START &&
+ (mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP)) {
+ return StackId.DOCKED_STACK_ID;
+ } else {
+ return StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+ }
+ }
+
+ /**
+ * @return true if and only if {@code dockSide} is top or left
+ */
+ private static boolean dockSideTopLeft(int dockSide) {
+ return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
+ }
+
+ /**
+ * @return true if and only if {@code dockSide} is bottom or right
+ */
+ private static boolean dockSideBottomRight(int dockSide) {
+ return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 225187455f3f..161f873267d0 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -50,6 +50,9 @@ public class DividerWindowManager {
| FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
mLp.setTitle(WINDOW_TITLE);
+ view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
mWindowManager.addView(view, mLp);
mView = view;
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index ef47d8d1f2d1..2791dfc3972e 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -40,18 +40,41 @@ public class WindowManagerProxy {
private static final WindowManagerProxy sInstance = new WindowManagerProxy();
@GuardedBy("mResizeRect")
- private final Rect mResizeRect = new Rect();
- private final Rect mTmpRect = new Rect();
+ private final Rect mDockedRect = new Rect();
+ private final Rect mTempDockedTaskRect = new Rect();
+ private final Rect mTempDockedInsetRect = new Rect();
+ private final Rect mTempOtherTaskRect = new Rect();
+ private final Rect mTempOtherInsetRect = new Rect();
+
+ private final Rect mTmpRect1 = new Rect();
+ private final Rect mTmpRect2 = new Rect();
+ private final Rect mTmpRect3 = new Rect();
+ private final Rect mTmpRect4 = new Rect();
+ private final Rect mTmpRect5 = new Rect();
+
+ private boolean mDimLayerVisible;
+ private int mDimLayerTargetStack;
+ private float mDimLayerAlpha;
+
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private final Runnable mResizeRunnable = new Runnable() {
@Override
public void run() {
- synchronized (mResizeRect) {
- mTmpRect.set(mResizeRect);
+ synchronized (mDockedRect) {
+ mTmpRect1.set(mDockedRect);
+ mTmpRect2.set(mTempDockedTaskRect);
+ mTmpRect3.set(mTempDockedInsetRect);
+ mTmpRect4.set(mTempOtherTaskRect);
+ mTmpRect5.set(mTempOtherInsetRect);
}
try {
- ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, mTmpRect, true);
+ ActivityManagerNative.getDefault()
+ .resizeDockedStack(mTmpRect1,
+ mTmpRect2.isEmpty() ? null : mTmpRect2,
+ mTmpRect3.isEmpty() ? null : mTmpRect3,
+ mTmpRect4.isEmpty() ? null : mTmpRect4,
+ mTmpRect5.isEmpty() ? null : mTmpRect5);
} catch (RemoteException e) {
Log.w(TAG, "Failed to resize stack: " + e);
}
@@ -80,6 +103,18 @@ public class WindowManagerProxy {
}
};
+ private final Runnable mDimLayerRunnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ WindowManagerGlobal.getWindowManagerService().setResizeDimLayer(mDimLayerVisible,
+ mDimLayerTargetStack, mDimLayerAlpha);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to resize stack: " + e);
+ }
+ }
+ };
+
private WindowManagerProxy() {
}
@@ -87,9 +122,30 @@ public class WindowManagerProxy {
return sInstance;
}
- public void resizeDockedStack(Rect rect) {
- synchronized (mResizeRect) {
- mResizeRect.set(rect);
+ public void resizeDockedStack(Rect docked, Rect tempDockedTaskRect, Rect tempDockedInsetRect,
+ Rect tempOtherTaskRect, Rect tempOtherInsetRect) {
+ synchronized (mDockedRect) {
+ mDockedRect.set(docked);
+ if (tempDockedTaskRect != null) {
+ mTempDockedTaskRect.set(tempDockedTaskRect);
+ } else {
+ mTempDockedTaskRect.setEmpty();
+ }
+ if (tempDockedInsetRect != null) {
+ mTempDockedInsetRect.set(tempDockedInsetRect);
+ } else {
+ mTempDockedInsetRect.setEmpty();
+ }
+ if (tempOtherTaskRect != null) {
+ mTempOtherTaskRect.set(tempOtherTaskRect);
+ } else {
+ mTempOtherTaskRect.setEmpty();
+ }
+ if (tempOtherInsetRect != null) {
+ mTempOtherInsetRect.set(tempOtherInsetRect);
+ } else {
+ mTempOtherInsetRect.setEmpty();
+ }
}
mExecutor.execute(mResizeRunnable);
}
@@ -123,4 +179,11 @@ public class WindowManagerProxy {
}
return DOCKED_INVALID;
}
+
+ public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+ mDimLayerVisible = visible;
+ mDimLayerTargetStack = targetStackId;
+ mDimLayerAlpha = alpha;
+ mExecutor.execute(mDimLayerRunnable);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 3537d3e04504..5906bdac4523 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -148,8 +148,9 @@ public abstract class BaseStatusBar extends SystemUI implements
protected static final int INTERRUPTION_THRESHOLD = 10;
protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
- // Should match the value in PhoneWindowManager
+ // Should match the values in PhoneWindowManager
public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
+ public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
private static final String BANNER_ACTION_CANCEL =
"com.android.systemui.statusbar.banner_action_cancel";
@@ -970,7 +971,7 @@ public abstract class BaseStatusBar extends SystemUI implements
((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
((TextView) row.findViewById(R.id.pkgname)).setText(appname);
- final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
+ final View settingsButton = guts.findViewById(R.id.more_settings);
if (appUid >= 0) {
final int appUidF = appUid;
settingsButton.setOnClickListener(new View.OnClickListener() {
@@ -983,6 +984,13 @@ public abstract class BaseStatusBar extends SystemUI implements
settingsButton.setVisibility(View.GONE);
}
+ row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dismissPopups();
+ }
+ });
+
guts.bindImportance(sbn, row, mNotificationData.getImportance(sbn.getKey()));
}
@@ -1182,7 +1190,6 @@ public abstract class BaseStatusBar extends SystemUI implements
protected void toggleRecents() {
if (mRecents != null) {
- sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
}
}
@@ -1990,7 +1997,8 @@ public abstract class BaseStatusBar extends SystemUI implements
}
catch (RuntimeException e) {
// It failed to apply cleanly.
- Log.w(TAG, "Couldn't reapply views for package " + n.contentView.getPackage(), e);
+ Log.w(TAG, "Couldn't reapply views for package " +
+ notification.getPackageName(), e);
}
}
if (!updateSuccessful) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index f7680a7d81b2..3cc1ab9b42ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -292,6 +292,15 @@ public class NotificationData {
return false;
}
+ public boolean shouldSuppressScreenOn(String key) {
+ if (mRankingMap != null) {
+ mRankingMap.getRanking(key, mTmpRanking);
+ return (mTmpRanking.getSuppressedVisualEffects()
+ & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0;
+ }
+ return false;
+ }
+
public int getImportance(String key) {
if (mRankingMap != null) {
mRankingMap.getRanking(key, mTmpRanking);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
index 58c9722f4af6..d0c14f1fd52b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
@@ -746,7 +746,7 @@ class NavigationBarApps extends LinearLayout
// Launch or bring the activity to front.
final IActivityManager iAm = ActivityManagerNative.getDefault();
try {
- iAm.startActivityFromRecents(taskPersistentId, INVALID_STACK_ID, null /* options */);
+ iAm.startActivityFromRecents(taskPersistentId, null /* options */);
} catch (RemoteException e) {
Slog.e(TAG, "Exception when activating a recent task", e);
} catch (IllegalArgumentException e) {
@@ -1104,6 +1104,10 @@ class NavigationBarApps extends LinearLayout
}
});
}
+
+ @Override
+ public void onActivityPinned() {
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 79bd626efdb6..cc85d0fb8a25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -29,6 +29,8 @@ import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.DividerSnapAlgorithm.SnapTarget;
+import com.android.systemui.stackdivider.DividerView;
import com.android.systemui.tuner.TunerService;
import static android.view.WindowManager.*;
@@ -189,7 +191,7 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
mRecentsComponent.dockTopTask(mDragMode == DRAG_MODE_RECENTS, createMode,
initialBounds);
if (mDragMode == DRAG_MODE_DIVIDER) {
- mDivider.getView().startDragging();
+ mDivider.getView().startDragging(false /* animate */);
}
mDockWindowTouchSlopExceeded = true;
MetricsLogger.action(mContext,
@@ -198,8 +200,10 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
}
} else {
if (mDragMode == DRAG_MODE_DIVIDER) {
- mDivider.getView().resizeStack(
- !mIsVertical ? (int) event.getRawY() : (int) event.getRawX());
+ int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX();
+ SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm()
+ .calculateSnapTarget(position, 0f /* velocity */);
+ mDivider.getView().resizeStack(position, snapTarget.position, snapTarget);
} else if (mDragMode == DRAG_MODE_RECENTS) {
mRecentsComponent.onDraggingInRecents(event.getRawY());
}
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 cddb1fc3a6ad..a3d0ce69bdd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -36,11 +36,13 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
+import android.view.IDockedStackListener.Stub;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -227,8 +229,8 @@ public class NavigationBarView extends LinearLayout {
return mCurrentView;
}
- public View getRecentsButton() {
- return mCurrentView.findViewById(R.id.recent_apps);
+ public KeyButtonView getRecentsButton() {
+ return (KeyButtonView) mCurrentView.findViewById(R.id.recent_apps);
}
public View getMenuButton() {
@@ -455,6 +457,32 @@ public class NavigationBarView extends LinearLayout {
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
updateRTLOrder();
+
+ try {
+ WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(new Stub() {
+ @Override
+ public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
+ }
+
+ @Override
+ public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ updateRecentsIcon(exists);
+ }
+ });
+ }
+ });
+ } 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);
}
public boolean isVertical() {
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 80fcba60e895..78d09e3e03a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1269,19 +1269,26 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
- // Stop screensaver if the notification has a full-screen intent.
- // (like an incoming phone call)
- awakenDreams();
+ if (mNotificationData.shouldSuppressScreenOn(notification.getKey())) {
+ if (DEBUG) {
+ Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
+ }
+ } else {
+ // Stop screensaver if the notification has a full-screen intent.
+ // (like an incoming phone call)
+ awakenDreams();
- // not immersive & a full-screen alert should be shown
- if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
- try {
- EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
- notification.getKey());
- notification.getNotification().fullScreenIntent.send();
- shadeEntry.notifyFullScreenIntentLaunched();
- MetricsLogger.count(mContext, "note_fullscreen", 1);
- } catch (PendingIntent.CanceledException e) {
+ // not immersive & a full-screen alert should be shown
+ if (DEBUG)
+ Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
+ try {
+ EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
+ notification.getKey());
+ notification.getNotification().fullScreenIntent.send();
+ shadeEntry.notifyFullScreenIntentLaunched();
+ MetricsLogger.count(mContext, "note_fullscreen", 1);
+ } catch (PendingIntent.CanceledException e) {
+ }
}
}
addNotificationViews(shadeEntry, ranking);
@@ -4120,32 +4127,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return false;
}
- // Recents
-
- @Override
- protected void showRecents(boolean triggeredFromAltTab) {
- // Set the recents visibility flag
- mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
- notifyUiVisibilityChanged(mSystemUiVisibility);
- super.showRecents(triggeredFromAltTab);
- }
-
- @Override
- protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- // Unset the recents visibility flag
- mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
- notifyUiVisibilityChanged(mSystemUiVisibility);
- super.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
- }
-
- @Override
- protected void toggleRecents() {
- // Toggle the recents visibility flag
- mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE;
- notifyUiVisibilityChanged(mSystemUiVisibility);
- super.toggleRecents();
- }
-
public void updateRecentsVisibility(boolean visible) {
// Update the recents visibility flag
if (visible) {
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 e6d837a06d4d..5c856e89c6ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -18,30 +18,25 @@ package com.android.systemui.statusbar.phone;
import android.app.ActivityManager;
import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
-import android.os.Binder;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Process;
-import android.os.RemoteException;
import android.provider.Settings;
-import android.service.quicksettings.IQSService;
-import android.service.quicksettings.Tile;
import android.text.TextUtils;
import android.util.Log;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.external.CustomTile;
+import com.android.systemui.qs.external.TileServices;
import com.android.systemui.qs.tiles.AirplaneModeTile;
import com.android.systemui.qs.tiles.BatteryTile;
import com.android.systemui.qs.tiles.BluetoothTile;
import com.android.systemui.qs.tiles.CastTile;
import com.android.systemui.qs.tiles.CellularTile;
import com.android.systemui.qs.tiles.ColorInversionTile;
-import com.android.systemui.qs.tiles.CustomTile;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.FlashlightTile;
import com.android.systemui.qs.tiles.HotspotTile;
@@ -76,7 +71,7 @@ import java.util.List;
import java.util.Map;
/** Platform implementation of the quick settings tile host **/
-public final class QSTileHost extends IQSService.Stub implements QSTile.Host, Tunable {
+public final class QSTileHost implements QSTile.Host, Tunable {
private static final String TAG = "QSTileHost";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -100,6 +95,7 @@ public final class QSTileHost extends IQSService.Stub implements QSTile.Host, Tu
private final KeyguardMonitor mKeyguard;
private final SecurityController mSecurity;
private final BatteryController mBattery;
+ private final TileServices mServices;
private final List<Callback> mCallbacks = new ArrayList<>();
@@ -131,6 +127,8 @@ public final class QSTileHost extends IQSService.Stub implements QSTile.Host, Tu
ht.start();
mLooper = ht.getLooper();
+ mServices = new TileServices(this, mLooper);
+
TunerService.get(mContext).addTunable(this, TILES_SETTING);
}
@@ -256,6 +254,10 @@ public final class QSTileHost extends IQSService.Stub implements QSTile.Host, Tu
return mSecurity;
}
+ public TileServices getTileServices() {
+ return mServices;
+ }
+
@Override
public void onTuningChanged(String key, String newValue) {
if (!TILES_SETTING.equals(key)) {
@@ -306,50 +308,6 @@ public final class QSTileHost extends IQSService.Stub implements QSTile.Host, Tu
TextUtils.join(",", specs), ActivityManager.getCurrentUser());
}
- @Override
- public void updateQsTile(Tile tile) throws RemoteException {
- verifyCaller(tile.getComponentName().getPackageName());
- CustomTile customTile = getTileForComponent(tile.getComponentName());
- if (customTile != null) {
- customTile.updateState(tile);
- customTile.refreshState();
- }
- }
-
- @Override
- public void onShowDialog(Tile tile) throws RemoteException {
- verifyCaller(tile.getComponentName().getPackageName());
- CustomTile customTile = getTileForComponent(tile.getComponentName());
- if (customTile != null) {
- customTile.onDialogShown();
- collapsePanels();
- }
- }
-
- private void verifyCaller(String packageName) {
- try {
- int uid = mContext.getPackageManager().getPackageUid(packageName,
- Binder.getCallingUserHandle().getIdentifier());
- if (Binder.getCallingUid() != uid) {
- throw new SecurityException("Component outside caller's uid");
- }
- } catch (NameNotFoundException e) {
- throw new SecurityException(e);
- }
- }
-
- private CustomTile getTileForComponent(ComponentName component) {
- // TODO: Build map for easier lookup.
- for (QSTile<?> qsTile : mTiles.values()) {
- if (qsTile instanceof CustomTile) {
- if (((CustomTile) qsTile).getComponent().equals(component)) {
- return (CustomTile) qsTile;
- }
- }
- }
- return null;
- }
-
public QSTile<?> createTile(String tileSpec) {
if (tileSpec.equals("wifi")) return WifiTile.isSupported(this)
? new WifiTile(this) : null;
@@ -374,7 +332,10 @@ public final class QSTileHost extends IQSService.Stub implements QSTile.Host, Tu
// Intent tiles.
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
- else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
+ else {
+ Log.w(TAG, "Bad tile spec: " + tileSpec);
+ return null;
+ }
}
public static List<String> loadTileSpecs(Context context, String tileList) {
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 1372ccaa824e..a91f6a2879bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -24,7 +24,6 @@ import android.graphics.Rect;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@@ -135,7 +134,6 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
@Override
public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
mNextAlarm = nextAlarm;
- Log.d(TAG, "Got alarm update " + (nextAlarm != null));
if (nextAlarm != null) {
mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
}
@@ -179,10 +177,8 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
private void updateListeners() {
if (mListening) {
- Log.d(TAG, "Listening for Alarms");
mNextAlarmController.addStateChangedCallback(this);
} else {
- Log.d(TAG, "Not listening for Alarms");
mNextAlarmController.removeStateChangedCallback(this);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 1e3b0f1d7b8c..47a4667f29f0 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -32,7 +32,7 @@ import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArrayMap;
-
+import android.util.ArraySet;
import com.android.systemui.BatteryMeterDrawable;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
@@ -41,9 +41,8 @@ import com.android.systemui.SystemUIApplication;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
+import java.util.Set;
public class TunerService extends SystemUI {
@@ -54,7 +53,7 @@ public class TunerService extends SystemUI {
// Map of Uris we listen on to their settings keys.
private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
// Map of settings keys to the listener.
- private final HashMap<String, List<Tunable>> mTunableLookup = new HashMap<>();
+ private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>();
private ContentResolver mContentResolver;
private int mCurrentUser;
@@ -85,7 +84,7 @@ public class TunerService extends SystemUI {
private void addTunable(Tunable tunable, String key) {
if (!mTunableLookup.containsKey(key)) {
- mTunableLookup.put(key, new ArrayList<Tunable>());
+ mTunableLookup.put(key, new ArraySet<Tunable>());
}
mTunableLookup.get(key).add(tunable);
Uri uri = Settings.Secure.getUriFor(key);
@@ -99,7 +98,7 @@ public class TunerService extends SystemUI {
}
public void removeTunable(Tunable tunable) {
- for (List<Tunable> list : mTunableLookup.values()) {
+ for (Set<Tunable> list : mTunableLookup.values()) {
list.remove(tunable);
}
}
@@ -116,7 +115,7 @@ public class TunerService extends SystemUI {
public void reloadSetting(Uri uri) {
String key = mListeningUris.get(uri);
- List<Tunable> tunables = mTunableLookup.get(key);
+ Set<Tunable> tunables = mTunableLookup.get(key);
if (tunables == null) {
return;
}
@@ -153,8 +152,11 @@ public class TunerService extends SystemUI {
private static TunerService sInstance;
public static TunerService get(Context context) {
- SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
- TunerService service = sysUi.getComponent(TunerService.class);
+ TunerService service = null;
+ if (context.getApplicationContext() instanceof SystemUIApplication) {
+ SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
+ service = sysUi.getComponent(TunerService.class);
+ }
if (service == null) {
// Can't get it as a component, must in the tuner, lets just create one for now.
return getStaticService(context);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 9d4ec108aec1..3c63aae9c416 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -648,7 +648,7 @@ public class VolumeDialog {
if (D.BUG) Log.d(TAG, "updateFooterH");
final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE;
final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
- && mAudioManager.isStreamAffectedByRingerMode(mActiveStream);
+ && (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded);
if (wasVisible != visible && !visible) {
prepareForCollapse();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index cd47ac10fbd8..38d8de0d9b15 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -510,7 +510,7 @@ public class ZenModePanel extends LinearLayout {
GregorianCalendar weekRange = new GregorianCalendar();
final long now = weekRange.getTimeInMillis();
setToMidnight(weekRange);
- weekRange.roll(Calendar.DATE, 6);
+ weekRange.add(Calendar.DATE, 6);
final long nextAlarmMs = mController.getNextAlarm();
if (nextAlarmMs > 0) {
GregorianCalendar nextAlarm = new GregorianCalendar();
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index c21af2457030..282560100cb4 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -19,10 +19,16 @@
<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.MANAGE_USERS" />
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="com.android.systemui.screenshot.ScreenshotStubActivity" />
+
+ <service
+ android:name="com.android.systemui.qs.external.TileLifecycleManagerTests$FakeTileService"
+ android:process=":killable" />
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
new file mode 100644
index 000000000000..6ebf488937f9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
@@ -0,0 +1,318 @@
+/*
+ * 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.qs.external;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.test.AndroidTestCase;
+import android.util.ArraySet;
+import android.util.Log;
+
+public class TileLifecycleManagerTests extends AndroidTestCase {
+ public static final String TILE_UPDATE_BROADCAST = "com.android.systemui.tests.TILE_UPDATE";
+ public static final String EXTRA_CALLBACK = "callback";
+
+ private HandlerThread mThread;
+ private Handler mHandler;
+ private TileLifecycleManager mStateManager;
+ private final Object mBroadcastLock = new Object();
+ private final ArraySet<String> mCallbacks = new ArraySet<>();
+ private boolean mBound;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mThread = new HandlerThread("TestThread");
+ mThread.start();
+ mHandler = new Handler(mThread.getLooper());
+ mStateManager = new TileLifecycleManager(mHandler, getContext(),
+ new Intent(mContext, FakeTileService.class), new UserHandle(UserHandle.myUserId()));
+ mCallbacks.clear();
+ getContext().registerReceiver(mReceiver, new IntentFilter(TILE_UPDATE_BROADCAST));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if (mBound) {
+ unbindService();
+ }
+ mThread.quit();
+ getContext().unregisterReceiver(mReceiver);
+ }
+
+ public void testSync() {
+ syncWithHandler();
+ }
+
+ public void testBind() {
+ bindService();
+ waitForCallback("onCreate");
+ }
+
+ public void testUnbind() {
+ bindService();
+ waitForCallback("onCreate");
+ unbindService();
+ waitForCallback("onDestroy");
+ }
+
+ public void testTileServiceCallbacks() {
+ bindService();
+ waitForCallback("onCreate");
+
+ mStateManager.onTileAdded();
+ waitForCallback("onTileAdded");
+ mStateManager.onStartListening();
+ waitForCallback("onStartListening");
+ mStateManager.onClick(null);
+ waitForCallback("onClick");
+ mStateManager.onStopListening();
+ waitForCallback("onStopListening");
+ mStateManager.onTileRemoved();
+ waitForCallback("onTileRemoved");
+
+ unbindService();
+ }
+
+ public void testAddedBeforeBind() {
+ mStateManager.onTileAdded();
+
+ bindService();
+ waitForCallback("onCreate");
+ waitForCallback("onTileAdded");
+ }
+
+ public void testListeningBeforeBind() {
+ mStateManager.onTileAdded();
+ mStateManager.onStartListening();
+
+ bindService();
+ waitForCallback("onCreate");
+ waitForCallback("onTileAdded");
+ waitForCallback("onStartListening");
+ }
+
+ public void testClickBeforeBind() {
+ mStateManager.onTileAdded();
+ mStateManager.onStartListening();
+ mStateManager.onClick(null);
+
+ bindService();
+ waitForCallback("onCreate");
+ waitForCallback("onTileAdded");
+ waitForCallback("onStartListening");
+ waitForCallback("onClick");
+ }
+
+ public void testListeningNotListeningBeforeBind() {
+ mStateManager.onTileAdded();
+ mStateManager.onStartListening();
+ mStateManager.onStopListening();
+
+ bindService();
+ waitForCallback("onCreate");
+ unbindService();
+ waitForCallback("onDestroy");
+ assertFalse(mCallbacks.contains("onStartListening"));
+ }
+
+ public void testNoClickOfNotListeningAnymore() {
+ mStateManager.onTileAdded();
+ mStateManager.onStartListening();
+ mStateManager.onClick(null);
+ mStateManager.onStopListening();
+
+ bindService();
+ waitForCallback("onCreate");
+ unbindService();
+ waitForCallback("onDestroy");
+ assertFalse(mCallbacks.contains("onClick"));
+ }
+
+ public void testComponentEnabling() {
+ mStateManager.onTileAdded();
+ mStateManager.onStartListening();
+
+ PackageManager pm = getContext().getPackageManager();
+ pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
+
+ bindService();
+ assertTrue(mStateManager.mReceiverRegistered);
+
+ pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
+ waitForCallback("onCreate");
+ }
+
+ public void testKillProcess() {
+ mStateManager.onStartListening();
+ bindService();
+ waitForCallback("onCreate");
+ waitForCallback("onStartListening");
+
+ getContext().sendBroadcast(new Intent(FakeTileService.ACTION_KILL));
+
+ waitForCallback("onCreate");
+ waitForCallback("onStartListening");
+ }
+
+ private void bindService() {
+ mBound = true;
+ mStateManager.setBindService(true);
+ }
+
+ private void unbindService() {
+ mBound = false;
+ mStateManager.setBindService(false);
+ }
+
+ private void waitForCallback(String callback) {
+ for (int i = 0; i < 25; i++) {
+ if (mCallbacks.contains(callback)) {
+ mCallbacks.remove(callback);
+ return;
+ }
+ synchronized (mBroadcastLock) {
+ try {
+ mBroadcastLock.wait(500);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ if (mCallbacks.contains(callback)) {
+ mCallbacks.remove(callback);
+ return;
+ }
+ fail("Didn't receive callback: " + callback);
+ }
+
+ private void syncWithHandler() {
+ final Object lock = new Object();
+ synchronized (lock) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (lock) {
+ lock.notify();
+ }
+ }
+ });
+ try {
+ lock.wait(5000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mCallbacks.add(intent.getStringExtra(EXTRA_CALLBACK));
+ synchronized (mBroadcastLock) {
+ mBroadcastLock.notify();
+ }
+ }
+ };
+
+ public static class FakeTileService extends Service {
+ public static final String ACTION_KILL = "com.android.systemui.test.KILL";
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return new IQSTileService.Stub() {
+
+ @Override
+ public void setQSService(IQSService service) {
+
+ }
+
+ @Override
+ public void setQSTile(Tile tile) throws RemoteException {
+ }
+
+ @Override
+ public void onTileAdded() throws RemoteException {
+ sendCallback("onTileAdded");
+ }
+
+ @Override
+ public void onTileRemoved() throws RemoteException {
+ sendCallback("onTileRemoved");
+ }
+
+ @Override
+ public void onStartListening() throws RemoteException {
+ sendCallback("onStartListening");
+ }
+
+ @Override
+ public void onStopListening() throws RemoteException {
+ sendCallback("onStopListening");
+ }
+
+ @Override
+ public void onClick(IBinder iBinder) throws RemoteException {
+ sendCallback("onClick");
+ }
+ };
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ registerReceiver(mReceiver, new IntentFilter(ACTION_KILL));
+ sendCallback("onCreate");
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mReceiver);
+ sendCallback("onDestroy");
+ }
+
+ private void sendCallback(String callback) {
+ Log.d("TileLifecycleManager", "Relaying: " + callback);
+ sendBroadcast(new Intent(TILE_UPDATE_BROADCAST)
+ .putExtra(EXTRA_CALLBACK, callback));
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_KILL.equals(intent.getAction())) {
+ Process.killProcess(Process.myPid());
+ }
+ }
+ };
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
new file mode 100644
index 000000000000..4586c2813f72
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
@@ -0,0 +1,101 @@
+/*
+ * 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.qs.external;
+
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.service.quicksettings.TileService;
+import com.android.systemui.SysuiTestCase;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+public class TileServiceManagerTests extends SysuiTestCase {
+
+ private TileServices mTileServices;
+ private TileLifecycleManager mTileLifecycle;
+ private HandlerThread mThread;
+ private Handler mHandler;
+ private TileServiceManager mTileServiceManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mThread = new HandlerThread("TestThread");
+ mThread.start();
+ mHandler = new Handler(mThread.getLooper());
+ mTileServices = Mockito.mock(TileServices.class);
+ Mockito.when(mTileServices.getContext()).thenReturn(mContext);
+ mTileLifecycle = Mockito.mock(TileLifecycleManager.class);
+ ComponentName componentName = new ComponentName(mContext,
+ TileServiceManagerTests.class);
+ Mockito.when(mTileLifecycle.getComponent()).thenReturn(componentName);
+ mContext.getSharedPreferences(TileServiceManager.PREFS_FILE, 0).edit()
+ .putInt(componentName.flattenToString(), TileService.TILE_MODE_PASSIVE).commit();
+ mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mTileLifecycle);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ mThread.quit();
+ }
+
+ public void testSetBindRequested() {
+ // Request binding.
+ mTileServiceManager.setBindRequested(true);
+ mTileServiceManager.setLastUpdate(0);
+ mTileServiceManager.calculateBindPriority(5);
+ Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+ assertEquals(5, mTileServiceManager.getBindPriority());
+
+ // Verify same state doesn't trigger recalculating for no reason.
+ mTileServiceManager.setBindRequested(true);
+ Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+
+ mTileServiceManager.setBindRequested(false);
+ mTileServiceManager.calculateBindPriority(5);
+ Mockito.verify(mTileServices, Mockito.times(3)).recalculateBindAllowance();
+ assertEquals(Integer.MIN_VALUE, mTileServiceManager.getBindPriority());
+ }
+
+ public void testPendingClickPriority() {
+ Mockito.when(mTileLifecycle.hasPendingClick()).thenReturn(true);
+ mTileServiceManager.calculateBindPriority(0);
+ assertEquals(Integer.MAX_VALUE, mTileServiceManager.getBindPriority());
+ }
+
+ public void testBind() {
+ // Trigger binding requested and allowed.
+ mTileServiceManager.setBindRequested(true);
+ mTileServiceManager.setBindAllowed(true);
+
+ ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mTileLifecycle, Mockito.times(1)).setBindService(captor.capture());
+ assertTrue((boolean) captor.getValue());
+
+ mTileServiceManager.setBindRequested(false);
+ mTileServiceManager.calculateBindPriority(0);
+ // Priority shouldn't disappear after the request goes away if we just bound, instead
+ // it sticks around to avoid thrashing a bunch of processes.
+ assertEquals(Integer.MAX_VALUE - 1, mTileServiceManager.getBindPriority());
+
+ mTileServiceManager.setBindAllowed(false);
+ captor = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mTileLifecycle, Mockito.times(2)).setBindService(captor.capture());
+ assertFalse((boolean) captor.getValue());
+ }
+}
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
new file mode 100644
index 000000000000..7a3ce878b8cc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
@@ -0,0 +1,108 @@
+/*
+ * 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.qs.external;
+
+import android.content.ComponentName;
+import android.os.Looper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+
+public class TileServicesTests extends SysuiTestCase {
+ private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
+
+ private TileServices mTileService;
+ private ArrayList<TileServiceManager> mManagers;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mManagers = new ArrayList<>();
+ QSTileHost host = new QSTileHost(mContext, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null);
+ mTileService = new TestTileServices(host, Looper.myLooper());
+ }
+
+ public void testRecalculateBindAllowance() {
+ // Add some fake tiles.
+ for (int i = 0; i < NUM_FAKES; i++) {
+ mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+ }
+ assertEquals(NUM_FAKES, mManagers.size());
+
+ for (int i = 0; i < NUM_FAKES; i++) {
+ Mockito.when(mManagers.get(i).getBindPriority()).thenReturn(i);
+ }
+ mTileService.recalculateBindAllowance();
+ for (int i = 0; i < NUM_FAKES; i++) {
+ Mockito.verify(mManagers.get(i), Mockito.times(1)).calculateBindPriority(
+ Mockito.anyLong());
+ ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+ assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.DEFAULT_MAX_BOUND),
+ (boolean) captor.getValue());
+ }
+ }
+
+ public void testSetMemoryPressure() {
+ testRecalculateBindAllowance();
+ mTileService.setMemoryPressure(true);
+
+ for (int i = 0; i < NUM_FAKES; i++) {
+ ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mManagers.get(i), Mockito.times(2)).setBindAllowed(captor.capture());
+
+ assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.REDUCED_MAX_BOUND),
+ (boolean) captor.getValue());
+ }
+ }
+
+ public void testCalcFew() {
+ for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+ mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+ }
+ mTileService.recalculateBindAllowance();
+
+ for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+ // Shouldn't get bind prioirities calculated when there are less than the max services.
+ Mockito.verify(mManagers.get(i), Mockito.never()).calculateBindPriority(
+ Mockito.anyLong());
+
+ // All should be bound since there are less than the max services.
+ ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+ assertTrue(captor.getValue());
+ }
+ }
+
+ private class TestTileServices extends TileServices {
+ public TestTileServices(QSTileHost host, Looper looper) {
+ super(host, looper);
+ }
+
+ @Override
+ protected TileServiceManager onCreateTileService(ComponentName component) {
+ TileServiceManager manager = Mockito.mock(TileServiceManager.class);
+ mManagers.add(manager);
+ return manager;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index f329cff2c98d..3c91423a5d11 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -268,7 +268,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
int sysUiUid = -1;
try {
- sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui",
+ sysUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui",
UserHandle.USER_SYSTEM);
} catch (PackageManager.NameNotFoundException e) {
// Some platforms, such as wearables do not have a system ui.
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index f5ed83ed5f1d..8d707d610ae0 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1326,7 +1326,7 @@ public class DeviceIdleController extends SystemService
void addPowerSaveTempWhitelistAppInternal(int callingUid, String packageName,
long duration, int userId, boolean sync, String reason) {
try {
- int uid = getContext().getPackageManager().getPackageUid(packageName, userId);
+ int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId);
int appId = UserHandle.getAppId(uid);
addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration, sync, reason);
} catch (NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index e8b90d893ec5..1249c8c681b5 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -94,7 +94,7 @@ public class PersistentDataBlockService extends SystemService {
PackageManager pm = mContext.getPackageManager();
int allowedUid = -1;
try {
- allowedUid = pm.getPackageUid(allowedPackage, userHandle);
+ allowedUid = pm.getPackageUidAsUser(allowedPackage, userHandle);
} catch (PackageManager.NameNotFoundException e) {
// not expected
Slog.e(TAG, "not able to find package " + allowedPackage, e);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index ca5212ab2a5a..aa9944278134 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -37,7 +37,9 @@ import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentValues;
@@ -82,6 +84,7 @@ import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.FgThread;
+import com.android.server.LocalServices;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
@@ -830,7 +833,8 @@ public class AccountManagerService
throw new SecurityException(msg);
}
- if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
+ if (!canUserModifyAccounts(userId, callingUid) ||
+ !canUserModifyAccountsForType(userId, account.type, callingUid)) {
return false;
}
@@ -1259,7 +1263,7 @@ public class AccountManagerService
account.type);
throw new SecurityException(msg);
}
- if (!canUserModifyAccounts(userId)) {
+ if (!canUserModifyAccounts(userId, callingUid)) {
try {
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
"User cannot modify accounts");
@@ -1267,7 +1271,7 @@ public class AccountManagerService
}
return;
}
- if (!canUserModifyAccountsForType(userId, account.type)) {
+ if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
try {
response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
"User cannot modify accounts of this type (policy).");
@@ -1321,9 +1325,6 @@ public class AccountManagerService
throw new SecurityException(msg);
}
UserAccounts accounts = getUserAccountsForCaller();
- if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
- return false;
- }
logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
long identityToken = clearCallingIdentity();
try {
@@ -2146,8 +2147,9 @@ public class AccountManagerService
if (accountType == null) throw new IllegalArgumentException("accountType is null");
// Is user disallowed from modifying accounts?
- int userId = Binder.getCallingUserHandle().getIdentifier();
- if (!canUserModifyAccounts(userId)) {
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ if (!canUserModifyAccounts(userId, uid)) {
try {
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
"User is not allowed to add an account!");
@@ -2156,7 +2158,7 @@ public class AccountManagerService
showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
return;
}
- if (!canUserModifyAccountsForType(userId, accountType)) {
+ if (!canUserModifyAccountsForType(userId, accountType, uid)) {
try {
response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
"User cannot modify accounts of this type (policy).");
@@ -2168,7 +2170,6 @@ public class AccountManagerService
}
final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
options.putInt(AccountManager.KEY_CALLER_UID, uid);
options.putInt(AccountManager.KEY_CALLER_PID, pid);
@@ -2230,7 +2231,7 @@ public class AccountManagerService
}
// Is user disallowed from modifying accounts?
- if (!canUserModifyAccounts(userId)) {
+ if (!canUserModifyAccounts(userId, callingUid)) {
try {
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
"User is not allowed to add an account!");
@@ -2239,7 +2240,7 @@ public class AccountManagerService
showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
return;
}
- if (!canUserModifyAccountsForType(userId, accountType)) {
+ if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
try {
response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
"User cannot modify accounts of this type (policy).");
@@ -2310,8 +2311,9 @@ public class AccountManagerService
throw new IllegalArgumentException("accountType is null");
}
- int userId = Binder.getCallingUserHandle().getIdentifier();
- if (!canUserModifyAccounts(userId)) {
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ if (!canUserModifyAccounts(userId, uid)) {
try {
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
"User is not allowed to add an account!");
@@ -2320,7 +2322,7 @@ public class AccountManagerService
showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
return;
}
- if (!canUserModifyAccountsForType(userId, accountType)) {
+ if (!canUserModifyAccountsForType(userId, accountType, uid)) {
try {
response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
"User cannot modify accounts of this type (policy).");
@@ -2332,7 +2334,6 @@ public class AccountManagerService
}
final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
options.putInt(AccountManager.KEY_CALLER_UID, uid);
options.putInt(AccountManager.KEY_CALLER_PID, pid);
@@ -2497,8 +2498,9 @@ public class AccountManagerService
throw new IllegalArgumentException("sessionBundle is empty");
}
- int userId = Binder.getCallingUserHandle().getIdentifier();
- if (!canUserModifyAccounts(userId)) {
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ if (!canUserModifyAccounts(userId, uid)) {
sendErrorResponse(response,
AccountManager.ERROR_CODE_USER_RESTRICTED,
"User is not allowed to add an account!");
@@ -2507,7 +2509,6 @@ public class AccountManagerService
}
final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
final Bundle decryptedBundle;
final String accountType;
// First decrypt session bundle to get account type for checking permission.
@@ -2554,7 +2555,7 @@ public class AccountManagerService
return;
}
- if (!canUserModifyAccountsForType(userId, accountType)) {
+ if (!canUserModifyAccountsForType(userId, accountType, uid)) {
sendErrorResponse(
response,
AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
@@ -4319,7 +4320,11 @@ public class AccountManagerService
}
}
- private boolean canUserModifyAccounts(int userId) {
+ private boolean canUserModifyAccounts(int userId, int callingUid) {
+ // the managing app can always modify accounts
+ if (isProfileOwner(callingUid)) {
+ return true;
+ }
if (getUserManager().getUserRestrictions(new UserHandle(userId))
.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
return false;
@@ -4327,7 +4332,11 @@ public class AccountManagerService
return true;
}
- private boolean canUserModifyAccountsForType(int userId, String accountType) {
+ private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
+ // the managing app can always modify accounts
+ if (isProfileOwner(callingUid)) {
+ return true;
+ }
DevicePolicyManager dpm = (DevicePolicyManager) mContext
.getSystemService(Context.DEVICE_POLICY_SERVICE);
String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
@@ -4342,6 +4351,13 @@ public class AccountManagerService
return true;
}
+ private boolean isProfileOwner(int uid) {
+ final DevicePolicyManagerInternal dpmi =
+ LocalServices.getService(DevicePolicyManagerInternal.class);
+ return (dpmi != null)
+ && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ }
+
@Override
public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
throws RemoteException {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 552db7ddd3cd..fb62a95516c6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -244,6 +244,7 @@ import libcore.util.EmptyArray;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -257,6 +258,7 @@ import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
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.WAIT_FOR_DEBUGGER;
@@ -1445,6 +1447,7 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int SYSTEM_USER_UNLOCK_MSG = 61;
static final int LOG_STACK_STATE = 62;
static final int VR_MODE_CHANGE_MSG = 63;
+ static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 64;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1998,9 +2001,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
case NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG: {
synchronized (ActivityManagerService.this) {
- int i = mTaskStackListeners.beginBroadcast();
- while (i > 0) {
- i--;
+ for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
try {
// Make a one-way callback to the listener
mTaskStackListeners.getBroadcastItem(i).onTaskStackChanged();
@@ -2012,6 +2013,20 @@ public final class ActivityManagerService extends ActivityManagerNative
}
break;
}
+ case NOTIFY_ACTIVITY_PINNED_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).onActivityPinned();
+ } 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;
@@ -2743,9 +2758,15 @@ public final class ActivityManagerService extends ActivityManagerNative
return mAppBindArgs;
}
- final void setFocusedActivityLocked(ActivityRecord r, String reason) {
+ boolean setFocusedActivityLocked(ActivityRecord r, String reason) {
if (r == null || mFocusedActivity == r) {
- return;
+ return false;
+ }
+
+ if (!r.isFocusable()) {
+ if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
+ "setFocusedActivityLocked: unfocusable r=" + r);
+ return false;
}
if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
@@ -2783,7 +2804,7 @@ public final class ActivityManagerService extends ActivityManagerNative
finishVoiceTask(last.task.voiceSession);
}
}
- if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
+ if (mStackSupervisor.moveActivityStackToFront(r, reason + " setFocusedActivity")) {
mWindowManager.setFocusedApp(r.appToken, true);
}
applyUpdateLockStateLocked(r);
@@ -2799,23 +2820,35 @@ public final class ActivityManagerService extends ActivityManagerNative
mFocusedActivity == null ? -1 : mFocusedActivity.userId,
mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName,
reason);
+ return true;
}
- final void clearFocusedActivity(ActivityRecord r) {
- if (mFocusedActivity == r) {
- ActivityStack stack = mStackSupervisor.getFocusedStack();
- if (stack != null) {
- ActivityRecord top = stack.topActivity();
- if (top != null && top.userId != mLastFocusedUserId) {
- mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
- mHandler.sendMessage(mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG,
- top.userId, 0));
- mLastFocusedUserId = top.userId;
- }
+ final void resetFocusedActivityIfNeededLocked(ActivityRecord goingAway) {
+ if (mFocusedActivity != goingAway) {
+ return;
+ }
+
+ final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
+ if (focusedStack != null) {
+ final ActivityRecord top = focusedStack.topActivity();
+ if (top != null && top.userId != mLastFocusedUserId) {
+ mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
+ mHandler.sendMessage(
+ mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG, top.userId, 0));
+ mLastFocusedUserId = top.userId;
}
- mFocusedActivity = null;
- EventLogTags.writeAmFocusedActivity(-1, "NULL", "clearFocusedActivity");
}
+
+ // Try to move focus to another activity if possible.
+ if (setFocusedActivityLocked(
+ focusedStack.topRunningActivityLocked(), "resetFocusedActivityIfNeeded")) {
+ return;
+ }
+
+ if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "resetFocusedActivityIfNeeded: Setting focus to NULL "
+ + "prev mFocusedActivity=" + mFocusedActivity + " goingAway=" + goingAway);
+ mFocusedActivity = null;
+ EventLogTags.writeAmFocusedActivity(-1, "NULL", "resetFocusedActivityIfNeeded");
}
@Override
@@ -2827,7 +2860,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ActivityRecord r = stack.topRunningActivityLocked();
if (r != null) {
setFocusedActivityLocked(r, "setFocusedStack");
- mStackSupervisor.resumeTopActivitiesLocked(stack, null, null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
@@ -2844,7 +2877,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ActivityRecord r = task.topRunningActivityLocked();
if (r != null) {
setFocusedActivityLocked(r, "setFocusedTask");
- mStackSupervisor.resumeTopActivitiesLocked(task.stack, null, null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
@@ -2856,7 +2889,8 @@ public final class ActivityManagerService extends ActivityManagerNative
/** Sets the task stack listener that gets callbacks when a task stack changes. */
@Override
public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException {
- synchronized (ActivityManagerService.this) {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "registerTaskStackListener()");
+ synchronized (this) {
if (listener != null) {
mTaskStackListeners.register(listener);
}
@@ -3590,7 +3624,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Intent getHomeIntent() {
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
- intent.addFlags(Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED);
+ intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
intent.addCategory(Intent.CATEGORY_HOME);
}
@@ -4342,7 +4376,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
- public final int startActivityFromRecents(int taskId, int launchStackId, Bundle bOptions) {
+ public final int startActivityFromRecents(int taskId, Bundle bOptions) {
if (checkCallingPermission(START_TASKS_FROM_RECENTS) != PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: startActivityFromRecents called without " +
START_TASKS_FROM_RECENTS;
@@ -4351,24 +4385,28 @@ public final class ActivityManagerService extends ActivityManagerNative
}
final long origId = Binder.clearCallingIdentity();
try {
- return startActivityFromRecentsInner(taskId, launchStackId, bOptions);
+ return startActivityFromRecentsInner(taskId, bOptions);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
- final int startActivityFromRecentsInner(int taskId, int launchStackId, Bundle bOptions) {
+ final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
final TaskRecord task;
final int callingUid;
final String callingPackage;
final Intent intent;
final int userId;
synchronized (this) {
+ final ActivityOptions activityOptions = (bOptions != null)
+ ? new ActivityOptions(bOptions) : null;
+ final int launchStackId = (activityOptions != null)
+ ? activityOptions.getLaunchStackId() : INVALID_STACK_ID;
+
if (launchStackId == HOME_STACK_ID) {
throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
+ taskId + " can't be launch in the home stack.");
}
-
task = mStackSupervisor.anyTaskForIdLocked(taskId, RESTORE_FROM_RECENTS, launchStackId);
if (task == null) {
throw new IllegalArgumentException(
@@ -4376,10 +4414,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (launchStackId != INVALID_STACK_ID) {
- if (launchStackId == DOCKED_STACK_ID && bOptions != null) {
- ActivityOptions activityOptions = new ActivityOptions(bOptions);
- mWindowManager.setDockedStackCreateState(activityOptions.getDockCreateMode(),
- null /* initialBounds */);
+ if (launchStackId == DOCKED_STACK_ID && activityOptions != null) {
+ mWindowManager.setDockedStackCreateState(
+ activityOptions.getDockCreateMode(), null /* initialBounds */);
}
if (task.stack.mStackId != launchStackId) {
mStackSupervisor.moveTaskToStackLocked(
@@ -4388,7 +4425,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- if (task.getRootActivity() != null) {
+ // If the user must confirm credentials (e.g. when first launching a work app and the
+ // Work Challenge is present) let startActivityInPackage handle the intercepting.
+ if (!mUserController.shouldConfirmCredentials(task.userId)
+ && task.getRootActivity() != null) {
moveTaskToFrontLocked(task.taskId, 0, bOptions);
return ActivityManager.START_TASK_TO_FRONT;
}
@@ -4473,7 +4513,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (config != null) {
r.frozenBeforeDestroy = true;
if (!updateConfigurationLocked(config, r, false)) {
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
Binder.restoreCallingIdentity(origId);
@@ -4811,12 +4851,11 @@ public final class ActivityManagerService extends ActivityManagerNative
finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
}
- if (!restarting && hasVisibleActivities && !mStackSupervisor.resumeTopActivitiesLocked()) {
- // If there was nothing to resume, and we are not already
- // restarting this process, but there is a visible activity that
- // is hosted by the process... then make sure all visible
- // activities are running, taking care of restarting this
- // process.
+ if (!restarting && hasVisibleActivities
+ && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
+ // If there was nothing to resume, and we are not already restarting this process, but
+ // there is a visible activity that is hosted by the process... then make sure all
+ // visible activities are running, taking care of restarting this process.
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
}
@@ -5873,7 +5912,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Clean-up disabled activities.
if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
packageName, disabledClasses, true, false, userId) && mBooted) {
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
mStackSupervisor.scheduleIdleLocked();
}
@@ -6061,7 +6100,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
if (mBooted) {
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
mStackSupervisor.scheduleIdleLocked();
}
}
@@ -6736,6 +6775,15 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
+ public final void activityRelaunched(IBinder token) {
+ final long origId = Binder.clearCallingIdentity();
+ synchronized (this) {
+ mStackSupervisor.activityRelaunchedLocked(token);
+ }
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ @Override
public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Report configuration: " + token + " "
@@ -7257,7 +7305,7 @@ public final class ActivityManagerService extends ActivityManagerNative
+ "Can't find activity for token=" + token);
}
- if (!r.info.supportsPip) {
+ if (!r.supportsPictureInPicture()) {
throw new IllegalArgumentException("enterPictureInPictureMode: "
+ "Picture-In-Picture not supported for r=" + r);
}
@@ -8230,6 +8278,18 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ @Override
+ public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) {
+ enforceNotIsolatedCaller("getUriPermissionOwnerForActivity");
+ synchronized(this) {
+ ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
+ if (r == null) {
+ throw new IllegalArgumentException("Activity does not exist; token="
+ + activityToken);
+ }
+ return r.getUriPermissionsLocked().getExternalTokenLocked();
+ }
+ }
/**
* @param uri This uri must NOT contain an embedded userId.
* @param sourceUserId The userId in which the uri is to be resolved.
@@ -8982,15 +9042,14 @@ public final class ActivityManagerService extends ActivityManagerNative
task.mResizeable = resizeable;
mWindowManager.setTaskResizeable(taskId, resizeable);
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
@Override
public void resizeTask(int taskId, Rect bounds, int resizeMode) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "resizeTask()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -9040,8 +9099,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public Rect getTaskBounds(int taskId) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "getTaskBounds()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getTaskBounds()");
long ident = Binder.clearCallingIdentity();
Rect rect = new Rect();
try {
@@ -9343,8 +9401,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
IActivityContainerCallback callback) throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "createActivityContainer()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createActivityContainer()");
synchronized (this) {
if (parentActivityToken == null) {
throw new IllegalArgumentException("parent token must not be null");
@@ -9362,8 +9419,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void deleteActivityContainer(IActivityContainer container) throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "deleteActivityContainer()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "deleteActivityContainer()");
synchronized (this) {
mStackSupervisor.deleteActivityContainer(container);
}
@@ -9371,8 +9427,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "createStackOnDisplay()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createStackOnDisplay()");
synchronized (this) {
final int stackId = mStackSupervisor.getNextStackId();
final ActivityStack stack =
@@ -9432,8 +9487,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "moveTaskToStack()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
if (stackId == HOME_STACK_ID) {
throw new IllegalArgumentException(
"moveTaskToStack: Attempt to move task " + taskId + " to home stack");
@@ -9468,8 +9522,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
Rect initialBounds) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "moveTaskToDockedStack()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()");
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
@@ -9495,8 +9548,7 @@ public final class ActivityManagerService extends ActivityManagerNative
*/
@Override
public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "moveTopActivityToPinnedStack()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTopActivityToPinnedStack()");
synchronized (this) {
if (!mSupportsPictureInPicture) {
throw new IllegalStateException("moveTopActivityToPinnedStack:"
@@ -9514,13 +9566,13 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "resizeStack()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
mStackSupervisor.resizeStackLocked(
- stackId, bounds, !PRESERVE_WINDOWS, allowResizeInDockedMode);
+ stackId, bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+ !PRESERVE_WINDOWS, allowResizeInDockedMode);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -9528,9 +9580,26 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
- public void positionTaskInStack(int taskId, int stackId, int position) {
+ public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+ Rect tempDockedTaskInsetBounds,
+ Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) {
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "positionTaskInStack()");
+ "resizeDockedStack()");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ mStackSupervisor.resizeDockedStackLocked(dockedBounds, tempDockedTaskBounds,
+ tempDockedTaskInsetBounds, tempOtherTaskBounds, tempOtherTaskInsetBounds,
+ PRESERVE_WINDOWS);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void positionTaskInStack(int taskId, int stackId, int position) {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
if (stackId == HOME_STACK_ID) {
throw new IllegalArgumentException(
"positionTaskInStack: Attempt to change the position of task "
@@ -9551,8 +9620,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public List<StackInfo> getAllStackInfos() {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "getAllStackInfos()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -9565,8 +9633,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public StackInfo getStackInfo(int stackId) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "getStackInfo()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -9579,8 +9646,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public boolean isInHomeStack(int taskId) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "getStackInfo()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -9694,8 +9760,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void startLockTaskModeOnCurrent() throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "startLockTaskModeOnCurrent");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startLockTaskModeOnCurrent");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -9747,8 +9812,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void stopLockTaskModeOnCurrent() throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "stopLockTaskModeOnCurrent");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopLockTaskModeOnCurrent");
long ident = Binder.clearCallingIdentity();
try {
stopLockTaskMode();
@@ -9790,7 +9854,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager()
.queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
- | PackageManager.MATCH_ENCRYPTION_DEFAULT);
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
providers = slice != null ? slice.getList() : null;
} catch (RemoteException ex) {
}
@@ -11021,6 +11085,12 @@ public final class ActivityManagerService extends ActivityManagerNative
mHandler.sendMessageDelayed(nmsg, NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY);
}
+ /** Notifies all listeners when an Activity is pinned. */
+ void notifyActivityPinnedLocked() {
+ mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
+ mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG).sendToTarget();
+ }
+
@Override
public void notifyCleartextNetwork(int uid, byte[] firstPacket) {
mHandler.obtainMessage(NOTIFY_CLEARTEXT_NETWORK_MSG, uid, 0, firstPacket).sendToTarget();
@@ -12137,7 +12207,9 @@ public final class ActivityManagerService extends ActivityManagerNative
private void retrieveSettings() {
final ContentResolver resolver = mContext.getContentResolver();
final boolean freeformWindowManagement =
- mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+ mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
+ || Settings.Global.getInt(
+ resolver, DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
final boolean supportsPictureInPicture =
mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
@@ -12146,9 +12218,8 @@ public final class ActivityManagerService extends ActivityManagerNative
final boolean alwaysFinishActivities =
Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
- final int defaultForceResizable = Build.IS_DEBUGGABLE ? 1 : 0;
final boolean forceResizable = Settings.Global.getInt(
- resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, defaultForceResizable) != 0;
+ resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
// Transfer any global setting for forcing RTL layout, into a System Property
SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
@@ -12591,7 +12662,7 @@ public final class ActivityManagerService extends ActivityManagerNative
} finally {
Binder.restoreCallingIdentity(ident);
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
}
}
@@ -12702,10 +12773,10 @@ public final class ActivityManagerService extends ActivityManagerNative
// annoy the user repeatedly. Unless it is persistent, since those
// processes run critical code.
removeProcessLocked(app, false, false, "crash");
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
return false;
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
} else {
mStackSupervisor.finishTopRunningActivityLocked(app, reason);
}
@@ -14799,7 +14870,7 @@ public final class ActivityManagerService extends ActivityManagerNative
int dumpUid = -2;
if (dumpPackage != null) {
try {
- dumpUid = mContext.getPackageManager().getPackageUid(dumpPackage, 0);
+ dumpUid = mContext.getPackageManager().getPackageUidAsUser(dumpPackage, 0);
} catch (NameNotFoundException e) {
dumpUid = -1;
}
@@ -16998,7 +17069,7 @@ public final class ActivityManagerService extends ActivityManagerNative
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
int callingUid, int[] users) {
// TODO: come back and remove this assumption to triage all broadcasts
- int pmFlags = STOCK_PM_FLAGS | PackageManager.MATCH_ENCRYPTION_DEFAULT;
+ int pmFlags = STOCK_PM_FLAGS | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
List<ResolveInfo> receivers = null;
try {
@@ -17921,8 +17992,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "suppressResizeConfigChanges()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "suppressResizeConfigChanges()");
synchronized (this) {
mSuppressResizeConfigChanges = suppress;
}
@@ -17930,8 +18000,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void moveTasksToFullscreenStack(int fromStackId) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "moveTasksToFullscreenStack()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTasksToFullscreenStack()");
if (fromStackId == HOME_STACK_ID) {
throw new IllegalArgumentException("You can't move tasks from the home stack.");
}
@@ -18050,10 +18119,18 @@ public final class ActivityManagerService extends ActivityManagerNative
EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
- if (mSupportedSystemLocales == null) {
- mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
+ final Locale locale;
+ if (values.getLocales().size() == 1) {
+ // This is an optimization to avoid the JNI call when the result of
+ // getFirstMatch() does not depend on the supported locales.
+ locale = values.getLocales().getPrimary();
+ } else {
+ if (mSupportedSystemLocales == null) {
+ mSupportedSystemLocales =
+ Resources.getSystem().getAssets().getLocales();
+ }
+ locale = values.getLocales().getFirstMatch(mSupportedSystemLocales);
}
- final Locale locale = values.getLocales().getFirstMatch(mSupportedSystemLocales);
SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
locale));
@@ -20877,7 +20954,7 @@ public final class ActivityManagerService extends ActivityManagerNative
public void moveToFront() {
checkCaller();
// Will bring task to front if it already has a root activity.
- startActivityFromRecentsInner(mTaskId, INVALID_STACK_ID, null);
+ startActivityFromRecentsInner(mTaskId, null);
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 9680382e922d..4101dde37198 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -26,7 +26,7 @@ class ActivityMetricsLogger {
// 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 = {
- "tron_varz_window_time_0", "tron_varz_window_time_1", "tron_varz_window_time_2"};
+ "window_time_0", "window_time_1", "window_time_2"};
private int mWindowState = WINDOW_STATE_STANDARD;
private long mLastLogTimeSecs;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 4d9120b09478..4fb87c3a2660 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,7 +16,11 @@
package com.android.server.am;
+import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE;
+import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
@@ -739,6 +743,22 @@ final class ActivityRecord {
(intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
}
+ boolean isFocusable() {
+ return StackId.canReceiveKeys(task.stack.mStackId) || isAlwaysFocusable();
+ }
+
+ boolean isResizeable() {
+ return (info.flags & FLAG_RESIZEABLE) != 0;
+ }
+
+ boolean supportsPictureInPicture() {
+ return (info.flags & FLAG_SUPPORTS_PICTURE_IN_PICTURE) != 0;
+ }
+
+ boolean isAlwaysFocusable() {
+ return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
+ }
+
void makeFinishingLocked() {
if (!finishing) {
if (task != null && task.stack != null
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1492e23e37e4..8d9cb5897bd6 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -560,7 +560,7 @@ final class ActivityStack {
// TODO(multi-display): Needs to also work if focus is moving to the non-home display.
if (isOnHomeDisplay()) {
- mStackSupervisor.setFocusStack(reason, this);
+ mStackSupervisor.setFocusStackUnchecked(reason, this);
}
if (task != null) {
insertTaskAtTop(task, null);
@@ -572,6 +572,16 @@ final class ActivityStack {
}
}
+ boolean isFocusable() {
+ if (StackId.canReceiveKeys(mStackId)) {
+ return true;
+ }
+ // The stack isn't focusable. See if its top activity is focusable to force focus on the
+ // stack.
+ final ActivityRecord r = topRunningActivityLocked();
+ return r != null && r.isFocusable();
+ }
+
final boolean isAttached() {
return mStacks != null;
}
@@ -917,7 +927,7 @@ final class ActivityStack {
if (prev == null) {
if (!resuming) {
Slog.wtf(TAG, "Trying to pause when nothing is resumed");
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
return false;
}
@@ -1008,7 +1018,7 @@ final class ActivityStack {
// pause, so just treat it as being paused now.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
if (!resuming) {
- mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
return false;
}
@@ -1075,7 +1085,7 @@ final class ActivityStack {
} else {
if (r.configDestroy) {
destroyActivityLocked(r, true, "stop-config");
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
} else {
mStackSupervisor.updatePreviousProcessLocked(r);
}
@@ -1131,17 +1141,16 @@ final class ActivityStack {
if (resumeNext) {
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
if (!mService.isSleepingOrShuttingDown()) {
- mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
} else {
mStackSupervisor.checkReadyForSleepLocked();
ActivityRecord top = topStack.topRunningActivityLocked();
if (top == null || (prev != null && top != prev)) {
- // If there are no more activities available to run,
- // do resume anyway to start something. Also if the top
- // activity on the stack is not the just paused activity,
- // we need to go ahead and resume it to ensure we complete
- // an in-flight app switch.
- mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);
+ // If there are no more activities available to run, do resume anyway to start
+ // something. Also if the top activity on the stack is not the just paused
+ // activity, we need to go ahead and resume it to ensure we complete an
+ // in-flight app switch.
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
@@ -1296,7 +1305,7 @@ final class ActivityStack {
return null;
}
- private ActivityStack getNextVisibleStackLocked() {
+ ActivityStack getNextFocusableStackLocked() {
ArrayList<ActivityStack> stacks = mStacks;
final ActivityRecord parent = mActivityContainer.mParentActivity;
if (parent != null) {
@@ -1305,7 +1314,7 @@ final class ActivityStack {
if (stacks != null) {
for (int i = stacks.size() - 1; i >= 0; --i) {
ActivityStack stack = stacks.get(i);
- if (stack != this && stack.isStackVisibleLocked()) {
+ if (stack != this && stack.isFocusable() && stack.isStackVisibleLocked()) {
return stack;
}
}
@@ -1478,7 +1487,7 @@ final class ActivityStack {
boolean aboveTop = top != null;
final boolean stackInvisible = !isStackVisibleLocked();
boolean behindFullscreenActivity = stackInvisible;
- boolean noStackActivityResumed = (isInStackLocked(starting) == null);
+ boolean resumeNextActivity = isFocusable() && (isInStackLocked(starting) == null);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
@@ -1509,18 +1518,18 @@ final class ActivityStack {
if (r.app == null || r.app.thread == null) {
if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
- noStackActivityResumed, r)) {
+ resumeNextActivity, r)) {
if (activityNdx >= activities.size()) {
// Record may be removed if its process needs to restart.
activityNdx = activities.size() - 1;
} else {
- noStackActivityResumed = false;
+ resumeNextActivity = false;
}
}
} else if (r.visible) {
// If this activity is already visible, then there is nothing to do here.
if (handleAlreadyVisible(r)) {
- noStackActivityResumed = false;
+ resumeNextActivity = false;
}
} else {
makeVisible(starting, r);
@@ -1561,7 +1570,7 @@ final class ActivityStack {
}
private boolean makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
- boolean isTop, boolean noStackActivityResumed, ActivityRecord r) {
+ boolean isTop, boolean andResume, ActivityRecord r) {
// We need to make sure the app is running if it's the top, or it is just made visible from
// invisible. If the app is already visible, it must have died while it was visible. In this
// case, we'll show the dead window but will not restart the app. Otherwise we could end up
@@ -1578,7 +1587,7 @@ final class ActivityStack {
setVisible(r, true);
}
if (r != starting) {
- mStackSupervisor.startSpecificActivityLocked(r, noStackActivityResumed, false);
+ mStackSupervisor.startSpecificActivityLocked(r, andResume, false);
return true;
}
}
@@ -1772,15 +1781,17 @@ final class ActivityStack {
*
* @param prev The previously resumed activity, for when in the process
* of pausing; can be null to call from elsewhere.
+ * @param options Activity options.
*
* @return Returns true if something is being resumed, or false if
* nothing happened.
+ *
+ * NOTE: It is not safe to call this method directly as it can cause an activity in a
+ * non-focused stack to be resumed.
+ * Use {@link ActivityStackSupervisor#resumeFocusedStackTopActivityLocked} to resume the
+ * right activity for the current system state.
*/
- final boolean resumeTopActivityLocked(ActivityRecord prev) {
- return resumeTopActivityLocked(prev, null);
- }
-
- final boolean resumeTopActivityLocked(ActivityRecord prev, ActivityOptions options) {
+ boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
// Don't even start recursing.
return false;
@@ -1831,14 +1842,13 @@ final class ActivityStack {
if (next == null) {
// There are no more activities!
final String reason = "noMoreActivities";
- if (!mFullscreen) {
+ if (!mFullscreen && adjustFocusToNextFocusableStackLocked(reason)) {
// Try to move focus to the next visible stack with a running activity if this
// stack is not covering the entire screen.
- final ActivityStack stack = getNextVisibleStackLocked();
- if (adjustFocusToNextVisibleStackLocked(stack, reason)) {
- return mStackSupervisor.resumeTopActivitiesLocked(stack, prev, null);
- }
+ return mStackSupervisor.resumeFocusedStackTopActivityLocked(
+ mStackSupervisor.getFocusedStack(), prev, null);
}
+
// Let's just start up the Launcher...
ActivityOptions.abort(options);
if (DEBUG_STATES) Slog.d(TAG_STATES,
@@ -2870,7 +2880,7 @@ final class ActivityStack {
final ActivityRecord next = topRunningActivityLocked();
final String myReason = reason + " adjustFocus";
if (next != r) {
- if (next != null && StackId.keepFocusInStackIfPossible(mStackId)) {
+ if (next != null && StackId.keepFocusInStackIfPossible(mStackId) && isFocusable()) {
// For freeform, docked, and pinned stacks we always keep the focus within the
// stack as long as there is a running activity in the stack that we can adjust
// focus to.
@@ -2882,8 +2892,7 @@ final class ActivityStack {
// For non-fullscreen stack, we want to move the focus to the next visible
// stack to prevent the home screen from moving to the top and obscuring
// other visible stacks.
- if (!mFullscreen
- && adjustFocusToNextVisibleStackLocked(null, myReason)) {
+ if (!mFullscreen && adjustFocusToNextFocusableStackLocked(myReason)) {
return;
}
// Move the home stack to the top if this stack is fullscreen or there is no
@@ -2897,24 +2906,16 @@ final class ActivityStack {
}
}
- final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
- if (top != null) {
- mService.setFocusedActivityLocked(top, myReason);
- }
+ mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked(), myReason);
}
- private boolean adjustFocusToNextVisibleStackLocked(ActivityStack inStack, String reason) {
- final ActivityStack stack = (inStack != null) ? inStack : getNextVisibleStackLocked();
- final String myReason = reason + " adjustFocusToNextVisibleStack";
+ private boolean adjustFocusToNextFocusableStackLocked(String reason) {
+ final ActivityStack stack = getNextFocusableStackLocked();
+ final String myReason = reason + " adjustFocusToNextFocusableStack";
if (stack == null) {
return false;
}
- final ActivityRecord top = stack.topRunningActivityLocked();
- if (top == null) {
- return false;
- }
- mService.setFocusedActivityLocked(top, myReason);
- return true;
+ return mService.setFocusedActivityLocked(stack.topRunningActivityLocked(), myReason);
}
final void stopActivityLocked(ActivityRecord r) {
@@ -3224,7 +3225,7 @@ final class ActivityStack {
r.makeFinishingLocked();
boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
if (activityRemoved) {
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS,
"destroyActivityLocked: finishCurrentActivityLocked r=" + r +
@@ -3237,7 +3238,7 @@ final class ActivityStack {
if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r);
mStackSupervisor.mFinishingActivities.add(r);
r.resumeKeyDispatchingLocked();
- mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
return r;
}
@@ -3395,7 +3396,7 @@ final class ActivityStack {
if (mPausingActivity == r) {
mPausingActivity = null;
}
- mService.clearFocusedActivity(r);
+ mService.resetFocusedActivityIfNeededLocked(r);
r.configDestroy = false;
r.frozenBeforeDestroy = false;
@@ -3526,7 +3527,7 @@ final class ActivityStack {
}
}
if (activityRemoved) {
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
@@ -3700,7 +3701,7 @@ final class ActivityStack {
removeActivityFromHistoryLocked(r, reason);
}
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -3738,7 +3739,7 @@ final class ActivityStack {
setVisibleBehindActivity(null);
mStackSupervisor.scheduleIdleTimeoutLocked(null);
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
boolean hasVisibleBehindActivity() {
@@ -3953,7 +3954,7 @@ final class ActivityStack {
updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
if (VALIDATE_TOKENS) {
@@ -4016,7 +4017,7 @@ final class ActivityStack {
if (fullscreenStack != null && fullscreenStack.hasVisibleBehindActivity()) {
final ActivityRecord visibleBehind = fullscreenStack.getVisibleBehindActivity();
mService.setFocusedActivityLocked(visibleBehind, "moveTaskToBack");
- mStackSupervisor.resumeTopActivitiesLocked(fullscreenStack, null, null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
return true;
}
}
@@ -4071,7 +4072,7 @@ final class ActivityStack {
return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null, "moveTaskToBack");
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
return true;
}
@@ -4313,6 +4314,7 @@ final class ActivityStack {
r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
!andResume, new Configuration(mService.mConfiguration),
new Configuration(r.task.mOverrideConfig), preserveWindow);
+ mStackSupervisor.activityRelaunchingLocked(r);
// Note: don't need to call pauseIfSleepingLocked() here, because
// the caller will only pass in 'andResume' if this activity is
// currently resumed, which implies we aren't sleeping.
@@ -4661,7 +4663,7 @@ final class ActivityStack {
// We only need to adjust focused stack if this stack is in focus.
if (isOnHomeDisplay() && mStackSupervisor.isFocusedStack(this)) {
String myReason = reason + " leftTaskHistoryEmpty";
- if (mFullscreen || !adjustFocusToNextVisibleStackLocked(null, myReason)) {
+ if (mFullscreen || !adjustFocusToNextFocusableStackLocked(myReason)) {
mStackSupervisor.moveHomeStackToFront(myReason);
}
}
@@ -4734,10 +4736,7 @@ final class ActivityStack {
private void postAddTask(TaskRecord task, ActivityStack prevStack) {
if (prevStack != null) {
- if (prevStack != this
- && (prevStack.mStackId == PINNED_STACK_ID || mStackId == PINNED_STACK_ID)) {
- task.reportPictureInPictureModeChange();
- }
+ task.reportPictureInPictureModeChangeIfNeeded(prevStack);
} else if (task.voiceSession != null) {
try {
task.voiceSession.taskStarted(task.intent, task.taskId);
@@ -4751,32 +4750,28 @@ final class ActivityStack {
task.updateOverrideConfiguration(bounds);
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
- (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
- r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
- bounds, task.mOverrideConfig, !r.isHomeActivity());
+ (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
+ task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
+ !r.isHomeActivity(), r.isAlwaysFocusable());
mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
r.taskConfigOverride = task.mOverrideConfig;
}
- void setFocusAndResumeStateIfNeeded(
- ActivityRecord r, boolean setFocus, boolean setResume, String reason) {
- // If the activity had focus before move focus to this stack.
- if (setFocus) {
- // If the activity owns the last resumed activity, transfer that together,
- // so that we don't resume the same activity again in the new stack.
- // Apps may depend on onResume()/onPause() being called in pairs.
- if (setResume) {
- mResumedActivity = r;
- // Move the stack in which we are placing the activity to the front. We don't use
- // ActivityManagerService.setFocusedActivityLocked, because if the activity is
- // already focused, the call will short-circuit and do nothing.
- moveToFront(reason);
- } else {
- // We need to not only move the stack to the front, but also have the activity
- // focused. This will achieve both goals.
- mService.setFocusedActivityLocked(r, reason);
- }
+ void moveToFrontAndResumeStateIfNeeded(
+ ActivityRecord r, boolean moveToFront, boolean setResume, String reason) {
+ if (!moveToFront) {
+ return;
}
+
+ // If the activity owns the last resumed activity, transfer that together,
+ // so that we don't resume the same activity again in the new stack.
+ // Apps may depend on onResume()/onPause() being called in pairs.
+ if (setResume) {
+ mResumedActivity = r;
+ }
+ // Move the stack in which we are placing the activity to the front. The call will also
+ // make sure the activity focus is set.
+ moveToFront(reason);
}
/**
@@ -4800,8 +4795,11 @@ final class ActivityStack {
r.setTask(task, null);
task.addActivityToTop(r);
setAppTask(r, task);
- task.reportPictureInPictureModeChange();
- setFocusAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+ task.reportPictureInPictureModeChangeIfNeeded(prevStack);
+ moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+ if (wasResumed) {
+ prevStack.mResumedActivity = null;
+ }
}
private void setAppTask(ActivityRecord r, TaskRecord task) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 32671acfcc30..4672023a220e 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -16,70 +16,6 @@
package com.android.server.am;
-import static android.Manifest.permission.START_ANY_ACTIVITY;
-import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
-import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
-import static android.app.ActivityManager.RESIZE_MODE_FORCED;
-import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_STATIC_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.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
-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.PackageManager.PERMISSION_GRANTED;
-import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-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.FIRST_SUPERVISOR_STACK_MSG;
-import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
-import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
-import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
-import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
-import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
-import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
-import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
-import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
-
import android.Manifest;
import android.app.Activity;
import android.app.ActivityManager;
@@ -164,6 +100,70 @@ import java.util.Arrays;
import java.util.List;
import java.util.Set;
+import static android.Manifest.permission.START_ANY_ACTIVITY;
+import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
+import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
+import static android.app.ActivityManager.RESIZE_MODE_FORCED;
+import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_STATIC_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.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
+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.PackageManager.PERMISSION_GRANTED;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
+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.FIRST_SUPERVISOR_STACK_MSG;
+import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
+import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
+
public final class ActivityStackSupervisor implements DisplayListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
@@ -370,7 +370,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
*/
private LockTaskNotify mLockTaskNotify;
- /** Used to keep resumeTopActivityLocked() from being entered recursively */
+ /** Used to keep resumeTopActivityUncheckedLocked() from being entered recursively */
boolean inResumeTopActivity;
// temp. rects used during resize calculation so we don't need to create a new object each time.
@@ -379,6 +379,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
+ private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>();
// 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.
@@ -389,6 +390,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
private final ActivityMetricsLogger mActivityMetricsLogger;
+ private final ResizeDockedStackTimeout mResizeDockedStackTimeout;
+
static class FindTaskResult {
ActivityRecord r;
boolean matchedByRootAffinity;
@@ -432,6 +435,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
mRecentTasks = recentTasks;
mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
+ mResizeDockedStackTimeout = new ResizeDockedStackTimeout(service, this, mHandler);
}
/**
@@ -492,8 +496,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay);
}
- createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY, true);
- mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);
+ mHomeStack = mFocusedStack = mLastFocusedStack =
+ getStack(HOME_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
}
@@ -537,16 +541,30 @@ public final class ActivityStackSupervisor implements DisplayListener {
return stack == mHomeStack.mStacks.get((mHomeStack.mStacks.size() - 1));
}
- void setFocusStack(String reason, ActivityStack focusedStack) {
- mLastFocusedStack = mFocusedStack;
- mFocusedStack = focusedStack;
+ /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */
+ void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) {
+ if (!focusCandidate.isFocusable()) {
+ // The focus candidate isn't focusable. Move focus to the top stack that is focusable.
+ focusCandidate = focusCandidate.getNextFocusableStackLocked();
+ }
+
+ if (focusCandidate != mFocusedStack) {
+ mLastFocusedStack = mFocusedStack;
+ mFocusedStack = focusCandidate;
- EventLogTags.writeAmFocusedStack(
- mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
- mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
+ EventLogTags.writeAmFocusedStack(
+ mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
+ mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
+ }
+
+ final ActivityRecord r = topRunningActivityLocked();
+ if (mService.mFocusedActivity != r) {
+ // The focus activity should always be the top activity in the focused stack.
+ // There will be chaos and anarchy if it isn't...
+ mService.setFocusedActivityLocked(r, reason + " setFocusStack");
+ }
if (mService.mBooting || !mService.mBooted) {
- final ActivityRecord r = topRunningActivityLocked();
if (r != null && r.idle) {
checkFinishBootingLocked();
}
@@ -591,12 +609,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
ActivityRecord r = getHomeActivity();
+ final String myReason = reason + " resumeHomeStackTask";
+
// Only resume home activity if isn't finishing.
if (r != null && !r.finishing) {
- mService.setFocusedActivityLocked(r, reason);
- return resumeTopActivitiesLocked(mHomeStack, prev, null);
+ mService.setFocusedActivityLocked(r, myReason);
+ return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
}
- return mService.startHomeActivityLocked(mCurrentUser, reason);
+ return mService.startHomeActivityLocked(mCurrentUser, myReason);
}
TaskRecord anyTaskForIdLocked(int id) {
@@ -893,7 +913,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
final ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
- if (stack != focusedStack && isFrontStack(stack)) {
+ if (stack != focusedStack && isFrontStack(stack) && stack.isFocusable()) {
r = stack.topRunningActivityLocked();
if (r != null) {
return r;
@@ -1148,14 +1168,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
// a resume.
stack.minimalResumeActivityLocked(r);
} else {
- // This activity is not starting in the resumed state... which
- // should look like we asked it to pause+stop (but remain visible),
- // and it has done so and reported back the current icicle and
- // other state.
+ // This activity is not starting in the resumed state... which should look like we asked
+ // it to pause+stop (but remain visible), and it has done so and reported back the
+ // current icicle and other state.
if (DEBUG_STATES) Slog.v(TAG_STATES,
- "Moving to STOPPED: " + r + " (starting in stopped state)");
- r.state = STOPPED;
- r.stopped = true;
+ "Moving to PAUSED: " + r + " (starting in paused state)");
+ r.state = PAUSED;
}
// Launch the new version setup screen if needed. We do this -after-
@@ -1345,30 +1363,20 @@ public final class ActivityStackSupervisor implements DisplayListener {
return ACTIVITY_RESTRICTION_NONE;
}
- boolean setFocusedStack(ActivityRecord r, String reason) {
+ boolean moveActivityStackToFront(ActivityRecord r, String reason) {
if (r == null) {
// Not sure what you are trying to do, but it is not going to work...
return false;
}
final TaskRecord task = r.task;
if (task == null || task.stack == null) {
- Slog.w(TAG, "Can't set focus stack for r=" + r + " task=" + task);
+ Slog.w(TAG, "Can't move stack to front for r=" + r + " task=" + task);
return false;
}
task.stack.moveToFront(reason, task);
return true;
}
- Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
- Rect newBounds = null;
- if (options != null && (r.info.resizeable || (inTask != null && inTask.mResizeable))) {
- if (canUseActivityOptionsLaunchBounds(options)) {
- newBounds = options.getLaunchBounds();
- }
- }
- return newBounds;
- }
-
void setLaunchSource(int uid) {
mLaunchingActivity.setWorkSource(new WorkSource(uid));
}
@@ -1518,7 +1526,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
//mWindowManager.dump();
if (activityRemoved) {
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
return r;
@@ -1611,35 +1619,17 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
- boolean resumeTopActivitiesLocked() {
- return resumeTopActivitiesLocked(null, null, null);
+ boolean resumeFocusedStackTopActivityLocked() {
+ return resumeFocusedStackTopActivityLocked(null, null, null);
}
- boolean resumeTopActivitiesLocked(
+ boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
- if (targetStack == null) {
- targetStack = mFocusedStack;
+ if (targetStack != null && isFocusedStack(targetStack)) {
+ return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
- // Do targetStack first.
- boolean result = false;
- if (isFocusedStack(targetStack)) {
- result = targetStack.resumeTopActivityLocked(target, targetOptions);
- }
-
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
- for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = stacks.get(stackNdx);
- if (stack == targetStack) {
- // Already started above.
- continue;
- }
- if (isFocusedStack(stack)) {
- stack.resumeTopActivityLocked(null);
- }
- }
- }
- return result;
+ mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
+ return false;
}
void finishTopRunningActivityLocked(ProcessRecord app, String reason) {
@@ -1681,10 +1671,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
if (task.mResizeable && options != null) {
- if (canUseActivityOptionsLaunchBounds(options)) {
+ int stackId = options.getLaunchStackId();
+ if (canUseActivityOptionsLaunchBounds(options, stackId)) {
Rect bounds = options.getLaunchBounds();
task.updateOverrideConfiguration(bounds);
- final int stackId = task.getLaunchStackId();
+ if (stackId == INVALID_STACK_ID) {
+ stackId = task.getLaunchStackId();
+ }
if (stackId != task.stack.mStackId) {
moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
// moveTaskToStackUncheckedLocked() should already placed the task on top,
@@ -1706,10 +1699,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
"findTaskToMoveToFront: moved to front of stack=" + task.stack);
}
- private boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) {
+ boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
// We use the launch bounds in the activity options is the device supports freeform
- // window management.
- return options.hasLaunchBounds() && mService.mSupportsFreeformWindowManagement;
+ // window management or is launching into the pinned stack.
+ if (!options.hasLaunchBounds()) {
+ return false;
+ }
+ return (mService.mSupportsPictureInPicture && launchStackId == PINNED_STACK_ID)
+ || mService.mSupportsFreeformWindowManagement;
}
ActivityStack getStack(int stackId) {
@@ -1806,16 +1803,20 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
- void resizeStackLocked(int stackId, Rect bounds, boolean preserveWindows,
- boolean allowResizeInDockedMode) {
+ void resizeStackLocked(int stackId, Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds,
+ boolean preserveWindows, boolean allowResizeInDockedMode) {
+ if (stackId == DOCKED_STACK_ID) {
+ resizeDockedStackLocked(bounds, tempTaskBounds, tempTaskInsetBounds, null, null,
+ preserveWindows);
+ return;
+ }
final ActivityStack stack = getStack(stackId);
if (stack == null) {
Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
return;
}
- if (!allowResizeInDockedMode
- && stackId != DOCKED_STACK_ID && getStack(DOCKED_STACK_ID) != null) {
+ if (!allowResizeInDockedMode && getStack(DOCKED_STACK_ID) != null) {
// If the docked stack exist we don't allow resizes of stacks not caused by the docked
// stack size changing so things don't get out of sync.
return;
@@ -1824,100 +1825,143 @@ public final class ActivityStackSupervisor implements DisplayListener {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
mWindowManager.deferSurfaceLayout();
try {
+ resizeStackUncheckedLocked(stack, bounds, tempTaskBounds, tempTaskInsetBounds);
+ ensureConfigurationAndResume(stack, stack.topRunningActivityLocked(), preserveWindows);
+ } finally {
+ mWindowManager.continueSurfaceLayout();
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ }
- if (bounds != null && mWindowManager.isFullscreenBounds(stackId, bounds)) {
- // The bounds passed in corresponds to the fullscreen bounds which we normally
- // represent with null. Go ahead and set it to null so that all tasks configuration
- // can have the right fullscreen state.
- bounds = null;
- }
-
- ActivityRecord r = stack.topRunningActivityLocked();
+ private void resizeStackUncheckedLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
+ Rect tempTaskInsetBounds) {
+ if (bounds != null && mWindowManager.isFullscreenBounds(stack.mStackId, bounds)) {
+ // The bounds passed in corresponds to the fullscreen bounds which we normally
+ // represent with null. Go ahead and set it to null so that all tasks configuration
+ // can have the right fullscreen state.
+ bounds = null;
+ }
- mTmpBounds.clear();
- mTmpConfigs.clear();
- ArrayList<TaskRecord> tasks = stack.getAllTasks();
- for (int i = tasks.size() - 1; i >= 0; i--) {
- TaskRecord task = tasks.get(i);
- if (task.mResizeable) {
- if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
- // For freeform stack we don't adjust the size of the tasks to match that
- // of the stack, but we do try to make sure the tasks are still contained
- // with the bounds of the stack.
- tempRect2.set(task.mBounds);
- fitWithinBounds(tempRect2, bounds);
- task.updateOverrideConfiguration(tempRect2);
- } else {
- task.updateOverrideConfiguration(bounds);
- }
+ mTmpBounds.clear();
+ mTmpConfigs.clear();
+ mTmpInsetBounds.clear();
+ ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ TaskRecord task = tasks.get(i);
+ if (task.mResizeable) {
+ if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+ // For freeform stack we don't adjust the size of the tasks to match that
+ // of the stack, but we do try to make sure the tasks are still contained
+ // with the bounds of the stack.
+ tempRect2.set(task.mBounds);
+ fitWithinBounds(tempRect2, bounds);
+ task.updateOverrideConfiguration(tempRect2);
+ } else {
+ task.updateOverrideConfiguration(tempTaskBounds != null
+ ? tempTaskBounds : bounds);
}
+ }
- mTmpConfigs.put(task.taskId, task.mOverrideConfig);
- mTmpBounds.put(task.taskId, task.mBounds);
+ mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+ mTmpBounds.put(task.taskId, task.mBounds);
+ if (tempTaskInsetBounds != null) {
+ mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds);
}
- stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds);
- if (stack.mStackId == DOCKED_STACK_ID) {
- // Dock stack funness...Yay!
- if (stack.mFullscreen) {
- // The dock stack went fullscreen which is kinda like dismissing it.
- // In this case we make all other static stacks fullscreen and move all
- // docked stack tasks to the fullscreen stack.
- for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
- if (StackId.isResizeableByDockedStack(i) && getStack(i) != null) {
- resizeStackLocked(i, null, preserveWindows, true);
- }
- }
+ }
- final int count = tasks.size();
- for (int i = 0; i < count; i++) {
- moveTaskToStackLocked(tasks.get(i).taskId,
- FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS, "resizeStack",
- false /* animate */);
- }
+ // We might trigger a configuration change. Save the current task bounds for freezing.
+ mWindowManager.prepareFreezingTaskBounds(stack.mStackId);
+ stack.mFullscreen = mWindowManager.resizeStack(stack.mStackId, bounds, mTmpConfigs,
+ mTmpBounds, mTmpInsetBounds);
+ stack.setBounds(bounds);
+ }
- // stack shouldn't contain anymore activities, so nothing to resume.
- r = null;
- } else {
- // Docked stacks occupy a dedicated region on screen so the size of all other
- // static stacks need to be adjusted so they don't overlap with the docked stack.
- // We get the bounds to use from window manager which has been adjusted for any
- // screen controls and is also the same for all stacks.
- mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect);
-
- for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
- if (StackId.isResizeableByDockedStack(i)) {
- ActivityStack otherStack = getStack(i);
- if (otherStack != null) {
- resizeStackLocked(i, tempRect, PRESERVE_WINDOWS, true);
- }
- }
+ private void ensureConfigurationAndResume(ActivityStack stack, ActivityRecord r,
+ boolean preserveWindows) {
+ if (r == null) {
+ return;
+ }
+ 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();
+ }
+ }
+
+ void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
+ Rect tempDockedTaskInsetBounds,
+ Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, boolean preserveWindows) {
+ final ActivityStack stack = getStack(DOCKED_STACK_ID);
+ if (stack == null) {
+ Slog.w(TAG, "resizeDockedStackLocked: docked stack not found");
+ return;
+ }
+
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeDockedStack");
+ mWindowManager.deferSurfaceLayout();
+ try {
+ ActivityRecord r = stack.topRunningActivityLocked();
+ resizeStackUncheckedLocked(stack, dockedBounds, tempDockedTaskBounds,
+ tempDockedTaskInsetBounds);
+
+ if (stack.mFullscreen) {
+ // The dock stack went fullscreen which is kinda like dismissing it.
+ // In this case we make all other static stacks fullscreen and move all
+ // docked stack tasks to the fullscreen stack.
+ for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+ if (StackId.isResizeableByDockedStack(i) && getStack(i) != null) {
+ resizeStackLocked(i, null, null, null, preserveWindows,
+ true /* allowResizeInDockedMode */);
}
}
- // Since we are resizing the stack, all other operations should strive to preserve
- // windows.
- preserveWindows = true;
- }
- stack.setBounds(bounds);
- if (r != null) {
- 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) {
- resumeTopActivitiesLocked(stack, null, null);
+ ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ final int count = tasks.size();
+ for (int i = 0; i < count; i++) {
+ moveTaskToStackLocked(tasks.get(i).taskId,
+ FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS, "resizeStack",
+ false /* animate */);
+ }
+
+ // stack shouldn't contain anymore activities, so nothing to resume.
+ r = null;
+ } else {
+ // Docked stacks occupy a dedicated region on screen so the size of all other
+ // static stacks need to be adjusted so they don't overlap with the docked stack.
+ // We get the bounds to use from window manager which has been adjusted for any
+ // screen controls and is also the same for all stacks.
+ mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect);
+ for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+ if (StackId.isResizeableByDockedStack(i)) {
+ ActivityStack otherStack = getStack(i);
+ if (otherStack != null) {
+ resizeStackLocked(i, tempRect, tempOtherTaskBounds,
+ tempOtherTaskInsetBounds, preserveWindows,
+ true /* allowResizeInDockedMode */);
+ }
+ }
}
}
+ ensureConfigurationAndResume(stack, r, preserveWindows);
} finally {
mWindowManager.continueSurfaceLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
+
+ mResizeDockedStackTimeout.notifyResizing(dockedBounds,
+ tempDockedTaskBounds != null
+ || tempDockedTaskInsetBounds != null
+ || tempOtherTaskBounds != null
+ || tempOtherTaskInsetBounds != null);
}
- void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
+ boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
if (!task.mResizeable) {
Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
- return;
+ return true;
}
adjustForMinimalTaskDimensions(task, bounds);
@@ -1927,7 +1971,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) {
// Nothing to do here...
- return;
+ return true;
}
if (!mWindowManager.isValidTaskId(task.taskId)) {
@@ -1939,7 +1983,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// re-restore the task so it can have the proper stack association.
restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID);
}
- return;
+ return true;
}
// Do not move the task to another stack here.
@@ -1961,13 +2005,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
// All other activities must be made visible with their correct configuration.
ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
if (!kept) {
- resumeTopActivitiesLocked(stack, null, null);
+ resumeFocusedStackTopActivityLocked();
}
}
}
mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ return kept;
}
private void adjustForMinimalTaskDimensions(TaskRecord task, Rect bounds) {
@@ -2083,8 +2128,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
ActivityStack moveTaskToStackUncheckedLocked(
TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
final ActivityRecord r = task.getTopActivity();
- final boolean wasFocused = isFocusedStack(task.stack) && (topRunningActivityLocked() == r);
- final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r);
+ final ActivityStack prevStack = task.stack;
+ final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
+ final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);
+ // In some cases the focused stack isn't the front stack. E.g. pinned stack.
+ // Whenever we are moving the top activity from the front stack we want to make sure to move
+ // the stack to the front.
+ final boolean wasFront = isFrontStack(prevStack)
+ && (prevStack.topRunningActivityLocked() == r);
final boolean resizeable = task.mResizeable;
// Temporarily disable resizeablility of task we are moving. We don't want it to be resized
@@ -2097,9 +2148,9 @@ public final class ActivityStackSupervisor implements DisplayListener {
stack.addTask(task, toTop, reason);
// If the task had focus before (or we're requested to move focus),
- // move focus to the new stack.
- stack.setFocusAndResumeStateIfNeeded(
- r, forceFocus || wasFocused, wasResumed, reason);
+ // move focus to the new stack by moving the stack to the front.
+ stack.moveToFrontAndResumeStateIfNeeded(
+ r, forceFocus || wasFocused || wasFront, wasResumed, reason);
return stack;
}
@@ -2119,13 +2170,17 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
final ActivityRecord topActivity = task.getTopActivity();
- if (StackId.preserveWindowOnTaskMove(stackId) && topActivity != null) {
+ final boolean mightReplaceWindow =
+ StackId.preserveWindowOnTaskMove(stackId) && topActivity != null;
+ if (mightReplaceWindow) {
// We are about to relaunch the activity because its configuration changed due to
// being maximized, i.e. size change. The activity will first remove the old window
// and then add a new one. This call will tell window manager about this, so it can
// preserve the old window until the new one is drawn. This prevents having a gap
// between the removal and addition, in which no window is visible. We also want the
// entrance of the new window to be properly animated.
+ // Note here we always set the replacing window first, as the flags might be needed
+ // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
mWindowManager.setReplacingWindow(topActivity.appToken, animate);
}
final ActivityStack stack = moveTaskToStackUncheckedLocked(
@@ -2135,21 +2190,29 @@ public final class ActivityStackSupervisor implements DisplayListener {
stack.mNoAnimActivities.add(topActivity);
}
+ boolean kept = true;
// Make sure the task has the appropriate bounds/size for the stack it is in.
if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
- resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+ kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
} else if (stackId == FREEFORM_WORKSPACE_STACK_ID
&& task.mBounds == null && task.mLastNonFullscreenBounds != null) {
- resizeTaskLocked(task, task.mLastNonFullscreenBounds,
+ kept = resizeTaskLocked(task, task.mLastNonFullscreenBounds,
RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
} else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
- resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+ kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+ }
+
+ if (mightReplaceWindow) {
+ // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
+ // window), we need to clear the replace window settings. Otherwise, we schedule a
+ // timeout to remove the old window if the replacing window is not coming in time.
+ mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept);
}
// 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);
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
if (!task.mResizeable && isStackDockedInEffect(stackId)) {
showNonResizeableDockToast(taskId);
@@ -2170,7 +2233,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
return false;
}
- if (!mService.mForceResizableActivities && !r.info.supportsPip) {
+ if (!mService.mForceResizableActivities && !r.supportsPictureInPicture()) {
Slog.w(TAG,
"moveTopStackActivityToPinnedStackLocked: Picture-In-Picture not supported for "
+ " r=" + r);
@@ -2194,13 +2257,18 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
if (bounds != null) {
- resizeStackLocked(stackId, bounds, !PRESERVE_WINDOWS, true);
+ resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
+ null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true);
}
// 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);
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
+
+ if (stackId == PINNED_STACK_ID) {
+ mService.notifyActivityPinnedLocked();
+ }
}
void positionTaskInStackLocked(int taskId, int stackId, int position) {
@@ -2219,7 +2287,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
ActivityRecord findTaskLocked(ActivityRecord r) {
@@ -2329,7 +2397,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
final ActivityStack stack = stacks.get(stackNdx);
stack.awakeFromSleepingLocked();
if (isFocusedStack(stack)) {
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
}
}
@@ -3124,7 +3192,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
"setLockTaskModeLocked: Tasks remaining, can't unlock");
lockedTask.performClearTaskLocked();
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
return;
}
}
@@ -3165,7 +3233,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
if (andResume) {
findTaskToMoveToFrontLocked(task, 0, null, reason);
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
}
@@ -3233,7 +3301,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
didSomething = true;
}
if (didSomething) {
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
}
@@ -3241,6 +3309,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
return mLockTaskModeState;
}
+ void activityRelaunchedLocked(IBinder token) {
+ mWindowManager.notifyAppRelaunchingFinished(token);
+ }
+
+ void activityRelaunchingLocked(ActivityRecord r) {
+ mWindowManager.notifyAppRelaunching(r.appToken);
+ }
+
void logStackState() {
mActivityMetricsLogger.logWindowState();
}
@@ -3280,7 +3356,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
} break;
case RESUME_TOP_ACTIVITY_MSG: {
synchronized (mService) {
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
} break;
case SLEEP_TIMEOUT_MSG: {
@@ -3661,7 +3737,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
mSurface = surface;
if (surface != null) {
- mStack.resumeTopActivityLocked(null);
+ resumeFocusedStackTopActivityLocked();
} else {
mContainerState = CONTAINER_STATE_NO_SURFACE;
((VirtualActivityDisplay) mActivityDisplay).setSurface(null);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index b16e160d9505..f712613a2037 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1,14 +1,47 @@
package com.android.server.am;
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
+import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
+import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
+import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED;
+import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER;
+import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
+import static android.app.ActivityManager.START_SUCCESS;
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
+import static android.content.Context.KEYGUARD_SERVICE;
+import static android.content.Intent.EXTRA_INTENT;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
+import static android.content.Intent.EXTRA_TASK_ID;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
+import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
+import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
+import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
@@ -42,7 +75,6 @@ import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.ProfilerInfo;
import android.content.ComponentName;
-import android.content.Context;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
@@ -67,7 +99,6 @@ import android.view.Display;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.widget.LockPatternUtils;
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
import com.android.server.wm.WindowManagerService;
@@ -79,7 +110,7 @@ import java.util.ArrayList;
* This class collects all the logic for determining how an intent and flags should be turned into
* an activity and associated task and stack.
*/
-public class ActivityStarter {
+class ActivityStarter {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStarter" : TAG_AM;
private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
@@ -92,6 +123,79 @@ public class ActivityStarter {
final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>();
+ // Share state variable among methods when starting an activity.
+ private ActivityRecord mStartActivity;
+ private Intent mIntent;
+ private int mCallingUid;
+ private ActivityOptions mOptions;
+
+ private boolean mLaunchSingleTop;
+ private boolean mLaunchSingleInstance;
+ private boolean mLaunchSingleTask;
+ private boolean mLaunchTaskBehind;
+ private int mLaunchFlags;
+
+ private Rect mLaunchBounds;
+
+ private ActivityRecord mNotTop;
+ private boolean mDoResume;
+ private int mStartFlags;
+ private ActivityRecord mSourceRecord;
+
+ private TaskRecord mInTask;
+ private boolean mAddingToTask;
+ private TaskRecord mReuseTask;
+
+ private ActivityInfo mNewTaskInfo;
+ private Intent mNewTaskIntent;
+ private ActivityStack mSourceStack;
+ private ActivityStack mTargetStack;
+ // TODO: Is the mMoveHome flag really needed?
+ private boolean mMovedHome;
+ private boolean mMovedToFront;
+ private boolean mNoAnimation;
+ private boolean mKeepCurTransition;
+
+ private IVoiceInteractionSession mVoiceSession;
+ private IVoiceInteractor mVoiceInteractor;
+
+ private void reset() {
+ mStartActivity = null;
+ mIntent = null;
+ mCallingUid = -1;
+ mOptions = null;
+
+ mLaunchSingleTop = false;
+ mLaunchSingleInstance = false;
+ mLaunchSingleTask = false;
+ mLaunchTaskBehind = false;
+ mLaunchFlags = 0;
+
+ mLaunchBounds = null;
+
+ mNotTop = null;
+ mDoResume = false;
+ mStartFlags = 0;
+ mSourceRecord = null;
+
+ mInTask = null;
+ mAddingToTask = false;
+ mReuseTask = null;
+
+ mNewTaskInfo = null;
+ mNewTaskIntent = null;
+ mSourceStack = null;
+
+ mTargetStack = null;
+ mMovedHome = false;
+ mMovedToFront = false;
+ mNoAnimation = false;
+ mKeepCurTransition = false;
+
+ mVoiceSession = null;
+ mVoiceInteractor = null;
+ }
+
ActivityStarter(ActivityManagerService service, ActivityStackSupervisor supervisor) {
mService = service;
mSupervisor = supervisor;
@@ -234,11 +338,10 @@ public class ActivityStarter {
final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
- if (err != ActivityManager.START_SUCCESS) {
+ if (err != START_SUCCESS) {
if (resultRecord != null) {
- resultStack.sendActivityResultLocked(-1,
- resultRecord, resultWho, requestCode,
- Activity.RESULT_CANCELED, null);
+ resultStack.sendActivityResultLocked(
+ -1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
}
ActivityOptions.abort(options);
return err;
@@ -262,48 +365,36 @@ public class ActivityStarter {
}
}
- UserInfo user = mSupervisor.getUserInfo(userId);
- KeyguardManager km = (KeyguardManager) mService.mContext
- .getSystemService(Context.KEYGUARD_SERVICE);
- if (user.isManagedProfile()
- && LockPatternUtils.isSeparateWorkChallengeEnabled()
- && km.isDeviceLocked(userId)) {
- IIntentSender target = mService.getIntentSenderLocked(
- ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
- Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
- new String[]{ resolvedType },
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_IMMUTABLE, null);
- final int flags = intent.getFlags();
- final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, user.id);
- if (newIntent != null) {
- intent = newIntent;
- intent.setFlags(flags
- | Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
- intent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
-
- resolvedType = null;
- callingUid = realCallingUid;
- callingPid = realCallingPid;
-
- UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId);
- rInfo = mSupervisor.resolveIntent(intent, resolvedType, parent.id);
- aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
- null /*profilerInfo*/);
+ final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(intent,
+ resolvedType, aInfo, callingPackage, userId);
+ if (interceptingIntent != null) {
+ intent = interceptingIntent;
+ callingPid = realCallingPid;
+ callingUid = realCallingUid;
+ resolvedType = null;
+ // If we are intercepting and there was a task, convert it into an extra for the
+ // ConfirmCredentials intent and unassign it, as otherwise the task will move to
+ // front even if ConfirmCredentials is cancelled.
+ if (inTask != null) {
+ intent.putExtra(EXTRA_TASK_ID, inTask.taskId);
+ inTask = null;
}
+
+ final UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId);
+ rInfo = mSupervisor.resolveIntent(intent, resolvedType, parent.id);
+ aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
+ null /*profilerInfo*/);
}
if (abort) {
if (resultRecord != null) {
resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
- Activity.RESULT_CANCELED, null);
+ RESULT_CANCELED, null);
}
// We pretend to the caller that it was really started, but
// they will just get a cancel result.
ActivityOptions.abort(options);
- return ActivityManager.START_SUCCESS;
+ return START_SUCCESS;
}
// If permissions need a review before any of the app components can run, we
@@ -429,8 +520,8 @@ public class ActivityStarter {
doPendingActivityLaunchesLocked(false);
- err = startActivityUncheckedLocked(r, sourceRecord, voiceSession,
- voiceInteractor, startFlags, true, options, inTask);
+ err = startActivityUnchecked(
+ r, sourceRecord, voiceSession, voiceInteractor, startFlags, true, options, inTask);
if (err < 0) {
// If someone asked to have the keyguard dismissed on the next
@@ -442,6 +533,34 @@ public class ActivityStarter {
return err;
}
+ /**
+ * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
+ *
+ * @return The intercepting intent if needed.
+ */
+ private Intent interceptWithConfirmCredentialsIfNeeded(Intent intent, String resolvedType,
+ ActivityInfo aInfo, String callingPackage, int userId) {
+ if (!mService.mUserController.shouldConfirmCredentials(userId)) {
+ return null;
+ }
+ final IIntentSender target = mService.getIntentSenderLocked(
+ INTENT_SENDER_ACTIVITY, callingPackage,
+ Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
+ new String[]{ resolvedType },
+ FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null);
+ final int flags = intent.getFlags();
+ final KeyguardManager km = (KeyguardManager) mService.mContext
+ .getSystemService(KEYGUARD_SERVICE);
+ final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
+ if (newIntent == null) {
+ return null;
+ }
+ newIntent.setFlags(flags | FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
+ newIntent.putExtra(EXTRA_INTENT, new IntentSender(target));
+ return newIntent;
+ }
+
void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,
@@ -608,7 +727,7 @@ public class ActivityStarter {
} catch (InterruptedException e) {
}
} while (!outResult.timeout && outResult.who == null);
- } else if (res == ActivityManager.START_TASK_TO_FRONT) {
+ } else if (res == START_TASK_TO_FRONT) {
ActivityRecord r = stack.topRunningActivityLocked();
if (r.nowVisible && r.state == RESUMED) {
outResult.timeout = false;
@@ -632,119 +751,383 @@ public class ActivityStarter {
}
}
- final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
- boolean doResume, ActivityOptions options, TaskRecord inTask) {
- final Intent intent = r.intent;
- final int callingUid = r.launchedFromUid;
+ final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
+ Intent[] intents, String[] resolvedTypes, IBinder resultTo,
+ Bundle bOptions, int userId) {
+ if (intents == null) {
+ throw new NullPointerException("intents is null");
+ }
+ if (resolvedTypes == null) {
+ throw new NullPointerException("resolvedTypes is null");
+ }
+ if (intents.length != resolvedTypes.length) {
+ throw new IllegalArgumentException("intents are length different than resolvedTypes");
+ }
- final Rect newBounds = mSupervisor.getOverrideBounds(r, options, inTask);
- final boolean overrideBounds = newBounds != null;
- // In some flows in to this function, we retrieve the task record and hold on to it
- // without a lock before calling back in to here... so the task at this point may
- // not actually be in recents. Check for that, and if it isn't in recents just
- // consider it invalid.
- if (inTask != null && !inTask.inRecents) {
- Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
- inTask = null;
- }
-
- final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
- final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
- final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
- int launchFlags = adjustLaunchFlagsToDocumentMode(r, launchSingleInstance, launchSingleTask,
- intent.getFlags());
- final boolean launchTaskBehind = r.mLaunchTaskBehind
- && !launchSingleTask && !launchSingleInstance
- && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
-
- if (r.resultTo != null && (launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
- && r.resultTo.task.stack != null) {
- // For whatever reason this activity is being launched into a new
- // task... yet the caller has requested a result back. Well, that
- // is pretty messed up, so instead immediately send back a cancel
- // and let the new task continue launched as normal without a
- // dependency on its originator.
- Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
- r.resultTo.task.stack.sendActivityResultLocked(-1,
- r.resultTo, r.resultWho, r.requestCode,
- Activity.RESULT_CANCELED, null);
- r.resultTo = null;
+ int callingPid;
+ if (callingUid >= 0) {
+ callingPid = -1;
+ } else if (caller == null) {
+ callingPid = Binder.getCallingPid();
+ callingUid = Binder.getCallingUid();
+ } else {
+ callingPid = callingUid = -1;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mService) {
+ ActivityRecord[] outActivity = new ActivityRecord[1];
+ for (int i=0; i<intents.length; i++) {
+ Intent intent = intents[i];
+ if (intent == null) {
+ continue;
+ }
+
+ // Refuse possible leaked file descriptors
+ if (intent != null && intent.hasFileDescriptors()) {
+ throw new IllegalArgumentException("File descriptors passed in Intent");
+ }
+
+ boolean componentSpecified = intent.getComponent() != null;
+
+ // Don't modify the client's object!
+ intent = new Intent(intent);
+
+ // Collect information about the target of the Intent.
+ ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
+ null, userId);
+ // TODO: New, check if this is correct
+ aInfo = mService.getActivityInfoForUser(aInfo, userId);
+
+ if (aInfo != null &&
+ (aInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
+ throw new IllegalArgumentException(
+ "FLAG_CANT_SAVE_STATE not supported here");
+ }
+
+ ActivityOptions options = ActivityOptions.fromBundle(
+ i == intents.length - 1 ? bOptions : null);
+ int res = startActivityLocked(caller, intent, null /*ephemeralIntent*/,
+ resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
+ callingPid, callingUid, callingPackage, callingPid, callingUid, 0,
+ options, false, componentSpecified, outActivity, null, null);
+ if (res < 0) {
+ return res;
+ }
+
+ resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
- launchFlags |= FLAG_ACTIVITY_NEW_TASK;
+ return START_SUCCESS;
+ }
+
+ private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+
+ setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
+ voiceInteractor);
+
+ computeLaunchingTaskFlags();
+
+ computeSourceStack();
+
+ mIntent.setFlags(mLaunchFlags);
+
+ ActivityRecord intentActivity = getReusableIntentActivity();
+
+ if (intentActivity != null) {
+ // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
+ // still needs to be a lock task mode violation since the task gets cleared out and
+ // the device would otherwise leave the locked task.
+ if (mSupervisor.isLockTaskModeViolation(intentActivity.task,
+ (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+ == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
+ mSupervisor.showLockTaskToast();
+ Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+
+ if (mStartActivity.task == null) {
+ mStartActivity.task = intentActivity.task;
+ }
+ if (intentActivity.task.intent == null) {
+ // This task was started because of movement of the activity based on affinity...
+ // Now that we are actually launching it, we can assign the base intent.
+ intentActivity.task.setIntent(mStartActivity);
+ }
+
+ intentActivity = setTargetStackAndMoveToFrontIfNeeded(intentActivity);
+
+ if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+ // We don't need to start a new activity, and the client said not to do anything
+ // if that is the case, so this is it! And for paranoia, make sure we have
+ // correctly resumed the top activity.
+ resumeTargetStackIfNeeded();
+ return START_RETURN_INTENT_TO_CALLER;
+ }
+
+ setTaskFromIntentActivity(intentActivity);
+
+ if (!mAddingToTask && mReuseTask == null) {
+ // We didn't do anything... but it was needed (a.k.a., client don't use that
+ // intent!) And for paranoia, make sure we have correctly resumed the top activity.
+ resumeTargetStackIfNeeded();
+ return START_TASK_TO_FRONT;
+ }
+ }
+
+ if (mStartActivity.packageName == null) {
+ if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
+ mStartActivity.resultTo.task.stack.sendActivityResultLocked(
+ -1, mStartActivity.resultTo, mStartActivity.resultWho,
+ mStartActivity.requestCode, RESULT_CANCELED, null);
+ }
+ ActivityOptions.abort(mOptions);
+ return START_CLASS_NOT_FOUND;
+ }
+
+ // If the activity being launched is the same as the one currently at the top, then
+ // we need to check if it should only be launched once.
+ final ActivityStack topStack = mSupervisor.mFocusedStack;
+ final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
+ final boolean dontStart = top != null && mStartActivity.resultTo == null
+ && top.realActivity.equals(mStartActivity.realActivity)
+ && top.userId == mStartActivity.userId
+ && top.app != null && top.app.thread != null
+ && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
+ || mLaunchSingleTop || mLaunchSingleTask);
+ if (dontStart) {
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
+ // For paranoia, make sure we have correctly resumed the top activity.
+ topStack.mLastPausedActivity = null;
+ if (mDoResume) {
+ mSupervisor.resumeFocusedStackTopActivityLocked();
+ }
+ ActivityOptions.abort(mOptions);
+ if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+ // We don't need to start a new activity, and the client said not to do
+ // anything if that is the case, so this is it!
+ return START_RETURN_INTENT_TO_CALLER;
+ }
+ top.deliverNewIntentLocked(
+ mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ return START_DELIVERED_TO_TOP;
+ }
+
+ boolean newTask = false;
+ final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
+ ? mSourceRecord.task : null;
+
+ // Should this be considered a new task?
+ if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
+ && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+ newTask = true;
+ setTaskFromReuseOrCreateNewTask(taskToAffiliate);
+
+ if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+ if (!mMovedHome
+ && (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+ == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
+ // Caller wants to appear on home activity, so before starting
+ // their own activity we will bring home to the front.
+ mStartActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+ }
+ } else if (mSourceRecord != null) {
+ if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+
+ final int result = setTaskFromSourceRecord();
+ if (result != START_SUCCESS) {
+ return result;
+ }
+ } else if (mInTask != null) {
+ // The caller is asking that the new activity be started in an explicit
+ // task it has provided to us.
+ if (mSupervisor.isLockTaskModeViolation(mInTask)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+
+ final int result = setTaskFromInTask();
+ if (result != START_SUCCESS) {
+ return result;
+ }
+ } else {
+ // This not being started from an existing activity, and not part of a new task...
+ // just put it in the top task, though these days this case should never happen.
+ setTaskToCurrentTopOrCreateNewTask();
+ }
+
+ mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
+ mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
+
+ if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
+ mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
+ }
+ if (newTask) {
+ EventLog.writeEvent(
+ EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
+ }
+ ActivityStack.logStartActivity(
+ EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
+ mTargetStack.mLastPausedActivity = null;
+ mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
+ if (mDoResume) {
+ if (!mLaunchTaskBehind) {
+ // TODO(b/26381750): Remove this code after verification that all the decision
+ // points above moved targetStack to the front which will also set the focus
+ // activity.
+ mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
+ }
+ mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
+ mOptions);
+ } else {
+ mTargetStack.addRecentActivityLocked(mStartActivity);
+ }
+ mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
+
+ if (!mStartActivity.task.mResizeable
+ && mSupervisor.isStackDockedInEffect(mTargetStack.mStackId)) {
+ mSupervisor.showNonResizeableDockToast(mStartActivity.task.taskId);
+ }
+
+ return START_SUCCESS;
+ }
+
+ private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
+ boolean doResume, int startFlags, ActivityRecord sourceRecord,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
+ reset();
+
+ mStartActivity = r;
+ mIntent = r.intent;
+ mOptions = options;
+ mCallingUid = r.launchedFromUid;
+ mSourceRecord = sourceRecord;
+ mVoiceSession = voiceSession;
+ mVoiceInteractor = voiceInteractor;
+
+ mLaunchBounds = getOverrideBounds(r, options, inTask);
+
+ mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;
+ mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
+ mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
+ mLaunchFlags = adjustLaunchFlagsToDocumentMode(
+ r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
+ mLaunchTaskBehind = r.mLaunchTaskBehind
+ && !mLaunchSingleTask && !mLaunchSingleInstance
+ && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
+
+ sendNewTaskResultRequestIfNeeded();
+
+ if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
+ mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
// If we are actually going to launch in to a new task, there are some cases where
// we further want to do multiple task.
- if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
- if (launchTaskBehind
- || r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {
- launchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
+ if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+ if (mLaunchTaskBehind
+ || r.info.documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS) {
+ mLaunchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
}
}
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
- mSupervisor.mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
+ mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
"startActivity() => mUserLeaving=" + mSupervisor.mUserLeaving);
// If the caller has asked not to resume at this point, we make note
// of this in the record so that we can skip it when trying to find
// the top running activity.
+ mDoResume = doResume;
if (!doResume || !mSupervisor.okToShowLocked(r)) {
r.delayedResume = true;
- doResume = false;
+ mDoResume = false;
}
- final ActivityRecord notTop =
- (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
+ mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
+
+ mInTask = inTask;
+ // In some flows in to this function, we retrieve the task record and hold on to it
+ // without a lock before calling back in to here... so the task at this point may
+ // not actually be in recents. Check for that, and if it isn't in recents just
+ // consider it invalid.
+ if (inTask != null && !inTask.inRecents) {
+ Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
+ mInTask = null;
+ }
- // If the onlyIfNeeded flag is set, then we can do this if the activity
- // being launched is the same as the one making the call... or, as
- // a special case, if we do not know the caller then we count the
- // current top activity as the caller.
- if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
+ mStartFlags = startFlags;
+ // If the onlyIfNeeded flag is set, then we can do this if the activity being launched
+ // is the same as the one making the call... or, as a special case, if we do not know
+ // the caller then we count the current top activity as the caller.
+ if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
ActivityRecord checkedCaller = sourceRecord;
if (checkedCaller == null) {
checkedCaller = mSupervisor.mFocusedStack.topRunningNonDelayedActivityLocked(
- notTop);
+ mNotTop);
}
if (!checkedCaller.realActivity.equals(r.realActivity)) {
// Caller is not the same as launcher, so always needed.
- startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
+ mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
}
}
- boolean addingToTask = false;
- TaskRecord reuseTask = null;
+ mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
+ }
- // If the caller is not coming from another activity, but has given us an
- // explicit task into which they would like us to launch the new activity,
- // then let's see about doing that.
- if (sourceRecord == null && inTask != null && inTask.stack != null) {
- final Intent baseIntent = inTask.getBaseIntent();
- final ActivityRecord root = inTask.getRootActivity();
+ private void sendNewTaskResultRequestIfNeeded() {
+ if (mStartActivity.resultTo != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
+ && mStartActivity.resultTo.task.stack != null) {
+ // For whatever reason this activity is being launched into a new task...
+ // yet the caller has requested a result back. Well, that is pretty messed up,
+ // so instead immediately send back a cancel and let the new task continue launched
+ // as normal without a dependency on its originator.
+ Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
+ mStartActivity.resultTo.task.stack.sendActivityResultLocked(-1, mStartActivity.resultTo,
+ mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED, null);
+ mStartActivity.resultTo = null;
+ }
+ }
+
+ private void computeLaunchingTaskFlags() {
+ // If the caller is not coming from another activity, but has given us an explicit task into
+ // which they would like us to launch the new activity, then let's see about doing that.
+ if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
+ final Intent baseIntent = mInTask.getBaseIntent();
+ final ActivityRecord root = mInTask.getRootActivity();
if (baseIntent == null) {
- ActivityOptions.abort(options);
+ ActivityOptions.abort(mOptions);
throw new IllegalArgumentException("Launching into task without base intent: "
- + inTask);
+ + mInTask);
}
// If this task is empty, then we are adding the first activity -- it
// determines the root, and must be launching as a NEW_TASK.
- if (launchSingleInstance || launchSingleTask) {
- if (!baseIntent.getComponent().equals(r.intent.getComponent())) {
- ActivityOptions.abort(options);
+ if (mLaunchSingleInstance || mLaunchSingleTask) {
+ if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
+ ActivityOptions.abort(mOptions);
throw new IllegalArgumentException("Trying to launch singleInstance/Task "
- + r + " into different task " + inTask);
+ + mStartActivity + " into different task " + mInTask);
}
if (root != null) {
- ActivityOptions.abort(options);
- throw new IllegalArgumentException("Caller with inTask " + inTask
+ ActivityOptions.abort(mOptions);
+ throw new IllegalArgumentException("Caller with mInTask " + mInTask
+ " has root " + root + " but target is singleInstance/Task");
}
}
@@ -752,533 +1135,405 @@ public class ActivityStarter {
// If task is empty, then adopt the interesting intent launch flags in to the
// activity being started.
if (root == null) {
- final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK
- | FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT
- | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
- launchFlags = (launchFlags&~flagsOfInterest)
- | (baseIntent.getFlags()&flagsOfInterest);
- intent.setFlags(launchFlags);
- inTask.setIntent(r);
- addingToTask = true;
-
- // If the task is not empty and the caller is asking to start it as the root
- // of a new task, then we don't actually want to start this on the task. We
- // will bring the task to the front, and possibly give it a new intent.
- } else if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
- addingToTask = false;
+ final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
+ | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+ mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
+ | (baseIntent.getFlags() & flagsOfInterest);
+ mIntent.setFlags(mLaunchFlags);
+ mInTask.setIntent(mStartActivity);
+ mAddingToTask = true;
+
+ // If the task is not empty and the caller is asking to start it as the root of
+ // a new task, then we don't actually want to start this on the task. We will
+ // bring the task to the front, and possibly give it a new intent.
+ } else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+ mAddingToTask = false;
} else {
- addingToTask = true;
+ mAddingToTask = true;
}
- reuseTask = inTask;
+ mReuseTask = mInTask;
} else {
- inTask = null;
- // Launch ResolverActivity in the source task, so that it stays in the task
- // bounds when in freeform workspace.
- // Also put noDisplay activities in the source task. These by itself can
- // be placed in any task/stack, however it could launch other activities
- // like ResolverActivity, and we want those to stay in the original task.
- if ((r.isResolverActivity() || r.noDisplay) && sourceRecord != null
- && sourceRecord.isFreeform()) {
- addingToTask = true;
+ mInTask = null;
+ // Launch ResolverActivity in the source task, so that it stays in the task bounds
+ // when in freeform workspace.
+ // Also put noDisplay activities in the source task. These by itself can be placed
+ // in any task/stack, however it could launch other activities like ResolverActivity,
+ // and we want those to stay in the original task.
+ if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
+ && mSourceRecord.isFreeform()) {
+ mAddingToTask = true;
}
}
- if (inTask == null) {
- if (sourceRecord == null) {
+ if (mInTask == null) {
+ if (mSourceRecord == null) {
// This activity is not being started from another... in this
// case we -always- start a new task.
- if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
+ if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
- "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
- launchFlags |= FLAG_ACTIVITY_NEW_TASK;
+ "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
+ mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
- } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
+ } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
// The original activity who is starting us is running as a single
// instance... this new activity it is starting must go on its
// own task.
- launchFlags |= FLAG_ACTIVITY_NEW_TASK;
- } else if (launchSingleInstance || launchSingleTask) {
+ mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+ } else if (mLaunchSingleInstance || mLaunchSingleTask) {
// The activity being started is a single instance... it always
// gets launched into its own task.
- launchFlags |= FLAG_ACTIVITY_NEW_TASK;
+ mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
}
+ }
- ActivityInfo newTaskInfo = null;
- Intent newTaskIntent = null;
- final ActivityStack sourceStack;
- if (sourceRecord != null) {
- if (sourceRecord.finishing) {
- // If the source is finishing, we can't further count it as our source. This
- // is because the task it is associated with may now be empty and on its way out,
- // so we don't want to blindly throw it in to that task. Instead we will take
- // the NEW_TASK flow and try to find a task for it. But save the task information
- // so it can be used when creating the new task.
- if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
- Slog.w(TAG, "startActivity called from finishing " + sourceRecord
- + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
- launchFlags |= FLAG_ACTIVITY_NEW_TASK;
- newTaskInfo = sourceRecord.info;
- newTaskIntent = sourceRecord.task.intent;
- }
- sourceRecord = null;
- sourceStack = null;
- } else {
- sourceStack = sourceRecord.task.stack;
- }
- } else {
- sourceStack = null;
+ private void computeSourceStack() {
+ if (mSourceRecord == null) {
+ mSourceStack = null;
+ return;
+ }
+ if (!mSourceRecord.finishing) {
+ mSourceStack = mSourceRecord.task.stack;
+ return;
}
- boolean movedHome = false;
- ActivityStack targetStack;
-
- intent.setFlags(launchFlags);
- final boolean noAnimation = (launchFlags & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0;
+ // If the source is finishing, we can't further count it as our source. This is because the
+ // task it is associated with may now be empty and on its way out, so we don't want to
+ // blindly throw it in to that task. Instead we will take the NEW_TASK flow and try to find
+ // a task for it. But save the task information so it can be used when creating the new task.
+ if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
+ Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
+ + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
+ mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+ mNewTaskInfo = mSourceRecord.info;
+ mNewTaskIntent = mSourceRecord.task.intent;
+ }
+ mSourceRecord = null;
+ mSourceStack = null;
+ }
- ActivityRecord intentActivity = getReusableIntentActivity(r, inTask, intent,
- launchSingleInstance, launchSingleTask, launchFlags);
- if (intentActivity != null) {
- // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused
- // but still needs to be a lock task mode violation since the task gets
- // cleared out and the device would otherwise leave the locked task.
- if (mSupervisor.isLockTaskModeViolation(intentActivity.task,
- (launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
- == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
- mSupervisor.showLockTaskToast();
- Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
- return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
- if (r.task == null) {
- r.task = intentActivity.task;
- }
- if (intentActivity.task.intent == null) {
- // This task was started because of movement of the activity based on affinity...
- // Now that we are actually launching it, we can assign the base intent.
- intentActivity.task.setIntent(r);
- }
+ /**
+ * Decide whether the new activity should be inserted into an existing task. Returns null
+ * if not or an ActivityRecord with the task into which the new activity should be added.
+ */
+ private ActivityRecord getReusableIntentActivity() {
+ // We may want to try to place the new activity in to an existing task. We always
+ // do this if the target activity is singleTask or singleInstance; we will also do
+ // this if NEW_TASK has been requested, and there is not an additional qualifier telling
+ // us to still place it in a new task: multi task, always doc mode, or being asked to
+ // launch this as a new task behind the current one.
+ boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
+ (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
+ || mLaunchSingleInstance || mLaunchSingleTask;
+ // If bring to front is requested, and no result is requested and we have not been given
+ // an explicit task to launch in to, and we can find a task that was started with this
+ // same component, then instead of launching bring that one to the front.
+ putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
+ ActivityRecord intentActivity = null;
+ if (putIntoExistingTask) {
+ // See if there is a task to bring to the front. If this is a SINGLE_INSTANCE
+ // activity, there can be one and only one instance of it in the history, and it is
+ // always in its own unique task, so we do a special search.
+ intentActivity = mLaunchSingleInstance ? mSupervisor.findActivityLocked(mIntent, mStartActivity.info)
+ : mSupervisor.findTaskLocked(mStartActivity);
+ }
+ return intentActivity;
+ }
- targetStack = intentActivity.task.stack;
- targetStack.mLastPausedActivity = null;
- // If the target task is not in the front, then we need
- // to bring it to the front... except... well, with
- // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
- // to have the same behavior as if a new instance was
- // being started, which means not bringing it to the front
- // if the caller is not itself in the front.
- final ActivityStack focusStack = mSupervisor.getFocusedStack();
- ActivityRecord curTop = (focusStack == null)
- ? null : focusStack.topRunningNonDelayedActivityLocked(notTop);
- boolean movedToFront = false;
- if (curTop != null && (curTop.task != intentActivity.task ||
- curTop.task != focusStack.topTask())) {
- r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
- if (sourceRecord == null || (sourceStack.topActivity() != null &&
- sourceStack.topActivity().task == sourceRecord.task)) {
- // We really do want to push this one into the user's face, right now.
- if (launchTaskBehind && sourceRecord != null) {
- intentActivity.setTaskToAffiliateWith(sourceRecord.task);
- }
- movedHome = true;
- final ActivityStack sideStack = getLaunchToSideStack(r, launchFlags, r.task);
- if (sideStack == null || sideStack == targetStack) {
- // We only want to move to the front, if we aren't going to launch on a
- // different stack. If we launch on a different stack, we will put the
- // task on top there.
- targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
- options, r.appTimeTracker, "bringingFoundTaskToFront");
- movedToFront = true;
- }
- if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
- == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
- // Caller wants to appear on home activity.
- intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
- }
- options = null;
+ private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
+ mTargetStack = intentActivity.task.stack;
+ mTargetStack.mLastPausedActivity = null;
+ // If the target task is not in the front, then we need to bring it to the front...
+ // except... well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
+ // the same behavior as if a new instance was being started, which means not bringing it
+ // to the front if the caller is not itself in the front.
+ final ActivityStack focusStack = mSupervisor.getFocusedStack();
+ ActivityRecord curTop = (focusStack == null)
+ ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
+
+ if (curTop != null && (curTop.task != intentActivity.task ||
+ curTop.task != focusStack.topTask())) {
+ mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
+ if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
+ mSourceStack.topActivity().task == mSourceRecord.task)) {
+ // We really do want to push this one into the user's face, right now.
+ if (mLaunchTaskBehind && mSourceRecord != null) {
+ intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
}
- }
- if (!movedToFront && doResume) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
- + " from " + intentActivity);
- targetStack.moveToFront("intentActivityFound");
- }
-
- // If the caller has requested that the target task be
- // reset, then do so.
- if ((launchFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
- intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
- }
- if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
- // We don't need to start a new activity, and
- // the client said not to do anything if that
- // is the case, so this is it! And for paranoia, make
- // sure we have correctly resumed the top activity.
- if (doResume) {
- mSupervisor.resumeTopActivitiesLocked(targetStack, null, options);
-
- // Make sure to notify Keyguard as well if we are not running an app
- // transition later.
- if (!movedToFront) {
- mSupervisor.notifyActivityDrawnForKeyguard();
- }
- } else {
- ActivityOptions.abort(options);
+ mMovedHome = true;
+ final ActivityStack launchStack =
+ getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
+ mOptions, true);
+ if (launchStack == null || launchStack == mTargetStack) {
+ // We only want to move to the front, if we aren't going to launch on a
+ // different stack. If we launch on a different stack, we will put the
+ // task on top there.
+ mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
+ mOptions, mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
+ mMovedToFront = true;
}
- mSupervisor.updateUserStackLocked(r.userId, targetStack);
- return ActivityManager.START_RETURN_INTENT_TO_CALLER;
+ if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+ == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
+ // Caller wants to appear on home activity.
+ intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+ }
+ mOptions = null;
}
- if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
- == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
- // The caller has requested to completely replace any
- // existing task with its new activity. Well that should
- // not be too hard...
- reuseTask = intentActivity.task;
- reuseTask.performClearTaskLocked();
- reuseTask.setIntent(r);
- } else if ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
- || launchSingleInstance || launchSingleTask) {
- // In this situation we want to remove all activities
- // from the task up to the one being started. In most
- // cases this means we are resetting the task to its
- // initial state.
- ActivityRecord top = intentActivity.task.performClearTaskLocked(r, launchFlags);
- if (top != null) {
- if (top.frontOfTask) {
- // Activity aliases may mean we use different
- // intents for the top activity, so make sure
- // the task now has the identity of the new
- // intent.
- top.task.setIntent(r);
- }
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
- top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
- } else {
- // A special case: we need to start the activity because it is not
- // currently running, and the caller has asked to clear the current
- // task to have this activity at the top.
- addingToTask = true;
- // Now pretend like this activity is being started by the top of its
- // task, so it is put in the right place.
- sourceRecord = intentActivity;
- TaskRecord task = sourceRecord.task;
- if (task != null && task.stack == null) {
- // Target stack got cleared when we all activities were removed
- // above. Go ahead and reset it.
- targetStack = computeStackFocus(
- sourceRecord, false /* newTask */, null /* bounds */, launchFlags);
- targetStack.addTask(task,
- !launchTaskBehind /* toTop */, "startActivityUnchecked");
- }
+ }
+ if (!mMovedToFront && mDoResume) {
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + mTargetStack
+ + " from " + intentActivity);
+ mTargetStack.moveToFront("intentActivityFound");
+ }
+ // If the caller has requested that the target task be reset, then do so.
+ if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+ return mTargetStack.resetTaskIfNeededLocked(intentActivity, mStartActivity);
+ }
+ return intentActivity;
+ }
+
+ private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
+ if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+ == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
+ // The caller has requested to completely replace any existing task with its new
+ // activity. Well that should not be too hard...
+ mReuseTask = intentActivity.task;
+ mReuseTask.performClearTaskLocked();
+ mReuseTask.setIntent(mStartActivity);
+ } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
+ || mLaunchSingleInstance || mLaunchSingleTask) {
+ // In this situation we want to remove all activities from the task up to the one
+ // being started. In most cases this means we are resetting the task to its initial
+ // state.
+ ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
+ mLaunchFlags);
+ if (top != null) {
+ if (top.frontOfTask) {
+ // Activity aliases may mean we use different intents for the top activity,
+ // so make sure the task now has the identity of the new intent.
+ top.task.setIntent(mStartActivity);
}
- } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
- // In this case the top activity on the task is the
- // same as the one being launched, so we take that
- // as a request to bring the task to the foreground.
- // If the top activity in the task is the root
- // activity, deliver this new intent to it if it
- // desires.
- if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
- && intentActivity.realActivity.equals(r.realActivity)) {
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
- intentActivity.task);
- if (intentActivity.frontOfTask) {
- intentActivity.task.setIntent(r);
- }
- intentActivity.deliverNewIntentLocked(callingUid, r.intent,
- r.launchedFromPackage);
- } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
- // 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.
- addingToTask = true;
- sourceRecord = intentActivity;
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, top.task);
+ top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ } else {
+ // A special case: we need to start the activity because it is not currently
+ // running, and the caller has asked to clear the current task to have this
+ // activity at the top.
+ mAddingToTask = true;
+ // Now pretend like this activity is being started by the top of its task, so it
+ // is put in the right place.
+ mSourceRecord = intentActivity;
+ final TaskRecord task = mSourceRecord.task;
+ if (task != null && task.stack == null) {
+ // Target stack got cleared when we all activities were removed above.
+ // Go ahead and reset it.
+ mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
+ null /* bounds */, mLaunchFlags, mOptions);
+ mTargetStack.addTask(task,
+ !mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
}
- } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
- // In this case an activity is being launched in to an
- // existing task, without resetting that task. This
- // is typically the situation of launching an activity
- // from a notification or shortcut. We want to place
- // the new activity on top of the current task.
- addingToTask = true;
- sourceRecord = intentActivity;
- } else if (!intentActivity.task.rootWasReset) {
- // In this case we are launching in to an existing task
- // that has not yet been started from its front door.
- // The current task has been brought to the front.
- // Ideally, we'd probably like to place this new task
- // at the bottom of its stack, but that's a little hard
- // to do with the current organization of the code so
- // for now we'll just drop it.
- intentActivity.task.setIntent(r);
}
- if (!addingToTask && reuseTask == null) {
- // We didn't do anything... but it was needed (a.k.a., client
- // don't use that intent!) And for paranoia, make
- // sure we have correctly resumed the top activity.
- if (doResume) {
- targetStack.resumeTopActivityLocked(null, options);
- if (!movedToFront) {
- // Make sure to notify Keyguard as well if we are not running an app
- // transition later.
- mSupervisor.notifyActivityDrawnForKeyguard();
- }
- } else {
- ActivityOptions.abort(options);
+ } else if (mStartActivity.realActivity.equals(intentActivity.task.realActivity)) {
+ // In this case the top activity on the task is the same as the one being launched,
+ // so we take that as a request to bring the task to the foreground. If the top
+ // activity in the task is the root activity, deliver this new intent to it if it
+ // desires.
+ if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
+ && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity,
+ intentActivity.task);
+ if (intentActivity.frontOfTask) {
+ intentActivity.task.setIntent(mStartActivity);
}
- mSupervisor.updateUserStackLocked(r.userId, targetStack);
- return ActivityManager.START_TASK_TO_FRONT;
+ intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
+ mStartActivity.launchedFromPackage);
+ } else if (!mStartActivity.intent.filterEquals(intentActivity.task.intent)) {
+ // 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;
+ mSourceRecord = intentActivity;
}
+ } else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
+ // In this case an activity is being launched in to an existing task, without
+ // resetting that task. This is typically the situation of launching an activity
+ // from a notification or shortcut. We want to place the new activity on top of the
+ // current task.
+ mAddingToTask = true;
+ mSourceRecord = intentActivity;
+ } else if (!intentActivity.task.rootWasReset) {
+ // In this case we are launching into an existing task that has not yet been started
+ // from its front door. The current task has been brought to the front. Ideally,
+ // we'd probably like to place this new task at the bottom of its stack, but that's
+ // a little hard to do with the current organization of the code so for now we'll
+ // just drop it.
+ intentActivity.task.setIntent(mStartActivity);
}
+ }
- //String uri = r.intent.toURI();
- //Intent intent2 = new Intent(uri);
- //Slog.i(TAG, "Given intent: " + r.intent);
- //Slog.i(TAG, "URI is: " + uri);
- //Slog.i(TAG, "To intent: " + intent2);
-
- if (r.packageName != null) {
- // If the activity being launched is the same as the one currently
- // at the top, then we need to check if it should only be launched
- // once.
- ActivityStack topStack = mSupervisor.mFocusedStack;
- ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
- final boolean dontStart = top != null && r.resultTo == null
- && top.realActivity.equals(r.realActivity) && top.userId == r.userId
- && top.app != null && top.app.thread != null
- && ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
- || launchSingleTop || launchSingleTask);
- if (dontStart) {
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
- // For paranoia, make sure we have correctly resumed the top activity.
- topStack.mLastPausedActivity = null;
- if (doResume) {
- mSupervisor.resumeTopActivitiesLocked();
- }
- ActivityOptions.abort(options);
- if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
- // We don't need to start a new activity, and the client said not to do
- // anything if that is the case, so this is it!
- return ActivityManager.START_RETURN_INTENT_TO_CALLER;
- }
- top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
- return ActivityManager.START_DELIVERED_TO_TOP;
+ private void resumeTargetStackIfNeeded() {
+ if (mDoResume) {
+ mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, null, mOptions);
+ if (!mMovedToFront) {
+ // Make sure to notify Keyguard as well if we are not running an app transition
+ // later.
+ mSupervisor.notifyActivityDrawnForKeyguard();
}
} else {
- if (r.resultTo != null && r.resultTo.task.stack != null) {
- r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
- r.requestCode, Activity.RESULT_CANCELED, null);
- }
- ActivityOptions.abort(options);
- return ActivityManager.START_CLASS_NOT_FOUND;
+ ActivityOptions.abort(mOptions);
}
+ mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
+ }
- boolean newTask = false;
- boolean keepCurTransition = false;
-
- final TaskRecord taskToAffiliate = launchTaskBehind && sourceRecord != null ?
- sourceRecord.task : null;
+ private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
+ mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
+ mOptions);
+ if (mDoResume) {
+ mTargetStack.moveToFront("startingNewTask");
+ }
- // Should this be considered a new task?
- if (r.resultTo == null && inTask == null && !addingToTask
- && (launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
- newTask = true;
- targetStack = computeStackFocus(r, newTask, newBounds, launchFlags);
- if (doResume) {
- targetStack.moveToFront("startingNewTask");
+ if (mReuseTask == null) {
+ final TaskRecord task = mTargetStack.createTaskRecord(mSupervisor.getNextTaskId(),
+ mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
+ mNewTaskIntent != null ? mNewTaskIntent : mIntent,
+ mVoiceSession, mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
+ mStartActivity.setTask(task, taskToAffiliate);
+ if (mLaunchBounds != null) {
+ mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
}
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+ "Starting new activity " +
+ mStartActivity + " in new task " + mStartActivity.task);
+ } else {
+ mStartActivity.setTask(mReuseTask, taskToAffiliate);
+ }
+ }
- if (reuseTask == null) {
- r.setTask(targetStack.createTaskRecord(mSupervisor.getNextTaskId(),
- newTaskInfo != null ? newTaskInfo : r.info,
- newTaskIntent != null ? newTaskIntent : intent,
- voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
- taskToAffiliate);
- if (overrideBounds) {
- r.task.updateOverrideConfiguration(newBounds);
- }
- if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Starting new activity " + r + " in new task " + r.task);
- } else {
- r.setTask(reuseTask, taskToAffiliate);
- }
- if (mSupervisor.isLockTaskModeViolation(r.task)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
- return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
- if (!movedHome) {
- if ((launchFlags &
- (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
- == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
- // Caller wants to appear on home activity, so before starting
- // their own activity we will bring home to the front.
- r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
- }
- }
- } else if (sourceRecord != null) {
- final TaskRecord sourceTask = sourceRecord.task;
- if (mSupervisor.isLockTaskModeViolation(sourceTask)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
- return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
- targetStack = null;
- if (sourceTask.stack.topTask() != sourceTask) {
- // We only want to allow changing stack if the target task is not the top one,
- // otherwise we would move the launching task to the other side, rather than show
- // two side by side.
- targetStack = getLaunchToSideStack(r, launchFlags, r.task);
- }
- if (targetStack == null) {
- targetStack = sourceTask.stack;
- } else if (targetStack != sourceTask.stack) {
- mSupervisor.moveTaskToStackLocked(sourceTask.taskId, targetStack.mStackId,
- ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
- }
- if (doResume) {
- targetStack.moveToFront("sourceStackToFront");
- }
- final TaskRecord topTask = targetStack.topTask();
- if (topTask != sourceTask) {
- targetStack.moveTaskToFrontLocked(sourceTask, noAnimation, options,
- r.appTimeTracker, "sourceTaskToFront");
- }
- if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
- // In this case, we are adding the activity to an existing
- // task, but the caller has asked to clear that task if the
- // activity is already running.
- ActivityRecord top = sourceTask.performClearTaskLocked(r, launchFlags);
- keepCurTransition = true;
- if (top != null) {
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
- top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
- // For paranoia, make sure we have correctly
- // resumed the top activity.
- targetStack.mLastPausedActivity = null;
- if (doResume) {
- targetStack.resumeTopActivityLocked(null);
- }
- ActivityOptions.abort(options);
- return ActivityManager.START_DELIVERED_TO_TOP;
- }
- } else if (!addingToTask &&
- (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
- // In this case, we are launching an activity in our own task
- // that may already be running somewhere in the history, and
- // we want to shuffle it to the front of the stack if so.
- final ActivityRecord top = sourceTask.findActivityInHistoryLocked(r);
- if (top != null) {
- final TaskRecord task = top.task;
- task.moveActivityToFrontLocked(top);
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);
- top.updateOptionsLocked(options);
- top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
- targetStack.mLastPausedActivity = null;
- if (doResume) {
- targetStack.resumeTopActivityLocked(null);
- }
- return ActivityManager.START_DELIVERED_TO_TOP;
- }
- }
- // An existing activity is starting this new activity, so we want
- // to keep the new one in the same task as the one that is starting
- // it.
- r.setTask(sourceTask, null);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
- + " in existing task " + r.task + " from source " + sourceRecord);
-
- } else if (inTask != null) {
- // The caller is asking that the new activity be started in an explicit
- // task it has provided to us.
- if (mSupervisor.isLockTaskModeViolation(inTask)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
- return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
- if (overrideBounds) {
- inTask.updateOverrideConfiguration(newBounds);
- int stackId = inTask.getLaunchStackId();
- if (stackId != inTask.stack.mStackId) {
- mSupervisor.moveTaskToStackUncheckedLocked(
- inTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
+ private int setTaskFromSourceRecord() {
+ final TaskRecord sourceTask = mSourceRecord.task;
+ // We only want to allow changing stack if the target task is not the top one,
+ // otherwise we would move the launching task to the other side, rather than show
+ // two side by side.
+ final boolean launchToSideAllowed = sourceTask.stack.topTask() != sourceTask;
+ mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, launchToSideAllowed);
+
+ if (mTargetStack == null) {
+ mTargetStack = sourceTask.stack;
+ } else if (mTargetStack != sourceTask.stack) {
+ mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId,
+ ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
+ }
+ if (mDoResume) {
+ mTargetStack.moveToFront("sourceStackToFront");
+ }
+ final TaskRecord topTask = mTargetStack.topTask();
+ if (topTask != sourceTask) {
+ mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions,
+ mStartActivity.appTimeTracker, "sourceTaskToFront");
+ }
+ if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
+ // In this case, we are adding the activity to an existing task, but the caller has
+ // asked to clear that task if the activity is already running.
+ ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags);
+ mKeepCurTransition = true;
+ if (top != null) {
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, top.task);
+ top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ // For paranoia, make sure we have correctly resumed the top activity.
+ mTargetStack.mLastPausedActivity = null;
+ if (mDoResume) {
+ mSupervisor.resumeFocusedStackTopActivityLocked();
}
+ ActivityOptions.abort(mOptions);
+ return START_DELIVERED_TO_TOP;
}
- targetStack = inTask.stack;
- targetStack.moveTaskToFrontLocked(inTask, noAnimation, options, r.appTimeTracker,
- "inTaskToFront");
-
- // Check whether we should actually launch the new activity in to the task,
- // or just reuse the current activity on top.
- ActivityRecord top = inTask.getTopActivity();
- if (top != null && top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
- if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
- || launchSingleTop || launchSingleTask) {
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
- if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
- // We don't need to start a new activity, and
- // the client said not to do anything if that
- // is the case, so this is it!
- return ActivityManager.START_RETURN_INTENT_TO_CALLER;
- }
- top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
- return ActivityManager.START_DELIVERED_TO_TOP;
+ } else if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
+ // In this case, we are launching an activity in our own task that may already be
+ // running somewhere in the history, and we want to shuffle it to the front of the
+ // stack if so.
+ final ActivityRecord top = sourceTask.findActivityInHistoryLocked(mStartActivity);
+ if (top != null) {
+ final TaskRecord task = top.task;
+ task.moveActivityToFrontLocked(top);
+ top.updateOptionsLocked(mOptions);
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, task);
+ top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ mTargetStack.mLastPausedActivity = null;
+ if (mDoResume) {
+ mSupervisor.resumeFocusedStackTopActivityLocked();
}
+ return START_DELIVERED_TO_TOP;
}
-
- if (!addingToTask) {
- // We don't actually want to have this activity added to the task, so just
- // stop here but still tell the caller that we consumed the intent.
- ActivityOptions.abort(options);
- return ActivityManager.START_TASK_TO_FRONT;
- }
-
- r.setTask(inTask, null);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
- + " in explicit task " + r.task);
-
- } else {
- // This not being started from an existing activity, and not part
- // of a new task... just put it in the top task, though these days
- // this case should never happen.
- targetStack = computeStackFocus(r, newTask, null /* bounds */, launchFlags);
- if (doResume) {
- targetStack.moveToFront("addingToTopTask");
- }
- ActivityRecord prev = targetStack.topActivity();
- r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(
- mSupervisor.getNextTaskId(), r.info, intent, null, null, true), null);
- mWindowManager.moveTaskToTop(r.task.taskId);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
- + " in new guessed " + r.task);
}
- mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
- intent, r.getUriPermissionsLocked(), r.userId);
+ // An existing activity is starting this new activity, so we want to keep the new one in
+ // the same task as the one that is starting it.
+ mStartActivity.setTask(sourceTask, null);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ + " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
+ return START_SUCCESS;
+ }
- if (sourceRecord != null && sourceRecord.isRecentsActivity()) {
- r.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
+ private int setTaskFromInTask() {
+ if (mLaunchBounds != null) {
+ mInTask.updateOverrideConfiguration(mLaunchBounds);
+ int stackId = mInTask.getLaunchStackId();
+ if (stackId != mInTask.stack.mStackId) {
+ mSupervisor.moveTaskToStackUncheckedLocked(
+ mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
+ }
}
- if (newTask) {
- EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
- }
- ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
- targetStack.mLastPausedActivity = null;
- targetStack.startActivityLocked(r, newTask, keepCurTransition, options);
- if (doResume) {
- if (!launchTaskBehind) {
- mService.setFocusedActivityLocked(r, "startedActivity");
+ mTargetStack = mInTask.stack;
+ mTargetStack.moveTaskToFrontLocked(
+ mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");
+
+ // Check whether we should actually launch the new activity in to the task,
+ // or just reuse the current activity on top.
+ ActivityRecord top = mInTask.getTopActivity();
+ if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) {
+ if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
+ || mLaunchSingleTop || mLaunchSingleTask) {
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
+ if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+ // We don't need to start a new activity, and the client said not to do
+ // anything if that is the case, so this is it!
+ return START_RETURN_INTENT_TO_CALLER;
+ }
+ top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ return START_DELIVERED_TO_TOP;
}
- mSupervisor.resumeTopActivitiesLocked(targetStack, r, options);
- } else {
- targetStack.addRecentActivityLocked(r);
}
- mSupervisor.updateUserStackLocked(r.userId, targetStack);
- if (!r.task.mResizeable && mSupervisor.isStackDockedInEffect(targetStack.mStackId)) {
- mSupervisor.showNonResizeableDockToast(r.task.taskId);
+ if (!mAddingToTask) {
+ // We don't actually want to have this activity added to the task, so just
+ // stop here but still tell the caller that we consumed the intent.
+ ActivityOptions.abort(mOptions);
+ return START_TASK_TO_FRONT;
}
- return ActivityManager.START_SUCCESS;
+ mStartActivity.setTask(mInTask, null);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+ "Starting new activity " + mStartActivity + " in explicit task " + mStartActivity.task);
+
+ return START_SUCCESS;
+ }
+
+ private void setTaskToCurrentTopOrCreateNewTask() {
+ mTargetStack = computeStackFocus(mStartActivity, false, null /* bounds */, mLaunchFlags,
+ mOptions);
+ if (mDoResume) {
+ mTargetStack.moveToFront("addingToTopTask");
+ }
+ final ActivityRecord prev = mTargetStack.topActivity();
+ final TaskRecord task = prev != null ? prev.task
+ : mTargetStack.createTaskRecord(
+ mSupervisor.getNextTaskId(), mStartActivity.info, mIntent, null, null, true);
+ mStartActivity.setTask(task, null);
+ mWindowManager.moveTaskToTop(mStartActivity.task.taskId);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+ "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
}
private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
@@ -1308,90 +1563,13 @@ public class ActivityStarter {
return launchFlags;
}
- final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
- Intent[] intents, String[] resolvedTypes, IBinder resultTo,
- Bundle bOptions, int userId) {
- if (intents == null) {
- throw new NullPointerException("intents is null");
- }
- if (resolvedTypes == null) {
- throw new NullPointerException("resolvedTypes is null");
- }
- if (intents.length != resolvedTypes.length) {
- throw new IllegalArgumentException("intents are length different than resolvedTypes");
- }
-
-
- int callingPid;
- if (callingUid >= 0) {
- callingPid = -1;
- } else if (caller == null) {
- callingPid = Binder.getCallingPid();
- callingUid = Binder.getCallingUid();
- } else {
- callingPid = callingUid = -1;
- }
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (mService) {
- ActivityRecord[] outActivity = new ActivityRecord[1];
- for (int i=0; i<intents.length; i++) {
- Intent intent = intents[i];
- if (intent == null) {
- continue;
- }
-
- // Refuse possible leaked file descriptors
- if (intent != null && intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
-
- boolean componentSpecified = intent.getComponent() != null;
-
- // Don't modify the client's object!
- intent = new Intent(intent);
-
- // Collect information about the target of the Intent.
- ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
- null, userId);
- // TODO: New, check if this is correct
- aInfo = mService.getActivityInfoForUser(aInfo, userId);
-
- if (aInfo != null &&
- (aInfo.applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
- throw new IllegalArgumentException(
- "FLAG_CANT_SAVE_STATE not supported here");
- }
-
- ActivityOptions options = ActivityOptions.fromBundle(
- i == intents.length - 1 ? bOptions : null);
- int res = startActivityLocked(caller, intent, null /*ephemeralIntent*/,
- resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
- callingPid, callingUid, callingPackage, callingPid, callingUid, 0,
- options, false, componentSpecified, outActivity, null, null);
- if (res < 0) {
- return res;
- }
-
- resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
- }
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
-
- return ActivityManager.START_SUCCESS;
- }
-
final void doPendingActivityLaunchesLocked(boolean doResume) {
while (!mPendingActivityLaunches.isEmpty()) {
PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
try {
- startActivityUncheckedLocked(pal.r, pal.sourceRecord, null, null,
- pal.startFlags, doResume && mPendingActivityLaunches.isEmpty(),
- null, null);
+ startActivityUnchecked(pal.r, pal.sourceRecord, null, null, pal.startFlags,
+ doResume && mPendingActivityLaunches.isEmpty(), null, null);
} catch (Exception e) {
Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
pal.sendErrorResult(e.getMessage());
@@ -1400,13 +1578,13 @@ public class ActivityStarter {
}
private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds,
- int launchFlags) {
+ int launchFlags, ActivityOptions aOptions) {
final TaskRecord task = r.task;
if (!(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
return mSupervisor.mHomeStack;
}
- ActivityStack stack = getLaunchToSideStack(r, launchFlags, task);
+ ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions, true);
if (stack != null) {
return stack;
}
@@ -1442,7 +1620,7 @@ public class ActivityStarter {
final boolean canUseFocusedStack =
focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
|| focusedStackId == DOCKED_STACK_ID
- || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.info.resizeable);
+ || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeable());
if (canUseFocusedStack && (!newTask
|| mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
@@ -1471,10 +1649,19 @@ public class ActivityStarter {
return stack;
}
- private ActivityStack getLaunchToSideStack(ActivityRecord r, int launchFlags, TaskRecord task) {
- if ((launchFlags & FLAG_ACTIVITY_LAUNCH_TO_SIDE) == 0) {
+ private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
+ ActivityOptions aOptions, boolean launchToSideAllowed) {
+ final int launchStackId =
+ (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
+
+ if (isValidLaunchStackId(launchStackId, r)) {
+ return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
+ }
+
+ if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_TO_SIDE) == 0) {
return null;
}
+
// The parent activity doesn't want to launch the activity on top of itself, but
// instead tries to put it onto other side in side-by-side mode.
final ActivityStack parentStack = task != null ? task.stack
@@ -1498,36 +1685,39 @@ public class ActivityStarter {
}
}
- /**
- * Decide whether the new activity should be inserted into an existing task. Returns null if not
- * or an ActivityRecord with the task into which the new activity should be added.
- */
- private ActivityRecord getReusableIntentActivity(ActivityRecord r, TaskRecord inTask,
- Intent intent, boolean launchSingleInstance, boolean launchSingleTask,
- int launchFlags) {
- // We may want to try to place the new activity in to an existing task. We always
- // do this if the target activity is singleTask or singleInstance; we will also do
- // this if NEW_TASK has been requested, and there is not an additional qualifier telling
- // us to still place it in a new task: multi task, always doc mode, or being asked to
- // launch this as a new task behind the current one.
- boolean putIntoExistingTask = ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
- (launchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
- || launchSingleInstance || launchSingleTask;
- // If bring to front is requested, and no result is requested and we have not
- // been given an explicit task to launch in to, and
- // we can find a task that was started with this same
- // component, then instead of launching bring that one to the front.
- putIntoExistingTask &= inTask == null && r.resultTo == null;
- ActivityRecord intentActivity = null;
- if (putIntoExistingTask) {
- // See if there is a task to bring to the front. If this is
- // a SINGLE_INSTANCE activity, there can be one and only one
- // instance of it in the history, and it is always in its own
- // unique task, so we do a special search.
- intentActivity = launchSingleInstance ? mSupervisor.findActivityLocked(intent, r.info)
- : mSupervisor.findTaskLocked(r);
+ private boolean isValidLaunchStackId(int stackId, ActivityRecord r) {
+ if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID
+ || !StackId.isStaticStack(stackId)) {
+ return false;
}
- return intentActivity;
+
+ final boolean resizeable = r.isResizeable() || mService.mForceResizableActivities;
+
+ if (stackId != FULLSCREEN_WORKSPACE_STACK_ID && !resizeable) {
+ return false;
+ }
+
+ if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
+ return false;
+ }
+
+ final boolean supportsPip = mService.mSupportsPictureInPicture
+ && (r.supportsPictureInPicture() || mService.mForceResizableActivities);
+ if (stackId == PINNED_STACK_ID && !supportsPip) {
+ return false;
+ }
+ return true;
+ }
+
+ Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
+ Rect newBounds = null;
+ if (options != null && (r.isResizeable() || (inTask != null && inTask.mResizeable))) {
+ if (mSupervisor.canUseActivityOptionsLaunchBounds(
+ options, options.getLaunchStackId())) {
+ newBounds = options.getLaunchBounds();
+ }
+ }
+ return newBounds;
}
void setWindowManager(WindowManagerService wm) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index f64b80323b91..82862e8a1935 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1114,7 +1114,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
} else {
// Not an option, last argument must be a package name.
try {
- reqUid = mContext.getPackageManager().getPackageUid(arg,
+ reqUid = mContext.getPackageManager().getPackageUidAsUser(arg,
UserHandle.getCallingUserId());
} catch (PackageManager.NameNotFoundException e) {
pw.println("Unknown package: " + arg);
diff --git a/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java b/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java
new file mode 100644
index 000000000000..ff395895e638
--- /dev/null
+++ b/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.graphics.Rect;
+import android.os.Handler;
+
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+
+/**
+ * When resizing the docked stack, a caller can temporarily supply task bounds that are different
+ * from the stack bounds. In order to return to a sane state if the caller crashes or has a bug,
+ * this class manages this cycle.
+ */
+class ResizeDockedStackTimeout {
+
+ private static final long TIMEOUT_MS = 10 * 1000;
+ private final ActivityManagerService mService;
+ private final ActivityStackSupervisor mSupervisor;
+ private final Handler mHandler;
+ private final Rect mCurrentDockedBounds = new Rect();
+
+ private final Runnable mTimeoutRunnable = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mService) {
+ mSupervisor.resizeDockedStackLocked(mCurrentDockedBounds, null, null, null, null,
+ PRESERVE_WINDOWS);
+ }
+ }
+ };
+
+ ResizeDockedStackTimeout(ActivityManagerService service, ActivityStackSupervisor supervisor,
+ Handler handler) {
+ mService = service;
+ mSupervisor = supervisor;
+ mHandler = handler;
+ }
+
+ void notifyResizing(Rect dockedBounds, boolean hasTempBounds) {
+ mHandler.removeCallbacks(mTimeoutRunnable);
+ if (!hasTempBounds) {
+ return;
+ }
+ mCurrentDockedBounds.set(dockedBounds);
+ mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MS);
+ }
+
+}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4647d77bef89..c97d09c2ebbd 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -23,6 +23,7 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
@@ -441,7 +442,7 @@ final class TaskRecord {
} else {
autoRemoveRecents = false;
}
- mResizeable = info.resizeable || mService.mForceResizableActivities;
+ mResizeable = (info.flags & FLAG_RESIZEABLE) != 0 || mService.mForceResizableActivities;
mLockTaskMode = info.lockTaskLaunchMode;
mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
setLockTaskAuth();
@@ -697,7 +698,7 @@ final class TaskRecord {
if (mActivities.isEmpty()) {
taskType = r.mActivityType;
if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivities) {
- mResizeable = r.info.resizeable;
+ mResizeable = r.isResizeable();
}
isPersistable = r.isPersistable();
mCallingUid = r.launchedFromUid;
@@ -1321,7 +1322,12 @@ final class TaskRecord {
}
}
- void reportPictureInPictureModeChange() {
+ void reportPictureInPictureModeChangeIfNeeded(ActivityStack prevStack) {
+ if (prevStack == null || prevStack == stack
+ || (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) {
+ return;
+ }
+
for (int i = mActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = mActivities.get(i);
if (r.app != null && r.app.thread != null) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 43d4e775a098..717285930f5b 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -22,6 +22,7 @@ import static android.app.ActivityManager.USER_OP_ERROR_IS_SYSTEM;
import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
import static android.app.ActivityManager.USER_OP_SUCCESS;
+import static android.content.Context.KEYGUARD_SERVICE;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -43,6 +44,7 @@ import android.app.AppOpsManager;
import android.app.Dialog;
import android.app.IStopUserCallback;
import android.app.IUserSwitchObserver;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
@@ -73,6 +75,7 @@ import android.util.SparseIntArray;
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.pm.UserManagerService;
import java.io.PrintWriter;
@@ -304,7 +307,10 @@ final class UserController {
+ relatedUserId);
// We still need to stop the requested user if it's a force stop.
if (force) {
+ Slog.i(TAG,
+ "Force stop user " + userId + ". Related users will not be stopped");
stopSingleUserLocked(userId, callback);
+ return USER_OP_SUCCESS;
}
return USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
}
@@ -432,6 +438,10 @@ final class UserController {
synchronized (mService) {
mService.mStackSupervisor.removeUserLocked(userId);
}
+ // Remove the user if it is ephemeral.
+ if (getUserInfo(userId).isEphemeral()) {
+ mUserManager.removeUser(userId);
+ }
}
}
@@ -478,9 +488,9 @@ final class UserController {
}
/**
- * Stops the guest user if it has gone to the background.
+ * Stops the guest or ephemeral user if it has gone to the background.
*/
- private void stopGuestUserIfBackground() {
+ private void stopGuestOrEphemeralUserIfBackground() {
synchronized (mService) {
final int num = mUserLru.size();
for (int i = 0; i < num; i++) {
@@ -492,7 +502,7 @@ final class UserController {
continue;
}
UserInfo userInfo = getUserInfo(oldUserId);
- if (userInfo.isGuest()) {
+ if (userInfo.isGuest() || userInfo.isEphemeral()) {
// This is a user to be stopped.
stopUsersLocked(oldUserId, true, null);
break;
@@ -918,7 +928,7 @@ final class UserController {
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
newUserId, 0));
}
- stopGuestUserIfBackground();
+ stopGuestOrEphemeralUserIfBackground();
stopBackgroundUsersIfEnforced(oldUserId);
}
@@ -927,7 +937,7 @@ final class UserController {
if (homeInFront) {
mService.startHomeActivityLocked(newUserId, "moveUserToForeground");
} else {
- mService.mStackSupervisor.resumeTopActivitiesLocked();
+ mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
EventLogTags.writeAmSwitchUser(newUserId);
getUserManager().onUserForeground(newUserId);
@@ -1279,6 +1289,20 @@ final class UserController {
return mCurrentProfileIds;
}
+ /**
+ * Returns whether the given user requires credential entry at this time. This is used to
+ * intercept activity launches for work apps when the Work Challenge is present.
+ */
+ boolean shouldConfirmCredentials(int userId) {
+ final UserInfo user = getUserInfo(userId);
+ if (!user.isManagedProfile() || !LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+ return false;
+ }
+ final KeyguardManager km = (KeyguardManager) mService.mContext
+ .getSystemService(KEYGUARD_SERVICE);
+ return km.isDeviceLocked(user.id);
+ }
+
void dump(PrintWriter pw, boolean dumpAll) {
pw.println(" mStartedUsers:");
for (int i = 0; i < mStartedUsers.size(); i++) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 2bea278aad1a..5bd4f987073e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -309,7 +309,7 @@ public class Vpn {
PackageManager pm = mContext.getPackageManager();
int result;
try {
- result = pm.getPackageUid(app, userHandle);
+ result = pm.getPackageUidAsUser(app, userHandle);
} catch (NameNotFoundException e) {
result = -1;
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index c5e6e7c366c3..4eabe3684e4f 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -161,8 +161,9 @@ public class JobSchedulerService extends com.android.server.SystemService
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- Slog.d(TAG, "Receieved: " + intent.getAction());
- if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+ final String action = intent.getAction();
+ Slog.d(TAG, "Receieved: " + action);
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
// If this is an outright uninstall rather than the first half of an
// app update sequence, cancel the jobs associated with the app.
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
@@ -172,18 +173,21 @@ public class JobSchedulerService extends com.android.server.SystemService
}
cancelJobsForUid(uidRemoved, true);
}
- } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+ } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
if (DEBUG) {
Slog.d(TAG, "Removing jobs for user: " + userId);
}
cancelJobsForUser(userId);
- } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())
- || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
+ } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(action)
+ || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
updateIdleMode(mPowerManager != null
? (mPowerManager.isDeviceIdleMode()
|| mPowerManager.isLightDeviceIdleMode())
: false);
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+ // Kick off pending jobs for any apps that re-appeared
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
}
};
@@ -425,17 +429,24 @@ public class JobSchedulerService extends com.android.server.SystemService
@Override
public void onBootPhase(int phase) {
if (PHASE_SYSTEM_SERVICES_READY == phase) {
- // Register br for package removals and user removals.
+ // Register for package removals and user removals.
final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
getContext().registerReceiverAsUser(
mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+
final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
userFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
userFilter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
getContext().registerReceiverAsUser(
mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
- mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
+
+ final IntentFilter storageFilter = new IntentFilter();
+ storageFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ getContext().registerReceiverAsUser(
+ mBroadcastReceiver, UserHandle.ALL, storageFilter, null, null);
+
+ mPowerManager = getContext().getSystemService(PowerManager.class);
try {
ActivityManagerNative.getDefault().registerUidObserver(mUidObserver,
ActivityManager.UID_OBSERVER_IDLE);
@@ -834,7 +845,7 @@ public class JobSchedulerService extends com.android.server.SystemService
final boolean componentPresent;
try {
componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
- job.getServiceComponent(), PackageManager.MATCH_ENCRYPTION_DEFAULT,
+ job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
userId) != null);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
@@ -924,8 +935,8 @@ public class JobSchedulerService extends com.android.server.SystemService
final IPackageManager pm = AppGlobals.getPackageManager();
final ComponentName service = job.getService();
try {
- ServiceInfo si = pm.getServiceInfo(service, PackageManager.MATCH_ENCRYPTION_DEFAULT,
- UserHandle.getUserId(uid));
+ ServiceInfo si = pm.getServiceInfo(service,
+ PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(uid));
if (si == null) {
throw new IllegalArgumentException("No such service " + service);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 1997e40e610e..5aaa9304fbfb 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2333,7 +2333,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@Override
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
try {
- int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
+ int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, userId);
synchronized (mRulesLock) {
updateRuleForAppIdleLocked(uid);
}
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 19872144bfe3..ce18818c1fba 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -121,6 +121,11 @@ public class ConditionProviders extends ManagedServices {
}
@Override
+ protected boolean checkType(IInterface service) {
+ return service instanceof IConditionProvider;
+ }
+
+ @Override
public void onBootPhaseAppsCanStart() {
super.onBootPhaseAppsCanStart();
for (int i = 0; i < mSystemConditionProviders.size(); i++) {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index b7662daffec4..09e66475c1be 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -141,6 +141,8 @@ abstract public class ManagedServices {
abstract protected IInterface asInterface(IBinder binder);
+ abstract protected boolean checkType(IInterface service);
+
abstract protected void onServiceAdded(ManagedServiceInfo info);
protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
@@ -169,7 +171,8 @@ abstract public class ManagedServices {
if (filter != null && !filter.matches(info.component)) continue;
pw.println(" " + info.component
+ " (user " + info.userid + "): " + info.service
- + (info.isSystem?" SYSTEM":""));
+ + (info.isSystem?" SYSTEM":"")
+ + (info.isGuest(this)?" GUEST":""));
}
}
@@ -266,6 +269,18 @@ abstract public class ManagedServices {
}
}
+ /**
+ * Add a service to our callbacks. The lifecycle of this service is managed externally,
+ * but unlike a system service, it should not be considered privledged.
+ * */
+ public void registerGuestService(ManagedServiceInfo guest) {
+ checkNotNull(guest.service);
+ checkType(guest.service);
+ if (registerServiceImpl(guest) != null) {
+ onServiceAdded(guest);
+ }
+ }
+
public void setCategoryState(String category, boolean enabled) {
synchronized (mMutex) {
final Boolean previous = mCategoryEnabled.put(category, enabled);
@@ -484,7 +499,7 @@ abstract public class ManagedServices {
synchronized (mMutex) {
// Unbind automatically bound services, retain system services.
for (ManagedServiceInfo service : mServices) {
- if (!service.isSystem) {
+ if (!service.isSystem && !service.isGuest(this)) {
toRemove.add(service);
}
}
@@ -709,11 +724,15 @@ abstract public class ManagedServices {
private ManagedServiceInfo registerServiceImpl(final IInterface service,
final ComponentName component, final int userid) {
+ ManagedServiceInfo info = newServiceInfo(service, component, userid,
+ true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
+ return registerServiceImpl(info);
+ }
+
+ private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
synchronized (mMutex) {
try {
- ManagedServiceInfo info = newServiceInfo(service, component, userid,
- true /*isSystem*/, null, Build.VERSION_CODES.LOLLIPOP);
- service.asBinder().linkToDeath(info, 0);
+ info.service.asBinder().linkToDeath(info, 0);
mServices.add(info);
return info;
} catch (RemoteException e) {
@@ -728,7 +747,7 @@ abstract public class ManagedServices {
*/
private void unregisterServiceImpl(IInterface service, int userid) {
ManagedServiceInfo info = removeServiceImpl(service, userid);
- if (info != null && info.connection != null) {
+ if (info != null && info.connection != null && !info.isGuest(this)) {
mContext.unbindService(info.connection);
}
}
@@ -780,6 +799,10 @@ abstract public class ManagedServices {
this.targetSdkVersion = targetSdkVersion;
}
+ public boolean isGuest(ManagedServices host) {
+ return ManagedServices.this != host;
+ }
+
@Override
public String toString() {
return new StringBuilder("ManagedServiceInfo[")
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c6df83ae9165..9dcccc41e2cf 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -33,12 +33,14 @@ import static android.service.notification.NotificationListenerService.HINT_HOST
import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_LIGHTS;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_PEEK;
+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 org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -96,6 +98,7 @@ import android.service.notification.Condition;
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
import android.service.notification.IStatusBarNotificationHolder;
+import android.service.notification.NotificationAssistantService;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
import android.service.notification.StatusBarNotification;
@@ -154,6 +157,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.concurrent.TimeUnit;
/** {@hide} */
public class NotificationManagerService extends SystemService {
@@ -167,11 +171,13 @@ public class NotificationManagerService extends SystemService {
// message codes
static final int MESSAGE_TIMEOUT = 2;
static final int MESSAGE_SAVE_POLICY_FILE = 3;
- static final int MESSAGE_RECONSIDER_RANKING = 4;
- static final int MESSAGE_RANKING_CONFIG_CHANGE = 5;
- static final int MESSAGE_SEND_RANKING_UPDATE = 6;
- static final int MESSAGE_LISTENER_HINTS_CHANGED = 7;
- static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 8;
+ static final int MESSAGE_SEND_RANKING_UPDATE = 4;
+ static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
+ static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
+
+ // ranking thread messages
+ private static final int MESSAGE_RECONSIDER_RANKING = 1000;
+ private static final int MESSAGE_RANKING_SORT = 1001;
static final int LONG_DELAY = 3500; // 3.5 seconds
static final int SHORT_DELAY = 2000; // 2 seconds
@@ -281,11 +287,13 @@ public class NotificationManagerService extends SystemService {
private final UserProfiles mUserProfiles = new UserProfiles();
private NotificationListeners mListeners;
+ private NotificationAssistant mAssistant;
private ConditionProviders mConditionProviders;
private NotificationUsageStats mUsageStats;
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
+ private RankingHandler mRankingHandler;
private static class Archive {
final int mBufferSize;
@@ -738,6 +746,7 @@ public class NotificationManagerService extends SystemService {
}
}
mListeners.onPackagesChanged(queryReplace, pkgList);
+ mAssistant.onPackagesChanged(queryReplace, pkgList);
mConditionProviders.onPackagesChanged(queryReplace, pkgList);
mRankingHelper.onPackagesChanged(queryReplace, pkgList);
}
@@ -779,6 +788,7 @@ public class NotificationManagerService extends SystemService {
// Refresh managed services
mConditionProviders.onUserSwitched(user);
mListeners.onUserSwitched(user);
+ mAssistant.onUserSwitched(user);
mZenModeHelper.onUserSwitched(user);
} else if (action.equals(Intent.ACTION_USER_ADDED)) {
mUserProfiles.updateCache(context);
@@ -874,8 +884,9 @@ public class NotificationManagerService extends SystemService {
extractorNames = new String[0];
}
mUsageStats = new NotificationUsageStats(getContext());
+ mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
mRankingHelper = new RankingHelper(getContext(),
- new RankingWorkerHandler(mRankingThread.getLooper()),
+ mRankingHandler,
mUsageStats,
extractorNames);
mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
@@ -909,6 +920,7 @@ public class NotificationManagerService extends SystemService {
importOldBlockDb();
mListeners = new NotificationListeners();
+ mAssistant = new NotificationAssistant();
mStatusBar = getLocalService(StatusBarManagerInternal.class);
mStatusBar.setNotificationDelegate(mNotificationDelegate);
@@ -1025,6 +1037,7 @@ public class NotificationManagerService extends SystemService {
// bind to listener services.
mSettingsObserver.observe();
mListeners.onBootPhaseAppsCanStart();
+ mAssistant.onBootPhaseAppsCanStart();
mConditionProviders.onBootPhaseAppsCanStart();
}
}
@@ -1896,6 +1909,22 @@ public class NotificationManagerService extends SystemService {
Binder.restoreCallingIdentity(identity);
}
}
+
+ @Override
+ public void setImportanceFromAssistant(INotificationListener token, String key,
+ int importance, CharSequence explanation) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mNotificationList) {
+ mAssistant.checkServiceTokenLocked(token);
+ NotificationRecord n = mNotificationsByKey.get(key);
+ n.setImportance(importance, explanation);
+ mRankingHandler.requestSort();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
};
private String disableNotificationEffects(NotificationRecord record) {
@@ -2037,6 +2066,8 @@ public class NotificationManagerService extends SystemService {
pw.print(listener.component);
}
pw.println(')');
+ pw.println("\n Notification assistant:");
+ mAssistant.dump(pw, filter);
}
pw.println("\n Policy access:");
pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
@@ -2075,12 +2106,12 @@ public class NotificationManagerService extends SystemService {
for (UserInfo user : UserManager.get(getContext()).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
final PackageManager packageManager = getContext().getPackageManager();
- List<PackageInfo> packages = packageManager.getInstalledPackages(0, userId);
+ List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
final int packageCount = packages.size();
for (int p = 0; p < packageCount; p++) {
final String packageName = packages.get(p).packageName;
if (filter == null || filter.matches(packageName)) {
- final int uid = packageManager.getPackageUid(packageName, userId);
+ final int uid = packageManager.getPackageUidAsUser(packageName, userId);
if (!checkNotificationOp(packageName, uid)) {
packageNames.add(packageName);
}
@@ -2533,9 +2564,14 @@ public class NotificationManagerService extends SystemService {
updateLightsLocked();
}
if (buzz || beep || blink) {
- EventLogTags.writeNotificationAlert(record.getKey(),
- buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
- mHandler.post(mBuzzBeepBlinked);
+ if (((record.getSuppressedVisualEffects()
+ & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0)) {
+ if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
+ } else {
+ EventLogTags.writeNotificationAlert(record.getKey(),
+ buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
+ mHandler.post(mBuzzBeepBlinked);
+ }
}
}
@@ -2686,7 +2722,7 @@ public class NotificationManagerService extends SystemService {
}
}
- private void handleRankingConfigChange() {
+ private void handleRankingSort() {
synchronized (mNotificationList) {
final int N = mNotificationList.size();
ArrayList<String> orderBefore = new ArrayList<String>(N);
@@ -2697,8 +2733,8 @@ public class NotificationManagerService extends SystemService {
visibilities[i] = r.getPackageVisibilityOverride();
mRankingHelper.extractSignals(r);
}
+ mRankingHelper.sort(mNotificationList);
for (int i = 0; i < N; i++) {
- mRankingHelper.sort(mNotificationList);
final NotificationRecord r = mNotificationList.get(i);
if (!orderBefore.get(i).equals(r.getKey())
|| visibilities[i] != r.getPackageVisibilityOverride()) {
@@ -2714,7 +2750,8 @@ public class NotificationManagerService extends SystemService {
record.setIntercepted(mZenModeHelper.shouldIntercept(record));
if (record.isIntercepted()) {
int suppressed = (mZenModeHelper.shouldSuppressLight() ? SUPPRESSED_EFFECT_LIGHTS : 0)
- | (mZenModeHelper.shouldSuppressPeek() ? SUPPRESSED_EFFECT_PEEK : 0);
+ | (mZenModeHelper.shouldSuppressPeek() ? SUPPRESSED_EFFECT_PEEK : 0)
+ | (mZenModeHelper.shouldSuppressScreenOn() ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
record.setSuppressedVisualEffects(suppressed);
}
}
@@ -2788,9 +2825,9 @@ public class NotificationManagerService extends SystemService {
}
- private final class RankingWorkerHandler extends Handler
+ private final class RankingHandlerWorker extends Handler implements RankingHandler
{
- public RankingWorkerHandler(Looper looper) {
+ public RankingHandlerWorker(Looper looper) {
super(looper);
}
@@ -2800,11 +2837,23 @@ public class NotificationManagerService extends SystemService {
case MESSAGE_RECONSIDER_RANKING:
handleRankingReconsideration(msg);
break;
- case MESSAGE_RANKING_CONFIG_CHANGE:
- handleRankingConfigChange();
+ case MESSAGE_RANKING_SORT:
+ handleRankingSort();
break;
}
}
+
+ public void requestSort() {
+ removeMessages(MESSAGE_RANKING_SORT);
+ sendEmptyMessage(MESSAGE_RANKING_SORT);
+ }
+
+ public void requestReconsideration(RankingReconsideration recon) {
+ Message m = Message.obtain(this,
+ NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
+ long delay = recon.getDelay(TimeUnit.MILLISECONDS);
+ sendMessageDelayed(m, delay);
+ }
}
// Notifications
@@ -3305,6 +3354,45 @@ public class NotificationManagerService extends SystemService {
return true;
}
+ public class NotificationAssistant extends ManagedServices {
+
+ public NotificationAssistant() {
+ super(getContext(), mHandler, mNotificationList, mUserProfiles);
+ }
+
+ @Override
+ protected Config getConfig() {
+ Config c = new Config();
+ c.caption = "notification assistant";
+ c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
+ c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
+ c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
+ c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
+ c.clientLabel = R.string.notification_assistant_binding_label;
+ return c;
+ }
+
+ @Override
+ protected IInterface asInterface(IBinder binder) {
+ return INotificationListener.Stub.asInterface(binder);
+ }
+
+ @Override
+ protected boolean checkType(IInterface service) {
+ return service instanceof INotificationListener;
+ }
+
+ @Override
+ protected void onServiceAdded(ManagedServiceInfo info) {
+ mListeners.registerGuestService(info);
+ }
+
+ @Override
+ protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
+ mListeners.unregisterService(removed.service, removed.userid);
+ }
+ }
+
public class NotificationListeners extends ManagedServices {
private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
@@ -3332,6 +3420,11 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ protected boolean checkType(IInterface service) {
+ return service instanceof INotificationListener;
+ }
+
+ @Override
public void onServiceAdded(ManagedServiceInfo info) {
final INotificationListener listener = (INotificationListener) info.service;
final NotificationRankingUpdate update;
@@ -3366,7 +3459,6 @@ public class NotificationManagerService extends SystemService {
public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
-
}
/**
diff --git a/services/core/java/com/android/server/notification/RankingHandler.java b/services/core/java/com/android/server/notification/RankingHandler.java
new file mode 100644
index 000000000000..80bb4f089639
--- /dev/null
+++ b/services/core/java/com/android/server/notification/RankingHandler.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+public interface RankingHandler {
+ public void requestSort();
+ public void requestReconsideration(RankingReconsideration recon);
+}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 3287f67a6b86..f1fd42c69101 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -19,10 +19,7 @@ import android.app.Notification;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Handler;
-import android.os.Message;
import android.os.UserHandle;
-import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -40,7 +37,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.TimeUnit;
public class RankingHelper implements RankingConfig {
private static final String TAG = "RankingHelper";
@@ -73,10 +69,10 @@ public class RankingHelper implements RankingConfig {
private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record
private final Context mContext;
- private final Handler mRankingHandler;
+ private final RankingHandler mRankingHandler;
- public RankingHelper(Context context, Handler rankingHandler, NotificationUsageStats usageStats,
- String[] extractorNames) {
+ public RankingHelper(Context context, RankingHandler rankingHandler,
+ NotificationUsageStats usageStats, String[] extractorNames) {
mContext = context;
mRankingHandler = rankingHandler;
@@ -119,10 +115,7 @@ public class RankingHelper implements RankingConfig {
try {
RankingReconsideration recon = extractor.process(r);
if (recon != null) {
- Message m = Message.obtain(mRankingHandler,
- NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
- long delay = recon.getDelay(TimeUnit.MILLISECONDS);
- mRankingHandler.sendMessageDelayed(m, delay);
+ mRankingHandler.requestReconsideration(recon);
}
} catch (Throwable t) {
Slog.w(TAG, "NotificationSignalExtractor failed.", t);
@@ -155,7 +148,7 @@ public class RankingHelper implements RankingConfig {
if (forRestore) {
try {
//TODO: http://b/22388012
- uid = pm.getPackageUid(name, UserHandle.USER_SYSTEM);
+ uid = pm.getPackageUidAsUser(name, UserHandle.USER_SYSTEM);
} catch (NameNotFoundException e) {
// noop
}
@@ -287,7 +280,7 @@ public class RankingHelper implements RankingConfig {
for (int i = 0; i < N; i++) {
mSignalExtractors[i].setConfig(this);
}
- mRankingHandler.sendEmptyMessage(NotificationManagerService.MESSAGE_RANKING_CONFIG_CHANGE);
+ mRankingHandler.requestSort();
}
public void sort(ArrayList<NotificationRecord> notificationList) {
@@ -544,7 +537,7 @@ public class RankingHelper implements RankingConfig {
if (r != null) {
try {
//TODO: http://b/22388012
- r.uid = pm.getPackageUid(r.pkg, UserHandle.USER_SYSTEM);
+ r.uid = pm.getPackageUidAsUser(r.pkg, UserHandle.USER_SYSTEM);
mRestoredWithoutUids.remove(pkg);
mRecords.put(recordKey(r.pkg, r.uid), r);
updated = true;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 85c3cf88af19..276c6babce24 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -155,6 +155,12 @@ public class ZenModeHelper {
}
}
+ public boolean shouldSuppressScreenOn() {
+ synchronized (mConfig) {
+ return !mConfig.allowScreenOn;
+ }
+ }
+
public void addCallback(Callback callback) {
mCallbacks.add(callback);
}
@@ -435,11 +441,12 @@ public class ZenModeHelper {
return;
}
pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s,"
- + "events=%s,reminders=%s,lights=%s,peek=%s)\n",
+ + "events=%s,reminders=%s,lights=%s,peek=%s,screenOn=%s)\n",
config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
config.allowRepeatCallers, config.allowMessages,
ZenModeConfig.sourceToString(config.allowMessagesFrom),
- config.allowEvents, config.allowReminders, config.allowLights, config.allowPeek);
+ config.allowEvents, config.allowReminders, config.allowLights, config.allowPeek,
+ config.allowScreenOn);
pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule);
if (config.automaticRules.isEmpty()) return;
final int N = config.automaticRules.size();
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index f604bb781452..b254f29e0d5a 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -594,6 +594,14 @@ final class DefaultPermissionGrantPolicy {
}
}
+ // Print Spooler
+ PackageParser.Package printSpoolerPackage = getSystemPackageLPr(
+ "com.android.printspooler");
+ if (printSpoolerPackage != null
+ && doesPackageSupportRuntimePermissions(printSpoolerPackage)) {
+ grantRuntimePermissionsLPw(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId);
+ }
+
mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7bb6d1d91019..99f403104b01 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -59,6 +59,10 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.MATCH_ALL;
+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_DOESNT_EXIST;
import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
@@ -88,6 +92,8 @@ import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCES
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -106,6 +112,7 @@ import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.AppsQueryHelper;
+import android.content.pm.ComponentInfo;
import android.content.pm.EphemeralApplicationInfo;
import android.content.pm.EphemeralResolveInfo;
import android.content.pm.EphemeralResolveInfo.EphemeralResolveIntentInfo;
@@ -122,7 +129,6 @@ import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
@@ -207,7 +213,6 @@ import android.view.Display;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
@@ -308,7 +313,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private static final boolean DEBUG_DEXOPT = false;
private static final boolean DEBUG_ABI_SELECTION = false;
private static final boolean DEBUG_EPHEMERAL = false;
- private static final boolean DEBUG_ENCRYPTION_AWARE = false;
+ private static final boolean DEBUG_TRIAGED_MISSING = false;
static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
@@ -808,7 +813,7 @@ public class PackageManagerService extends IPackageManager.Stub {
packageName);
}
if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.d(TAG, "Adding verification filter for " + packageName + " : " + filter);
+ Slog.d(TAG, "Adding verification filter for " + packageName + ": " + filter);
}
ivs.addFilter(filter);
return true;
@@ -2427,113 +2432,60 @@ public class PackageManagerService extends IPackageManager.Stub {
return mIsUpgrade;
}
- private String getRequiredVerifierLPr() {
- final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
- // We only care about verifier that's installed under system user.
- final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
- PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM);
-
- String requiredVerifier = null;
-
- final int N = receivers.size();
- for (int i = 0; i < N; i++) {
- final ResolveInfo info = receivers.get(i);
+ private @NonNull String getRequiredVerifierLPr() {
+ final Intent intent = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
- if (info.activityInfo == null) {
- continue;
- }
-
- final String packageName = info.activityInfo.packageName;
-
- if (checkPermission(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
- packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
- continue;
- }
-
- if (requiredVerifier != null) {
- throw new RuntimeException("There can be only one required verifier");
- }
-
- requiredVerifier = packageName;
+ final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE,
+ MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+ if (matches.size() == 1) {
+ return matches.get(0).getComponentInfo().packageName;
+ } else {
+ throw new RuntimeException("There must be exactly one verifier; found " + matches);
}
-
- return requiredVerifier;
}
- private String getRequiredInstallerLPr() {
- Intent installerIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
- installerIntent.addCategory(Intent.CATEGORY_DEFAULT);
- installerIntent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
-
- final List<ResolveInfo> installers = queryIntentActivities(installerIntent,
- PACKAGE_MIME_TYPE, 0, UserHandle.USER_SYSTEM);
-
- String requiredInstaller = null;
-
- final int N = installers.size();
- for (int i = 0; i < N; i++) {
- final ResolveInfo info = installers.get(i);
- final String packageName = info.activityInfo.packageName;
-
- if (!info.activityInfo.applicationInfo.isSystemApp()) {
- continue;
- }
-
- if (requiredInstaller != null) {
- throw new RuntimeException("There must be one required installer");
- }
-
- requiredInstaller = packageName;
- }
+ private @NonNull String getRequiredInstallerLPr() {
+ final Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
- if (requiredInstaller == null) {
- throw new RuntimeException("There must be one required installer");
+ final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE,
+ MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+ if (matches.size() == 1) {
+ return matches.get(0).getComponentInfo().packageName;
+ } else {
+ throw new RuntimeException("There must be exactly one installer; found " + matches);
}
-
- return requiredInstaller;
}
- private ComponentName getIntentFilterVerifierComponentNameLPr() {
- final Intent verification = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
- final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
- PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM);
+ private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() {
+ final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
- ComponentName verifierComponentName = null;
-
- int priority = -1000;
- final int N = receivers.size();
+ final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE,
+ MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+ ResolveInfo best = null;
+ final int N = matches.size();
for (int i = 0; i < N; i++) {
- final ResolveInfo info = receivers.get(i);
-
- if (info.activityInfo == null) {
- continue;
- }
-
- final String packageName = info.activityInfo.packageName;
-
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- continue;
- }
-
+ final ResolveInfo cur = matches.get(i);
+ final String packageName = cur.getComponentInfo().packageName;
if (checkPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
continue;
}
- // Select the IntentFilterVerifier with the highest priority
- if (priority < info.priority) {
- priority = info.priority;
- verifierComponentName = new ComponentName(packageName, info.activityInfo.name);
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Selecting IntentFilterVerifier: "
- + verifierComponentName + " with priority: " + info.priority);
+ if (best == null || cur.priority > best.priority) {
+ best = cur;
}
}
- return verifierComponentName;
+ if (best != null) {
+ return best.getComponentInfo().getComponentName();
+ } else {
+ throw new RuntimeException("There must be at least one intent filter verifier");
+ }
}
- private ComponentName getEphemeralResolverLPr() {
+ private @Nullable ComponentName getEphemeralResolverLPr() {
final String[] packageArray =
mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
if (packageArray.length == 0) {
@@ -2543,9 +2495,9 @@ public class PackageManagerService extends IPackageManager.Stub {
return null;
}
- Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE);
- final List<ResolveInfo> resolvers = queryIntentServices(resolverIntent,
- null /*resolvedType*/, 0 /*flags*/, UserHandle.USER_SYSTEM);
+ final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE);
+ final List<ResolveInfo> resolvers = queryIntentServices(resolverIntent, null,
+ MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
final int N = resolvers.size();
if (N == 0) {
@@ -2584,36 +2536,21 @@ public class PackageManagerService extends IPackageManager.Stub {
return null;
}
- private ComponentName getEphemeralInstallerLPr() {
- Intent installerIntent = new Intent(Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE);
- installerIntent.addCategory(Intent.CATEGORY_DEFAULT);
- installerIntent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
- final List<ResolveInfo> installers = queryIntentActivities(installerIntent,
- PACKAGE_MIME_TYPE, 0 /*flags*/, 0 /*userId*/);
-
- ComponentName ephemeralInstaller = null;
-
- final int N = installers.size();
- for (int i = 0; i < N; i++) {
- final ResolveInfo info = installers.get(i);
- final String packageName = info.activityInfo.packageName;
-
- if (!info.activityInfo.applicationInfo.isSystemApp()) {
- if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Ephemeral installer is not system app;"
- + " pkg: " + packageName + ", info:" + info);
- }
- continue;
- }
-
- if (ephemeralInstaller != null) {
- throw new RuntimeException("There must only be one ephemeral installer");
- }
+ private @Nullable ComponentName getEphemeralInstallerLPr() {
+ final Intent intent = new Intent(Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
- ephemeralInstaller = new ComponentName(packageName, info.activityInfo.name);
+ final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE,
+ MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+ if (matches.size() == 0) {
+ return null;
+ } else if (matches.size() == 1) {
+ return matches.get(0).getComponentInfo().getComponentName();
+ } else {
+ throw new RuntimeException(
+ "There must be at most one ephemeral installer; found " + matches);
}
-
- return ephemeralInstaller;
}
private void primeDomainVerificationsLPw(int userId) {
@@ -2660,7 +2597,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ "' does not handle web links");
}
} else {
- Slog.w(TAG, "Unknown package '" + packageName + "' in sysconfig <app-link>");
+ Slog.w(TAG, "Unknown package " + packageName + " in sysconfig <app-link>");
}
}
@@ -2848,6 +2785,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ flags = updateFlagsForPackage(flags, userId, packageName);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package info");
// reader
synchronized (mPackages) {
@@ -2857,7 +2795,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (p != null) {
return generatePackageInfo(p, flags, userId);
}
- if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
}
}
@@ -2898,6 +2836,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public int getPackageUidEtc(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return -1;
+ flags = updateFlagsForPackage(flags, userId, packageName);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package uid");
// reader
@@ -2906,7 +2845,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (p != null) {
return UserHandle.getUid(userId, p.applicationInfo.uid);
}
- if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
return UserHandle.getUid(userId, ps.appId);
@@ -2924,10 +2863,8 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public int[] getPackageGidsEtc(String packageName, int flags, int userId) {
- if (!sUserManager.exists(userId)) {
- return null;
- }
-
+ if (!sUserManager.exists(userId)) return null;
+ flags = updateFlagsForPackage(flags, userId, packageName);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
"getPackageGids");
@@ -2938,7 +2875,7 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageSetting ps = (PackageSetting) p.mExtras;
return ps.getPermissionsState().computeGids(userId);
}
- if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
return ps.getPermissionsState().computeGids(userId);
@@ -2949,8 +2886,7 @@ public class PackageManagerService extends IPackageManager.Stub {
return null;
}
- static PermissionInfo generatePermissionInfo(
- BasePermission bp, int flags) {
+ static PermissionInfo generatePermissionInfo(BasePermission bp, int flags) {
if (bp.perm != null) {
return PackageParser.generatePermissionInfo(bp.perm, flags);
}
@@ -3047,7 +2983,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (ps != null) {
PackageParser.Package pkg = ps.pkg;
if (pkg == null) {
- if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
+ if ((flags & MATCH_UNINSTALLED_PACKAGES) == 0) {
return null;
}
// Only data remains, so we aren't worried about code paths
@@ -3068,6 +3004,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ flags = updateFlagsForApplication(flags, userId, packageName);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get application info");
// writer
synchronized (mPackages) {
@@ -3085,7 +3022,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if ("android".equals(packageName)||"system".equals(packageName)) {
return mAndroidApplication;
}
- if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
return generateApplicationInfoFromSettingsLPw(packageName, flags, userId);
}
}
@@ -3182,46 +3119,88 @@ public class PackageManagerService extends IPackageManager.Stub {
}
/**
- * Augment the given flags depending on current user running state. This is
- * purposefully done before acquiring {@link #mPackages} lock.
+ * Update given flags based on encryption status of current user.
*/
- private int augmentFlagsForUser(int flags, int userId, Object cookie) {
- if (cookie instanceof Intent) {
- // If intent claims to be triaged, then we're fine with default
- // matching behavior below
- final Intent intent = (Intent) cookie;
- if ((intent.getFlags() & Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED) != 0) {
- flags |= PackageManager.MATCH_ENCRYPTION_DEFAULT;
- }
- }
-
- if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE_ONLY
- | PackageManager.MATCH_ENCRYPTION_AWARE_ONLY)) != 0) {
- // Caller expressed an opinion about what components they want to
- // see, so fall through and give them what they want
+ private int updateFlagsForEncryption(int flags, int userId) {
+ if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+ | PackageManager.MATCH_ENCRYPTION_AWARE)) != 0) {
+ // Caller expressed an explicit opinion about what encryption
+ // aware/unaware components they want to see, so fall through and
+ // give them what they want
} else {
// Caller expressed no opinion, so match based on user state
if (isUserKeyUnlocked(userId)) {
flags |= PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
} else {
- flags |= PackageManager.MATCH_ENCRYPTION_AWARE_ONLY;
-
- // If we have a system caller that hasn't done their homework to
- // decide they want this default behavior, yell at them
- if (DEBUG_ENCRYPTION_AWARE && (Binder.getCallingUid() == Process.SYSTEM_UID)
- && ((flags & PackageManager.MATCH_ENCRYPTION_DEFAULT) == 0)) {
- Log.v(TAG, "Caller hasn't been triaged for FBE; they asked about " + cookie,
- new Throwable());
- }
+ flags |= PackageManager.MATCH_ENCRYPTION_AWARE;
}
}
return flags;
}
+ /**
+ * Update given flags when being used to request {@link PackageInfo}.
+ */
+ private int updateFlagsForPackage(int flags, int userId, Object cookie) {
+ boolean triaged = true;
+ if ((flags & PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
+ | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS) != 0) {
+ // Caller is asking for component details, so they'd better be
+ // asking for specific encryption matching behavior, or be triaged
+ if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+ | PackageManager.MATCH_ENCRYPTION_AWARE
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+ triaged = false;
+ }
+ }
+ if ((flags & (PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+ triaged = false;
+ }
+ if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
+ Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie,
+ new Throwable());
+ }
+ return updateFlagsForEncryption(flags, userId);
+ }
+
+ /**
+ * Update given flags when being used to request {@link ApplicationInfo}.
+ */
+ private int updateFlagsForApplication(int flags, int userId, Object cookie) {
+ return updateFlagsForPackage(flags, userId, cookie);
+ }
+
+ /**
+ * Update given flags when being used to request {@link ComponentInfo}.
+ */
+ private int updateFlagsForComponent(int flags, int userId, Object cookie) {
+ boolean triaged = true;
+ // Caller is asking for component details, so they'd better be
+ // asking for specific encryption matching behavior, or be triaged
+ if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+ | PackageManager.MATCH_ENCRYPTION_AWARE
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+ triaged = false;
+ }
+ if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
+ Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie,
+ new Throwable());
+ }
+ return updateFlagsForEncryption(flags, userId);
+ }
+
+ /**
+ * Update given flags when being used to request {@link ResolveInfo}.
+ */
+ private int updateFlagsForResolve(int flags, int userId, Object cookie) {
+ return updateFlagsForComponent(flags, userId, cookie);
+ }
+
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId, component);
+ flags = updateFlagsForComponent(flags, userId, component);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get activity info");
synchronized (mPackages) {
PackageParser.Activity a = mActivities.mActivities.get(component);
@@ -3266,7 +3245,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId, component);
+ flags = updateFlagsForComponent(flags, userId, component);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get receiver info");
synchronized (mPackages) {
PackageParser.Activity a = mReceivers.mActivities.get(component);
@@ -3285,7 +3264,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId, component);
+ flags = updateFlagsForComponent(flags, userId, component);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get service info");
synchronized (mPackages) {
PackageParser.Service s = mServices.mServices.get(component);
@@ -3304,7 +3283,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId, component);
+ flags = updateFlagsForComponent(flags, userId, component);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get provider info");
synchronized (mPackages) {
PackageParser.Provider p = mProviders.mProviders.get(component);
@@ -3732,8 +3711,8 @@ public class PackageManagerService extends IPackageManager.Stub {
final int flags = permissionsState.getPermissionFlags(name, userId);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
- throw new SecurityException("Cannot grant system fixed permission: "
- + name + " for package: " + packageName);
+ throw new SecurityException("Cannot grant system fixed permission "
+ + name + " for package " + packageName);
}
if (bp.isDevelopment()) {
@@ -3841,8 +3820,8 @@ public class PackageManagerService extends IPackageManager.Stub {
final int flags = permissionsState.getPermissionFlags(name, userId);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
- throw new SecurityException("Cannot revoke system fixed permission: "
- + name + " for package: " + packageName);
+ throw new SecurityException("Cannot revoke system fixed permission "
+ + name + " for package " + packageName);
}
if (bp.isDevelopment()) {
@@ -4429,7 +4408,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "resolve intent");
List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
final ResolveInfo bestChoice =
@@ -4647,7 +4626,7 @@ public class PackageManagerService extends IPackageManager.Stub {
ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
}
final ActivityInfo ai = getActivityInfo(ppa.mComponent,
- flags | PackageManager.GET_DISABLED_COMPONENTS, userId);
+ flags | MATCH_DISABLED_COMPONENTS, userId);
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Found persistent preferred activity:");
if (ai != null) {
@@ -4687,7 +4666,7 @@ public class PackageManagerService extends IPackageManager.Stub {
List<ResolveInfo> query, int priority, boolean always,
boolean removeMatches, boolean debug, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent);
// writer
synchronized (mPackages) {
if (intent.getSelector() != null) {
@@ -4756,7 +4735,7 @@ public class PackageManagerService extends IPackageManager.Stub {
continue;
}
final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent,
- flags | PackageManager.GET_DISABLED_COMPONENTS, userId);
+ flags | MATCH_DISABLED_COMPONENTS, userId);
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Found preferred activity:");
if (ai != null) {
@@ -4886,7 +4865,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public List<ResolveInfo> queryIntentActivities(Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = augmentFlagsForUser(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");
ComponentName comp = intent.getComponent();
if (comp == null) {
@@ -5370,7 +5349,7 @@ public class PackageManagerService extends IPackageManager.Stub {
Intent[] specifics, String[] specificTypes, Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = augmentFlagsForUser(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
false, "query intent activity options");
final String resultsAction = intent.getAction();
@@ -5543,7 +5522,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = augmentFlagsForUser(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -5580,7 +5559,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent);
List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
if (query != null) {
if (query.size() >= 1) {
@@ -5596,7 +5575,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = augmentFlagsForUser(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -5634,7 +5613,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public List<ResolveInfo> queryIntentContentProviders(
Intent intent, String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = augmentFlagsForUser(flags, userId, intent);
+ flags = updateFlagsForResolve(flags, userId, intent);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -5670,8 +5649,9 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
- final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
-
+ if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+ flags = updateFlagsForPackage(flags, userId, null);
+ final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "get installed packages");
// writer
@@ -5750,8 +5730,9 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
String[] permissions, int flags, int userId) {
- if (!sUserManager.exists(userId)) return null;
- final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
+ if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+ flags = updateFlagsForPackage(flags, userId, permissions);
+ final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
// writer
synchronized (mPackages) {
@@ -5777,8 +5758,9 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
- if (!sUserManager.exists(userId)) return null;
- final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
+ if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+ flags = updateFlagsForApplication(flags, userId, null);
+ final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
// writer
synchronized (mPackages) {
@@ -5920,7 +5902,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId, name);
+ flags = updateFlagsForComponent(flags, userId, name);
// reader
synchronized (mPackages) {
final PackageParser.Provider provider = mProvidersByAuthority.get(name);
@@ -5972,7 +5954,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final int userId = processName != null ? UserHandle.getUserId(uid)
: UserHandle.getCallingUserId();
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId, processName);
+ flags = updateFlagsForComponent(flags, userId, processName);
ArrayList<ProviderInfo> finalList = null;
// reader
@@ -6009,8 +5991,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
- public InstrumentationInfo getInstrumentationInfo(ComponentName name,
- int flags) {
+ public InstrumentationInfo getInstrumentationInfo(ComponentName name, int flags) {
// reader
synchronized (mPackages) {
final PackageParser.Instrumentation i = mInstrumentation.get(name);
@@ -6205,7 +6186,6 @@ public class PackageManagerService extends IPackageManager.Stub {
try {
pp.collectCertificates(pkg, parseFlags);
- pp.collectManifestDigest(pkg);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
@@ -6293,7 +6273,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ " ignored: updated version " + ps.versionCode
+ " better than this " + pkg.mVersionCode);
if (!updatedPkg.codePath.equals(scanFile)) {
- Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg : "
+ Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg "
+ ps.name + " changing from " + updatedPkg.codePathString
+ " to " + scanFile);
updatedPkg.codePath = scanFile;
@@ -6418,7 +6398,7 @@ public class PackageManagerService extends IPackageManager.Stub {
baseResourcePath = ps.resourcePathString;
} else {
// Should not happen at all. Just log an error.
- Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
+ Slog.e(TAG, "Resource path not set for package " + pkg.packageName);
}
} else {
resourcePath = pkg.codePath;
@@ -6667,7 +6647,7 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
pkg = mPackages.get(packageName);
if (pkg == null) {
- throw new IllegalArgumentException("Missing package: " + packageName);
+ throw new IllegalArgumentException("Unknown package: " + packageName);
}
}
@@ -7177,7 +7157,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
throw new PackageManagerException(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
- "Signature mismatch for shared user : "
+ "Signature mismatch for shared user: "
+ pkgSetting.sharedUser);
}
}
@@ -7429,7 +7409,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) {
Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
- " for package: " + pkg.packageName);
+ " for package " + pkg.packageName);
}
}
@@ -8136,7 +8116,7 @@ public class PackageManagerService extends IPackageManager.Stub {
ps.primaryCpuAbiString = adjustedAbi;
if (ps.pkg != null && ps.pkg.applicationInfo != null) {
ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
- Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
+ Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi);
mInstaller.rmdex(ps.codePathString,
getDexCodeInstructionSet(getPreferredInstructionSet()));
}
@@ -8374,7 +8354,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// 64 bit apps will see a 64 bit primary ABI,
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
- Slog.e(TAG, "Package: " + pkg + " has multiple bundled libs, but is not multiarch.");
+ Slog.e(TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
}
if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
@@ -10037,7 +10017,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
final VerificationParams verifParams = new VerificationParams(
null, sessionParams.originatingUri, sessionParams.referrerUri,
- sessionParams.originatingUid, null);
+ sessionParams.originatingUid);
verifParams.setInstallerUid(installerUid);
final OriginInfo origin;
@@ -10620,7 +10600,7 @@ public class PackageManagerService extends IPackageManager.Stub {
throw new SecurityException("Bad object " + obj + " for uid " + uid);
}
} else {
- throw new SecurityException("Unknown calling uid " + uid);
+ throw new SecurityException("Unknown calling UID: " + uid);
}
// Verify: can't set installerPackageName to a package that is
@@ -11019,13 +10999,6 @@ public class PackageManagerService extends IPackageManager.Stub {
+ " file=" + origin.file + " cid=" + origin.cid + "}";
}
- public ManifestDigest getManifestDigest() {
- if (verificationParams == null) {
- return null;
- }
- return verificationParams.getManifestDigest();
- }
-
private int installLocationPolicy(PackageInfoLite pkgLite) {
String packageName = pkgLite.packageName;
int installLocation = pkgLite.installLocation;
@@ -11228,9 +11201,9 @@ public class PackageManagerService extends IPackageManager.Stub {
PACKAGE_MIME_TYPE);
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ // Query all live verifiers based on current user state
final List<ResolveInfo> receivers = queryIntentReceivers(verification,
- PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS,
- verifierUser.getIdentifier());
+ PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());
if (DEBUG_VERIFY) {
Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
@@ -11444,7 +11417,6 @@ public class PackageManagerService extends IPackageManager.Stub {
final int installFlags;
final String installerPackageName;
final String volumeUuid;
- final ManifestDigest manifestDigest;
final UserHandle user;
final String abiOverride;
final String[] installGrantPermissions;
@@ -11459,7 +11431,7 @@ public class PackageManagerService extends IPackageManager.Stub {
InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
- ManifestDigest manifestDigest, UserHandle user, String[] instructionSets,
+ UserHandle user, String[] instructionSets,
String abiOverride, String[] installGrantPermissions,
String traceMethod, int traceCookie) {
this.origin = origin;
@@ -11468,7 +11440,6 @@ public class PackageManagerService extends IPackageManager.Stub {
this.observer = observer;
this.installerPackageName = installerPackageName;
this.volumeUuid = volumeUuid;
- this.manifestDigest = manifestDigest;
this.user = user;
this.instructionSets = instructionSets;
this.abiOverride = abiOverride;
@@ -11543,8 +11514,8 @@ public class PackageManagerService extends IPackageManager.Stub {
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package: "
- + " at location " + codePath + ", retcode=" + retCode);
+ Slog.w(TAG, "Couldn't remove dex file for package at location " + codePath
+ + ", retcode=" + retCode);
// we don't consider this to be a failure of the core package deletion
}
}
@@ -11570,7 +11541,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** New install */
FileInstallArgs(InstallParams params) {
super(params.origin, params.move, params.observer, params.installFlags,
- params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+ params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie);
@@ -11581,7 +11552,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** Existing install */
FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
- super(OriginInfo.fromNothing(), null, null, 0, null, null, null, null, instructionSets,
+ super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
null, null, null, 0);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
@@ -11808,7 +11779,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** New install */
AsecInstallArgs(InstallParams params) {
super(params.origin, params.move, params.observer, params.installFlags,
- params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+ params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie);
@@ -11818,7 +11789,7 @@ public class PackageManagerService extends IPackageManager.Stub {
AsecInstallArgs(String fullCodePath, String[] instructionSets,
boolean isExternal, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
+ | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
instructionSets, null, null, null, 0);
// Hackily pretend we're still looking at a full code path
if (!fullCodePath.endsWith(RES_FILE_NAME)) {
@@ -11835,7 +11806,7 @@ public class PackageManagerService extends IPackageManager.Stub {
AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
+ | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
instructionSets, null, null, null, 0);
this.cid = cid;
setMountPath(PackageHelper.getSdDir(cid));
@@ -12102,7 +12073,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** New install */
MoveInstallArgs(InstallParams params) {
super(params.origin, params.move, params.observer, params.installFlags,
- params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+ params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie);
@@ -12578,7 +12549,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if((oldPkg == null) || (oldPkg.applicationInfo == null) ||
(oldPkgSetting == null)) {
res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE,
- "Couldn't find package:" + packageName + " information");
+ "Couldn't find package " + packageName + " information");
return;
}
}
@@ -12876,35 +12847,6 @@ public class PackageManagerService extends IPackageManager.Stub {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- /* If the installer passed in a manifest digest, compare it now. */
- if (args.manifestDigest != null) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectManifestDigest");
- try {
- pp.collectManifestDigest(pkg);
- } catch (PackageParserException e) {
- res.setError("Failed collect during installPackageLI", e);
- return;
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- if (DEBUG_INSTALL) {
- final String parsedManifest = pkg.manifestDigest == null ? "null"
- : pkg.manifestDigest.toString();
- Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "
- + parsedManifest);
- }
-
- if (!args.manifestDigest.equals(pkg.manifestDigest)) {
- res.setError(INSTALL_FAILED_PACKAGE_CHANGED, "Manifest digest changed");
- return;
- }
- } else if (DEBUG_INSTALL) {
- final String parsedManifest = pkg.manifestDigest == null
- ? "null" : pkg.manifestDigest.toString();
- Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);
- }
-
// Get rid of all references to package scan path via parser.
pp = null;
String oldCodePath = null;
@@ -13692,7 +13634,7 @@ public class PackageManagerService extends IPackageManager.Stub {
try {
newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null);
} catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to restore system package:" + newPs.name + ": " + e.getMessage());
+ Slog.w(TAG, "Failed to restore system package " + newPs.name + ": " + e.getMessage());
return false;
}
@@ -13910,13 +13852,13 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean ret = false;
if (isSystemApp(ps)) {
- if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name);
+ 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, allUserHandles, perUserInstalled,
flags, outInfo, writeSettings);
} else {
- if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name);
+ 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, deleteCodeAndResources, flags,
@@ -14065,7 +14007,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// resorting to a full data wipe.
int retCode = mInstaller.clearUserData(pkg.volumeUuid, packageName, userId);
if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove cache files for package: " + packageName);
+ Slog.w(TAG, "Couldn't remove cache files for package " + packageName);
return false;
}
@@ -14295,7 +14237,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
int retCode = mInstaller.deleteCacheFiles(p.volumeUuid, packageName, userId);
if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove cache files for package: "
+ Slog.w(TAG, "Couldn't remove cache files for package "
+ packageName + " u" + userId);
return false;
}
@@ -14740,7 +14682,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
synchronized (mPackages) {
Slog.i(TAG, "Adding persistent preferred activity " + activity + " for user " + userId +
- " :");
+ ":");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
new PersistentPreferredActivity(filter, activity));
@@ -15145,12 +15087,10 @@ public class PackageManagerService extends IPackageManager.Stub {
pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null) {
if (className == null) {
- throw new IllegalArgumentException(
- "Unknown package: " + packageName);
+ throw new IllegalArgumentException("Unknown package: " + packageName);
}
throw new IllegalArgumentException(
- "Unknown component: " + packageName
- + "/" + className);
+ "Unknown component: " + packageName + "/" + className);
}
// Allow root and verify that userId is not being specified by a different user
if (!allowedByPermission && !UserHandle.isSameApp(uid, pkgSetting.appId)) {
@@ -17192,7 +17132,7 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized(mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
- Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+ Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
KeySetManagerService ksms = mSettings.mKeySetManagerService;
@@ -17208,7 +17148,7 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized(mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
- Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+ Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
if (pkg.applicationInfo.uid != Binder.getCallingUid()
@@ -17228,7 +17168,7 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized(mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
- Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+ Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
IBinder ksh = ks.getToken();
@@ -17248,7 +17188,7 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized(mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
- Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+ Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
IBinder ksh = ks.getToken();
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7c952a57f9ab..3f9ce7a64aae 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -16,23 +16,42 @@
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.Manifest.permission.READ_EXTERNAL_STORAGE;
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.os.Process.SYSTEM_UID;
+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;
+import android.content.ComponentName;
+import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.PackageCleanItem;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
+import android.content.pm.UserInfo;
+import android.content.pm.VerifierDeviceIdentity;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -47,11 +66,18 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
-import android.util.AtomicFile;
import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.Log;
import android.util.LogPrinter;
+import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.SparseLongArray;
+import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
@@ -65,55 +91,37 @@ import com.android.server.backup.PreferredActivityBackupHelper;
import com.android.server.pm.PackageManagerService.DumpState;
import com.android.server.pm.PermissionsState.PermissionState;
-import java.io.BufferedInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.util.Collection;
+import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
-import android.content.pm.PackageCleanItem;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.PermissionInfo;
-import android.content.pm.Signature;
-import android.content.pm.UserInfo;
-import android.content.pm.PackageUserState;
-import android.content.pm.VerifierDeviceIdentity;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.util.Xml;
-
+import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
import java.io.PrintWriter;
+import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
-import java.util.Map.Entry;
-
-import libcore.io.IoUtils;
/**
* Holds information about dynamic settings.
@@ -423,7 +431,7 @@ final class Settings {
boolean disableSystemPackageLPw(String name) {
final PackageSetting p = mPackages.get(name);
if(p == null) {
- Log.w(PackageManagerService.TAG, "Package:"+name+" is not an installed package");
+ Log.w(PackageManagerService.TAG, "Package " + name + " is not an installed package");
return false;
}
final PackageSetting dp = mDisabledSysPackages.get(name);
@@ -448,7 +456,7 @@ final class Settings {
PackageSetting enableSystemPackageLPw(String name) {
PackageSetting p = mDisabledSysPackages.get(name);
if(p == null) {
- Log.w(PackageManagerService.TAG, "Package:"+name+" is not disabled");
+ Log.w(PackageManagerService.TAG, "Package " + name + " is not disabled");
return null;
}
// Reset flag in ApplicationInfo object
@@ -1335,7 +1343,7 @@ final class Settings {
throws XmlPullParserException, IOException {
IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(parser);
packageSetting.setIntentFilterVerificationInfo(ivi);
- Log.d(TAG, "Read domain verification for package:" + ivi.getPackageName());
+ Log.d(TAG, "Read domain verification for package: " + ivi.getPackageName());
}
private void readRestoredIntentFilterVerifications(XmlPullParser parser)
@@ -1469,7 +1477,7 @@ final class Settings {
String name = parser.getAttributeValue(null, ATTR_NAME);
ps = mPackages.get(name);
if (ps == null) {
- Slog.w(PackageManagerService.TAG, "No package known for stopped package: "
+ Slog.w(PackageManagerService.TAG, "No package known for stopped package "
+ name);
XmlUtils.skipCurrentTag(parser);
continue;
@@ -2033,7 +2041,7 @@ final class Settings {
}
} else {
Slog.w(PackageManagerService.TAG,
- "No package known for stopped package: " + name);
+ "No package known for stopped package " + name);
}
XmlUtils.skipCurrentTag(parser);
} else {
@@ -2251,11 +2259,11 @@ final class Settings {
JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
final File writeTarget = journal.chooseForWrite();
- FileOutputStream fstr = null;
- BufferedOutputStream str = null;
+ FileOutputStream fstr;
+ BufferedWriter writer = null;
try {
fstr = new FileOutputStream(writeTarget);
- str = new BufferedOutputStream(fstr);
+ writer = new BufferedWriter(new OutputStreamWriter(fstr, Charset.defaultCharset()));
FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
StringBuilder sb = new StringBuilder();
@@ -2272,7 +2280,7 @@ final class Settings {
final int[] gids = pkg.getPermissionsState().computeGids(userIds);
// Avoid any application that has a space in its path.
- if (dataPath.indexOf(" ") >= 0)
+ if (dataPath.indexOf(' ') >= 0)
continue;
// we store on each line the following information for now:
@@ -2294,7 +2302,7 @@ final class Settings {
sb.setLength(0);
sb.append(ai.packageName);
sb.append(" ");
- sb.append((int)ai.uid);
+ sb.append(ai.uid);
sb.append(isDebug ? " 1 " : " 0 ");
sb.append(dataPath);
sb.append(" ");
@@ -2310,15 +2318,15 @@ final class Settings {
sb.append("none");
}
sb.append("\n");
- str.write(sb.toString().getBytes());
+ writer.append(sb);
}
- str.flush();
+ writer.flush();
FileUtils.sync(fstr);
- str.close();
+ writer.close();
journal.commit();
} catch (Exception e) {
Slog.wtf(TAG, "Failed to write packages.list", e);
- IoUtils.closeQuietly(str);
+ IoUtils.closeQuietly(writer);
journal.rollback();
}
}
@@ -2854,7 +2862,7 @@ final class Settings {
for (int i=0; i<tmpPa.countCategories(); i++) {
String cat = tmpPa.getCategory(i);
if (cat.equals(Intent.CATEGORY_DEFAULT)) {
- flags |= PackageManager.MATCH_DEFAULT_ONLY;
+ flags |= MATCH_DEFAULT_ONLY;
} else {
intent.addCategory(cat);
}
@@ -3004,7 +3012,7 @@ final class Settings {
filter.addCategory(cat);
}
}
- if ((flags&PackageManager.MATCH_DEFAULT_ONLY) != 0) {
+ if ((flags & MATCH_DEFAULT_ONLY) != 0) {
filter.addCategory(Intent.CATEGORY_DEFAULT);
}
if (scheme != null) {
@@ -3796,7 +3804,7 @@ final class Settings {
}
private boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) {
- if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
+ if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
return true;
}
final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
@@ -3812,7 +3820,7 @@ final class Settings {
return false;
}
PackageUserState ustate = packageSettings.readUserState(userId);
- if ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0) {
+ if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) != 0) {
if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
return true;
}
@@ -3836,16 +3844,16 @@ final class Settings {
}
private boolean isMatchLPr(ComponentInfo componentInfo, int flags) {
- if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
+ if ((flags & MATCH_SYSTEM_ONLY) != 0) {
final PackageSetting ps = mPackages.get(componentInfo.packageName);
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
return false;
}
}
- final boolean matchesUnaware = ((flags & PackageManager.MATCH_ENCRYPTION_UNAWARE_ONLY) != 0)
+ final boolean matchesUnaware = ((flags & MATCH_ENCRYPTION_UNAWARE) != 0)
&& !componentInfo.encryptionAware;
- final boolean matchesAware = ((flags & PackageManager.MATCH_ENCRYPTION_AWARE_ONLY) != 0)
+ final boolean matchesAware = ((flags & MATCH_ENCRYPTION_AWARE) != 0)
&& componentInfo.encryptionAware;
return matchesUnaware || matchesAware;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 13f48263b69e..3d614a35c13b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -69,6 +69,7 @@ import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
@@ -166,6 +167,10 @@ public class UserManagerService extends IUserManager.Stub {
private static final String XATTR_SERIAL = "user.serial";
+ // Tron counters
+ private static final String TRON_GUEST_CREATED = "users_guest_created";
+ private static final String TRON_USER_CREATED = "users_user_created";
+
private final Context mContext;
private final PackageManagerService mPm;
private final Object mPackagesLock;
@@ -1830,6 +1835,7 @@ public class UserManagerService extends IUserManager.Stub {
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
android.Manifest.permission.MANAGE_USERS);
+ MetricsLogger.count(mContext, isGuest ? TRON_GUEST_CREATED : TRON_USER_CREATED, 1);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 5948d3cb665d..3eae7fcb6fe5 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -383,13 +383,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
// Add a little delay before executing, to give the
// dialog a chance to go away before it takes a
// screenshot.
- // TODO: remove once screenshots are handled by Shell (instead of dumpstate)
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
try {
- // Take a "heavy" bugreport: it's more user friendly, but causes more
- // interference.
+ // Take an "interactive" bugreport.
ActivityManagerNative.getDefault().requestBugReport(true);
} catch (RemoteException e) {
}
@@ -405,11 +403,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
return false;
}
try {
- // Take a "light" bugreport, with less interference.
+ // Take a "full" bugreport.
ActivityManagerNative.getDefault().requestBugReport(false);
} catch (RemoteException e) {
}
- return true;
+ return false;
}
public boolean showDuringKeyguard() {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8a16850bd2b9..72611b7703e9 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1594,10 +1594,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mScreenshotChordEnabled = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enableScreenshotChord);
- // TODO(b/26050571): This can be only reenabled, if there are measure to prevent the alert
- // windows from being fullscreen. Please consult the bug before enabling.
- mForceWindowDrawsStatusBarBackground = false; // mContext.getResources().getBoolean(
- //R.bool.config_forceWindowDrawsStatusBarBackground);
+ mForceWindowDrawsStatusBarBackground = mContext.getResources().getBoolean(
+ R.bool.config_forceWindowDrawsStatusBarBackground);
mGlobalKeyManager = new GlobalKeyManager(mContext);
@@ -2065,7 +2063,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
}
if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
- || mForceWindowDrawsStatusBarBackground) {
+ || (mForceWindowDrawsStatusBarBackground
+ && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT)) {
attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
}
}
@@ -3382,7 +3381,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (awakenFromDreams) {
awakenDreams();
}
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
hideRecentApps(false, true);
} else {
// Otherwise, just launch Home
@@ -4244,6 +4242,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
&& (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
&& (attrs.type == TYPE_STATUS_BAR
|| attrs.type == TYPE_TOAST
+ || attrs.type == TYPE_DOCK_DIVIDER
|| attrs.type == TYPE_VOICE_INTERACTION_STARTING
|| (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
&& attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) {
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 29e3c6328af4..549d2dc39468 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -126,7 +126,7 @@ public class KeyguardServiceDelegate {
final ComponentName keyguardComponent = ComponentName.unflattenFromString(
resources.getString(com.android.internal.R.string.config_keyguardComponent));
- intent.addFlags(Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED);
+ intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
intent.setComponent(keyguardComponent);
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index b49641fb6ab6..751f8715a1e1 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.StackId;
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;
@@ -24,12 +25,14 @@ 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;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION;
import com.android.server.input.InputApplicationHandle;
import com.android.server.wm.WindowManagerService.H;
import android.annotation.NonNull;
import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
import android.os.Message;
import android.os.RemoteException;
import android.util.Slog;
@@ -38,6 +41,7 @@ import android.view.View;
import android.view.WindowManager;
import java.io.PrintWriter;
+import java.util.ArrayDeque;
import java.util.ArrayList;
class AppTokenList extends ArrayList<AppWindowToken> {
@@ -123,6 +127,10 @@ class AppWindowToken extends WindowToken {
// True if the windows associated with this token should be cropped to their stack bounds.
boolean mCropWindowsToStack;
+ boolean mAlwaysFocusable;
+
+ ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
+
AppWindowToken(WindowManagerService _service, IApplicationToken _token,
boolean _voiceInteraction) {
super(_service, _token.asBinder(),
@@ -256,8 +264,8 @@ class AppWindowToken extends WindowToken {
return candidate;
}
- boolean stackCanReceiveKeys() {
- return (windows.size() > 0) ? windows.get(windows.size() - 1).stackCanReceiveKeys() : false;
+ boolean windowsAreFocusable() {
+ return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
}
boolean isVisible() {
@@ -396,12 +404,28 @@ class AppWindowToken extends WindowToken {
}
}
+ void resetReplacingWindows() {
+ if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken
+ + " of replacing window marks.");
+
+ for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+ final WindowState w = allAppWindows.get(i);
+ w.resetReplacing();
+ }
+ }
+
void addWindow(WindowState w) {
for (int i = allAppWindows.size() - 1; i >= 0; i--) {
WindowState candidate = allAppWindows.get(i);
if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null &&
candidate.getWindowTag().equals(w.getWindowTag().toString())) {
candidate.mReplacingWindow = w;
+
+ // if we got a replacement window, reset the timeout to give drawing more time
+ service.mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
+ service.mH.sendMessageDelayed(
+ service.mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, this),
+ WINDOW_REPLACEMENT_TIMEOUT_DURATION);
}
}
allAppWindows.add(w);
@@ -417,7 +441,7 @@ class AppWindowToken extends WindowToken {
return false;
}
- void clearTimedoutReplaceesLocked() {
+ void clearTimedoutReplacesLocked() {
for (int i = allAppWindows.size() - 1; i >= 0;
// removeWindowLocked at bottom of loop may remove multiple entries from
// allAppWindows if the window to be removed has child windows. It also may
@@ -430,10 +454,31 @@ class AppWindowToken extends WindowToken {
continue;
}
candidate.mWillReplaceWindow = false;
- service.removeWindowLocked(candidate);
+ // Since the window already timed out, remove it immediately now.
+ // Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter
+ // delays removal on certain conditions, which will leave the stale window in the
+ // stack and marked mWillReplaceWindow=false, so the window will never be removed.
+ service.removeWindowInnerLocked(candidate);
}
}
+ /**
+ * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
+ * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
+ * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
+ * with a queue.
+ */
+ void freezeBounds() {
+ mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds));
+ }
+
+ /**
+ * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
+ */
+ void unfreezeBounds() {
+ mFrozenBounds.remove();
+ }
+
@Override
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
@@ -480,6 +525,9 @@ class AppWindowToken extends WindowToken {
pw.print(" startingDisplayed="); pw.print(startingDisplayed);
pw.print(" startingMoved"); pw.println(startingMoved);
}
+ if (!mFrozenBounds.isEmpty()) {
+ pw.print(prefix); pw.print("mFrozenBounds="); pw.print(mFrozenBounds);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 59421984dc1f..51787b066859 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -570,38 +570,19 @@ class DisplayContent {
pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
pw.print(subPrefix); pw.print("deferred="); pw.print(mDeferredRemoval);
pw.print(" layoutNeeded="); pw.println(layoutNeeded);
- for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final TaskStack stack = mStacks.get(stackNdx);
- pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
- stack.dump(prefix + " ", pw);
- }
+
pw.println();
pw.println(" Application tokens in top down Z order:");
- int ndx = 0;
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
final TaskStack stack = mStacks.get(stackNdx);
- pw.print(" mStackId="); pw.println(stack.mStackId);
- ArrayList<Task> tasks = stack.getTasks();
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = tasks.get(taskNdx);
- pw.print(" mTaskId="); pw.println(task.mTaskId);
- AppTokenList tokens = task.mAppTokens;
- for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx, ++ndx) {
- final AppWindowToken wtoken = tokens.get(tokenNdx);
- pw.print(" Activity #"); pw.print(tokenNdx);
- pw.print(' '); pw.print(wtoken); pw.println(":");
- wtoken.dump(pw, " ");
- }
- }
- }
- if (ndx == 0) {
- pw.println(" None");
+ stack.dump(prefix + " ", pw);
}
+
pw.println();
if (!mExitingTokens.isEmpty()) {
pw.println();
pw.println(" Exiting tokens:");
- for (int i=mExitingTokens.size()-1; i>=0; i--) {
+ for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
WindowToken token = mExitingTokens.get(i);
pw.print(" Exiting #"); pw.print(i);
pw.print(' '); pw.print(token);
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 8f3d3e30ad1a..72953183a173 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -18,11 +18,17 @@ package com.android.server.wm;
import android.content.Context;
import android.graphics.Rect;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Slog;
-import android.view.IDockDividerVisibilityListener;
+import android.view.DisplayInfo;
+import android.view.IDockedStackListener;
+import android.view.SurfaceControl;
+
+import com.android.server.wm.DimLayer.DimLayerUser;
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;
@@ -33,7 +39,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
/**
* Keeps information about the docked stack divider.
*/
-public class DockedStackDividerController {
+public class DockedStackDividerController implements DimLayerUser {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
@@ -44,9 +50,10 @@ public class DockedStackDividerController {
private WindowState mWindow;
private final Rect mTmpRect = new Rect();
private final Rect mLastRect = new Rect();
- private IDockDividerVisibilityListener mListener;
private boolean mLastVisibility = false;
- private boolean mForceVisibilityReevaluation;
+ private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
+ = new RemoteCallbackList<>();
+ private final DimLayer mDimLayer;
DockedStackDividerController(Context context, DisplayContent displayContent) {
mDisplayContent = displayContent;
@@ -54,6 +61,7 @@ public class DockedStackDividerController {
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());
}
boolean isResizing() {
@@ -83,15 +91,16 @@ public class DockedStackDividerController {
return;
}
mLastVisibility = visible;
- if (mListener != null) {
- try {
- mListener.onDockDividerVisibilityChanged(visible);
- } catch (RemoteException e) {
- Slog.e(TAG, "visibility call failed: " + e);
- }
+ notifyDockedDividerVisibilityChanged(visible);
+ if (!visible) {
+ setResizeDimLayer(false, INVALID_STACK_ID, 0f);
}
}
+ boolean wasVisible() {
+ return mLastVisibility;
+ }
+
void positionDockedStackedDivider(Rect frame) {
TaskStack stack = mDisplayContent.getDockedStackLocked();
if (stack == null) {
@@ -127,11 +136,76 @@ public class DockedStackDividerController {
mLastRect.set(frame);
}
- public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
- if (mListener != null && listener != null) {
- throw new IllegalStateException("Dock divider visibility listener already set!");
+ void notifyDockedDividerVisibilityChanged(boolean visible) {
+ final int size = mDockedStackListeners.beginBroadcast();
+ for (int i = 0; i < size; ++i) {
+ final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+ try {
+ listener.onDividerVisibilityChanged(visible);
+ } catch (RemoteException e) {
+ Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
+ }
+ }
+ mDockedStackListeners.finishBroadcast();
+ }
+
+ void notifyDockedStackExistsChanged(boolean exists) {
+ final int size = mDockedStackListeners.beginBroadcast();
+ for (int i = 0; i < size; ++i) {
+ final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+ try {
+ listener.onDockedStackExistsChanged(exists);
+ } catch (RemoteException e) {
+ Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
+ }
}
- mListener = listener;
- reevaluateVisibility(true);
+ mDockedStackListeners.finishBroadcast();
+ }
+
+ void registerDockedStackListener(IDockedStackListener listener) {
+ mDockedStackListeners.register(listener);
+ notifyDockedDividerVisibilityChanged(wasVisible());
+ notifyDockedStackExistsChanged(
+ mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
+ }
+
+ void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+ SurfaceControl.openTransaction();
+ TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
+ boolean visibleAndValid = visible && stack != null;
+ if (visibleAndValid) {
+ stack.getDimBounds(mTmpRect);
+ if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
+ mDimLayer.setBounds(mTmpRect);
+ mDimLayer.show(mDisplayContent.mService.mLayersController.getResizeDimLayer(),
+ alpha, 0 /* duration */);
+ } else {
+ visibleAndValid = false;
+ }
+ }
+ if (!visibleAndValid) {
+ mDimLayer.hide();
+ }
+ SurfaceControl.closeTransaction();
+ }
+
+ @Override
+ public boolean isFullscreen() {
+ return false;
+ }
+
+ @Override
+ public DisplayInfo getDisplayInfo() {
+ return mDisplayContent.getDisplayInfo();
+ }
+
+ @Override
+ public void getDimBounds(Rect outBounds) {
+ // This dim layer user doesn't need this.
+ }
+
+ @Override
+ public String toShortString() {
+ return TAG;
}
}
diff --git a/services/core/java/com/android/server/wm/DropPermissionsHandler.java b/services/core/java/com/android/server/wm/DropPermissionsHandler.java
index 2ac1ef4124b5..68cfaab02cdb 100644
--- a/services/core/java/com/android/server/wm/DropPermissionsHandler.java
+++ b/services/core/java/com/android/server/wm/DropPermissionsHandler.java
@@ -37,7 +37,7 @@ class DropPermissionsHandler extends IDropPermissions.Stub {
private final ArrayList<Uri> mUris = new ArrayList<Uri>();
- private IBinder mPermissionOwner = null;
+ private IBinder mActivityToken = null;
DropPermissionsHandler(ClipData clipData, int sourceUid, String targetPackage, int mode,
int sourceUserId, int targetUserId) {
@@ -51,18 +51,21 @@ class DropPermissionsHandler extends IDropPermissions.Stub {
}
@Override
- public void take() throws RemoteException {
- if (mPermissionOwner != null) {
+ public void take(IBinder activityToken) throws RemoteException {
+ if (mActivityToken != null) {
return;
}
+ mActivityToken = activityToken;
- mPermissionOwner = ActivityManagerNative.getDefault().newUriPermissionOwner("drop");
+ // Will throw if Activity is not found.
+ IBinder permissionOwner = ActivityManagerNative.getDefault().
+ getUriPermissionOwnerForActivity(mActivityToken);
long origId = Binder.clearCallingIdentity();
try {
for (int i = 0; i < mUris.size(); i++) {
ActivityManagerNative.getDefault().grantUriPermissionFromOwner(
- mPermissionOwner, mSourceUid, mTargetPackage, mUris.get(i), mMode,
+ permissionOwner, mSourceUid, mTargetPackage, mUris.get(i), mMode,
mSourceUserId, mTargetUserId);
}
} finally {
@@ -72,15 +75,24 @@ class DropPermissionsHandler extends IDropPermissions.Stub {
@Override
public void release() throws RemoteException {
- if (mPermissionOwner == null) {
+ if (mActivityToken == null) {
return;
}
+ IBinder permissionOwner = null;
+ try {
+ permissionOwner = ActivityManagerNative.getDefault().
+ getUriPermissionOwnerForActivity(mActivityToken);
+ } catch (Exception e) {
+ // Activity is destroyed, permissions already revoked.
+ return;
+ } finally {
+ mActivityToken = null;
+ }
+
for (int i = 0; i < mUris.size(); ++i) {
ActivityManagerNative.getDefault().revokeUriPermissionFromOwner(
- mPermissionOwner, mUris.get(i), mMode, mSourceUserId);
+ permissionOwner, mUris.get(i), mMode, mSourceUserId);
}
-
- mPermissionOwner = null;
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 72a834315b5d..72970f6c7545 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -61,6 +61,10 @@ class Task implements DimLayer.DimLayerUser {
// Content limits relative to the DisplayContent this sits in.
private Rect mBounds = new Rect();
+ final Rect mPreparedFrozenBounds = new Rect();
+
+ // Bounds used to calculate the insets.
+ private final Rect mTempInsetBounds = new Rect();
// Device rotation as of the last time {@link #mBounds} was set.
int mRotation;
@@ -197,8 +201,7 @@ class Task implements DimLayer.DimLayerUser {
boolean removeAppToken(AppWindowToken wtoken) {
boolean removed = mAppTokens.remove(wtoken);
if (mAppTokens.size() == 0) {
- EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId,
- "removeAppToken: last token");
+ EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
if (mDeferRemoval) {
removeLocked();
}
@@ -267,6 +270,26 @@ class Task implements DimLayer.DimLayerUser {
return boundsChange;
}
+ /**
+ * Sets the bounds used to calculate the insets. See
+ * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
+ */
+ void setTempInsetBounds(Rect tempInsetBounds) {
+ if (tempInsetBounds != null) {
+ mTempInsetBounds.set(tempInsetBounds);
+ } else {
+ mTempInsetBounds.setEmpty();
+ }
+ }
+
+ /**
+ * Gets the bounds used to calculate the insets. See
+ * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
+ */
+ void getTempInsetBounds(Rect out) {
+ out.set(mTempInsetBounds);
+ }
+
void setResizeable(boolean resizeable) {
mResizeable = resizeable;
}
@@ -285,10 +308,20 @@ class Task implements DimLayer.DimLayerUser {
}
if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
resizeWindows();
+ } else {
+ moveWindows();
}
return true;
}
+ /**
+ * Prepares the task bounds to be frozen with the current size. See
+ * {@link AppWindowToken#freezeBounds}.
+ */
+ void prepareFreezingBounds() {
+ mPreparedFrozenBounds.set(mBounds);
+ }
+
boolean scrollLocked(Rect bounds) {
// shift the task bound if it doesn't fully cover the stack area
mStack.getDimBounds(mTmpRect);
@@ -355,7 +388,6 @@ class Task implements DimLayer.DimLayerUser {
mStack.getDisplayContent().getLogicalDisplayRect(out);
}
-
/**
* Calculate the maximum visible area of this task. If the task has only one app,
* the result will be visible frame of that app. If the task has more than one apps,
@@ -463,13 +495,24 @@ class Task implements DimLayer.DimLayerUser {
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
if (!resizingWindows.contains(win)) {
- if (DEBUG_RESIZE) Slog.d(TAG_WM, "setBounds: Resizing " + win);
+ if (DEBUG_RESIZE) Slog.d(TAG_WM, "resizeWindows: Resizing " + win);
resizingWindows.add(win);
}
}
}
}
+ void moveWindows() {
+ 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);
+ if (DEBUG_RESIZE) Slog.d(TAG_WM, "moveWindows: Moving " + win);
+ win.mMovedByResize = true;
+ }
+ }
+ }
+
/**
* Cancels any running app transitions associated with the task.
*/
@@ -560,11 +603,23 @@ class Task implements DimLayer.DimLayerUser {
return "Task=" + mTaskId;
}
- public void printTo(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("taskId="); pw.println(mTaskId);
- pw.print(prefix + prefix); pw.print("mFullscreen="); pw.println(mFullscreen);
- pw.print(prefix + prefix); pw.print("mBounds="); pw.println(mBounds.toShortString());
- pw.print(prefix + prefix); pw.print("mdr="); pw.println(mDeferRemoval);
- pw.print(prefix + prefix); pw.print("appTokens="); pw.println(mAppTokens);
+ public void dump(String prefix, PrintWriter pw) {
+ final String doublePrefix = prefix + " ";
+
+ pw.println(prefix + "taskId=" + mTaskId);
+ pw.println(doublePrefix + "mFullscreen=" + mFullscreen);
+ pw.println(doublePrefix + "mBounds=" + mBounds.toShortString());
+ pw.println(doublePrefix + "mdr=" + mDeferRemoval);
+ pw.println(doublePrefix + "appTokens=" + mAppTokens);
+ pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString());
+
+ final String triplePrefix = doublePrefix + " ";
+
+ for (int i = mAppTokens.size() - 1; i >= 0; i--) {
+ final AppWindowToken wtoken = mAppTokens.get(i);
+ pw.println(triplePrefix + "Activity #" + i + " " + wtoken);
+ wtoken.dump(pw, triplePrefix);
+ }
+
}
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index b9618791b848..fc6ad70513b1 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -114,7 +114,8 @@ public class TaskStack implements DimLayer.DimLayerUser {
* @return True if the stack bounds was changed.
* */
boolean setBounds(
- Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
+ Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
+ SparseArray<Rect> taskTempInsetBounds) {
if (!setBounds(stackBounds)) {
return false;
}
@@ -136,6 +137,9 @@ public class TaskStack implements DimLayer.DimLayerUser {
task.scrollLocked(mTmpRect);
} else {
task.setBounds(bounds, config);
+ task.setTempInsetBounds(
+ taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId)
+ : null);
}
} else {
Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
@@ -144,6 +148,13 @@ public class TaskStack implements DimLayer.DimLayerUser {
return true;
}
+ void prepareFreezingTaskBounds() {
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final Task task = mTasks.get(taskNdx);
+ task.prepareFreezingBounds();
+ }
+ }
+
boolean isFullscreenBounds(Rect bounds) {
if (mDisplayContent == null || bounds == null) {
return true;
@@ -608,16 +619,15 @@ public class TaskStack implements DimLayer.DimLayerUser {
}
public void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
- pw.print(prefix); pw.print("mDeferDetach="); pw.println(mDeferDetach);
- pw.print(prefix); pw.print("mFullscreen="); pw.println(mFullscreen);
- pw.print(prefix); pw.print("mBounds="); pw.println(mBounds.toShortString());
- for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
- pw.print(prefix);
- mTasks.get(taskNdx).printTo(prefix + " ", pw);
+ pw.println(prefix + "mStackId=" + mStackId);
+ pw.println(prefix + "mDeferDetach=" + mDeferDetach);
+ pw.println(prefix + "mFullscreen=" + mFullscreen);
+ pw.println(prefix + "mBounds=" + mBounds.toShortString());
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) {
+ mTasks.get(taskNdx).dump(prefix + " ", pw);
}
if (mAnimationBackgroundSurface.isDimming()) {
- pw.print(prefix); pw.println("mWindowAnimationBackgroundSurface:");
+ pw.println(prefix + "mWindowAnimationBackgroundSurface:");
mAnimationBackgroundSurface.printTo(prefix + " ", pw);
}
if (!mExitingAppTokens.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index af109d4195cf..98033f637562 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -20,6 +20,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.view.DisplayInfo;
import android.view.GestureDetector;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.WindowManagerPolicy.PointerEventListener;
@@ -108,7 +109,8 @@ public class TaskTapPointerEventListener implements PointerEventListener {
final int x = (int) motionEvent.getX();
final int y = (int) motionEvent.getY();
final Task task = mDisplayContent.findTaskForControlPoint(x, y);
- if (task == null) {
+ InputDevice inputDevice = motionEvent.getDevice();
+ if (task == null || inputDevice == null) {
mPointerIconShape = STYLE_NOT_SPECIFIED;
break;
}
@@ -130,7 +132,7 @@ public class TaskTapPointerEventListener implements PointerEventListener {
}
if (mPointerIconShape != iconShape) {
mPointerIconShape = iconShape;
- motionEvent.getDevice().setPointerShape(iconShape);
+ inputDevice.setPointerShape(iconShape);
}
} else {
mPointerIconShape = STYLE_NOT_SPECIFIED;
@@ -139,7 +141,10 @@ public class TaskTapPointerEventListener implements PointerEventListener {
case MotionEvent.ACTION_HOVER_EXIT:
mPointerIconShape = STYLE_NOT_SPECIFIED;
- motionEvent.getDevice().setPointerShape(STYLE_DEFAULT);
+ InputDevice inputDevice = motionEvent.getDevice();
+ if (inputDevice != null) {
+ inputDevice.setPointerShape(STYLE_DEFAULT);
+ }
break;
case MotionEvent.ACTION_UP:
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index 263b411097d8..2cf26180441f 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -1,9 +1,20 @@
-package com.android.server.wm;
+/*
+ * 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.
+ */
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.WINDOW_LAYER_MULTIPLIER;
+package com.android.server.wm;
import android.app.ActivityManager.StackId;
import android.util.Slog;
@@ -11,6 +22,11 @@ import android.view.Display;
import java.io.PrintWriter;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.WINDOW_LAYER_MULTIPLIER;
+
/**
* Controller for assigning layers to windows on the display.
*
@@ -42,7 +58,6 @@ public class WindowLayersController {
private WindowState mPinnedWindow = null;
private WindowState mDockedWindow = null;
private WindowState mDockDivider = null;
- private WindowState mImeWindow = null;
private WindowState mReplacingWindow = null;
final void assignLayersLocked(WindowList windows) {
@@ -133,6 +148,14 @@ public class WindowLayersController {
return 0;
}
+ /**
+ * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
+ * above all application surfaces.
+ */
+ int getResizeDimLayer() {
+ return mDockDivider.mLayer - 1;
+ }
+
private void logDebugLayers(WindowList windows) {
for (int i = 0, n = windows.size(); i < n; i++) {
final WindowState w = windows.get(i);
@@ -146,16 +169,13 @@ public class WindowLayersController {
private void clear() {
mHighestApplicationLayer = 0;
- mImeWindow = null;
mPinnedWindow = null;
mDockedWindow = null;
mDockDivider = null;
}
private void collectSpecialWindows(WindowState w) {
- if (w.mIsImWindow) {
- mImeWindow = w;
- } else if (w.mAttrs.type == TYPE_DOCK_DIVIDER) {
+ if (w.mAttrs.type == TYPE_DOCK_DIVIDER) {
mDockDivider = w;
} else {
final TaskStack stack = w.getStack();
@@ -175,18 +195,17 @@ public class WindowLayersController {
// For pinned and docked stack window, we want to make them above other windows
// also when these windows are animating.
layer = assignAndIncreaseLayerIfNeeded(mDockedWindow, layer);
+
+ // Leave some space here so the dim layer while dismissing docked/fullscreen stack has space
+ // below the divider but above the app windows. It needs to be below the divider in because
+ // the divider sometimes overlaps the app windows.
+ layer++;
layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
// We know that we will be animating a relaunching window in the near future,
// which will receive a z-order increase. We want the replaced window to
// immediately receive the same treatment, e.g. to be above the dock divider.
layer = assignAndIncreaseLayerIfNeeded(mReplacingWindow, layer);
layer = assignAndIncreaseLayerIfNeeded(mPinnedWindow, layer);
- final WindowState inputMethodTarget = mService.mInputMethodTarget;
- // There might be no applications windows yet, so we need to make sure we uplift the input
- // method above the target.
- layer = Math.max(layer,
- inputMethodTarget != null ? inputMethodTarget.mWinAnimator.mAnimLayer + 1 : 0);
- layer = assignAndIncreaseLayerIfNeeded(mImeWindow, layer);
}
private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 845100d14eec..4c3a422731b3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -35,7 +35,7 @@ public class WindowManagerDebugConfig {
static final boolean DEBUG_RESIZE = false;
static final boolean DEBUG = false;
- static final boolean DEBUG_ADD_REMOVE = false;
+ static final boolean DEBUG_ADD_REMOVE = true;
static final boolean DEBUG_FOCUS = true;
static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
static final boolean DEBUG_ANIM = false;
@@ -50,8 +50,8 @@ public class WindowManagerDebugConfig {
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_ORIENTATION = false;
static final boolean DEBUG_CONFIGURATION = false;
- static final boolean DEBUG_APP_TRANSITIONS = false;
- static final boolean DEBUG_STARTING_WINDOW = false;
+ static final boolean DEBUG_APP_TRANSITIONS = true;
+ static final boolean DEBUG_STARTING_WINDOW = true;
static final boolean DEBUG_WALLPAPER = false;
static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
static final boolean DEBUG_DRAG = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6385caac3fa9..a7f7f04b26ca 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,81 +16,11 @@
package com.android.server.wm;
-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.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.StatusBarManager.DISABLE_MASK;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
-import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
-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 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;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.HIDE_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;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
import android.Manifest;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager.StackId;
import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.IActivityManager;
@@ -127,6 +57,7 @@ import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
@@ -154,7 +85,7 @@ import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IApplicationToken;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
import android.view.IInputFilter;
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
@@ -224,9 +155,83 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+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.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.StatusBarManager.DISABLE_MASK;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+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 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;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.HIDE_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;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowManagerService" : TAG_WM;
+
static final int LAYOUT_REPEAT_THRESHOLD = 4;
static final boolean PROFILE_ORIENTATION = false;
@@ -2426,13 +2431,17 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- void setInsetsWindow(Session session, IWindow client,
- int touchableInsets, Rect contentInsets,
+ void setInsetsWindow(Session session, IWindow client, int touchableInsets, Rect contentInsets,
Rect visibleInsets, Region touchableRegion) {
long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
WindowState w = windowForClientLocked(session, client, false);
+ if (DEBUG_LAYOUT) Slog.d(TAG, "setInsetsWindow " + w
+ + ", contentInsets=" + w.mGivenContentInsets + " -> " + contentInsets
+ + ", visibleInsets=" + w.mGivenVisibleInsets + " -> " + visibleInsets
+ + ", touchableRegion=" + w.mGivenTouchableRegion + " -> " + touchableRegion
+ + ", touchableInsets " + w.mTouchableInsets + " -> " + touchableInsets);
if (w != null) {
w.mGivenInsetsPending = false;
w.mGivenContentInsets.set(contentInsets);
@@ -3203,7 +3212,8 @@ public class WindowManagerService extends IWindowManager.Stub
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- Rect taskBounds, Configuration config, boolean cropWindowsToStack) {
+ Rect taskBounds, Configuration config, boolean cropWindowsToStack,
+ boolean alwaysFocusable) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3238,6 +3248,7 @@ public class WindowManagerService extends IWindowManager.Stub
(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
atoken.mLaunchTaskBehind = launchTaskBehind;
atoken.mCropWindowsToStack = cropWindowsToStack;
+ atoken.mAlwaysFocusable = alwaysFocusable;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
@@ -3877,7 +3888,7 @@ public class WindowManagerService extends IWindowManager.Stub
return false;
}
WindowState startingWindow = ttoken.startingWindow;
- if (startingWindow != null) {
+ if (startingWindow != null && ttoken.startingView != null) {
// In this case, the starting icon has already been displayed, so start
// letting windows get shown immediately without any more transitions.
mSkipAppTransitionAnimation = true;
@@ -4651,6 +4662,10 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_STACK) Slog.d(TAG_WM, "attachStack: stackId=" + stackId);
stack = new TaskStack(this, stackId);
mStackIdToStack.put(stackId, stack);
+ if (stackId == DOCKED_STACK_ID) {
+ getDefaultDisplayContentLocked().mDividerControllerLocked
+ .notifyDockedStackExistsChanged(true);
+ }
}
stack.attachDisplayContent(displayContent);
displayContent.attachStack(stack, onTop);
@@ -4676,6 +4691,10 @@ public class WindowManagerService extends IWindowManager.Stub
void detachStackLocked(DisplayContent displayContent, TaskStack stack) {
displayContent.detachStack(stack);
stack.detachDisplay();
+ if (stack.mStackId == DOCKED_STACK_ID) {
+ getDefaultDisplayContentLocked().mDividerControllerLocked
+ .notifyDockedStackExistsChanged(false);
+ }
}
public void detachStack(int stackId) {
@@ -4822,14 +4841,16 @@ public class WindowManagerService extends IWindowManager.Stub
* @return True if the stack is now fullscreen.
* */
public boolean resizeStack(int stackId, Rect bounds,
- SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
+ SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
+ SparseArray<Rect> taskTempInsetBounds) {
synchronized (mWindowMap) {
final TaskStack stack = mStackIdToStack.get(stackId);
if (stack == null) {
throw new IllegalArgumentException("resizeStack: stackId " + stackId
+ " not found.");
}
- if (stack.setBounds(bounds, configs, taskBounds) && stack.isVisibleLocked()) {
+ if (stack.setBounds(bounds, configs, taskBounds, taskTempInsetBounds)
+ && stack.isVisibleLocked()) {
stack.resizeWindows();
stack.getDisplayContent().layoutNeeded = true;
mWindowPlacerLocked.performSurfacePlacement();
@@ -4838,6 +4859,17 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ public void prepareFreezingTaskBounds(int stackId) {
+ synchronized (mWindowMap) {
+ final TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack == null) {
+ throw new IllegalArgumentException("prepareFreezingTaskBounds: stackId " + stackId
+ + " not found.");
+ }
+ stack.prepareFreezingTaskBounds();
+ }
+ }
+
public void positionTaskInStack(int taskId, int stackId, int position, Rect bounds,
Configuration config) {
synchronized (mWindowMap) {
@@ -8074,7 +8106,7 @@ public class WindowManagerService extends IWindowManager.Stub
case WINDOW_REPLACEMENT_TIMEOUT: {
final AppWindowToken token = (AppWindowToken) msg.obj;
synchronized (mWindowMap) {
- token.clearTimedoutReplaceesLocked();
+ token.clearTimedoutReplacesLocked();
}
}
break;
@@ -9078,8 +9110,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (wtoken == token) {
break;
}
- if (mFocusedApp == token && token.stackCanReceiveKeys()) {
- // Whoops, we are below the focused app whose stack can receive keys...
+ if (mFocusedApp == token && token.windowsAreFocusable()) {
+ // Whoops, we are below the focused app whose windows are focusable...
// No focus for you!!!
if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM,
"findFocusedWindow: Reached focused app=" + mFocusedApp);
@@ -9464,6 +9496,32 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ public void notifyAppRelaunching(IBinder token) {
+ synchronized (mWindowMap) {
+ AppWindowToken appWindow = findAppWindowToken(token);
+ if (canFreezeBounds(appWindow)) {
+ appWindow.freezeBounds();
+ }
+ }
+ }
+
+ public void notifyAppRelaunchingFinished(IBinder token) {
+ synchronized (mWindowMap) {
+ AppWindowToken appWindow = findAppWindowToken(token);
+ if (canFreezeBounds(appWindow)) {
+ appWindow.unfreezeBounds();
+ }
+ }
+ }
+
+ private boolean canFreezeBounds(AppWindowToken appWindow) {
+
+ // For freeform windows, we can't freeze the bounds at the moment because this would make
+ // the resizing unresponsive.
+ return appWindow != null && appWindow.mTask != null
+ && !appWindow.mTask.inFreeformWorkspace();
+ }
+
void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
mPolicy.dump(" ", pw, args);
@@ -9732,6 +9790,10 @@ public class WindowManagerService extends IWindowManager.Stub
if ("visible".equals(name) || "visible-apps".equals(name)) {
final boolean appsOnly = "visible-apps".equals(name);
synchronized(mWindowMap) {
+ if (appsOnly) {
+ dumpDisplayContentsLocked(pw, true);
+ }
+
final int numDisplays = mDisplayContents.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final WindowList windowList =
@@ -10128,16 +10190,40 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mWindowMap) {
appWindowToken = findAppWindowToken(token);
if (appWindowToken == null || !appWindowToken.isVisible()) {
- Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " + token);
+ Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+ + token);
return;
}
appWindowToken.setReplacingWindows(animate);
}
+ }
- if (appWindowToken != null) {
- mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
- mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken),
- WINDOW_REPLACEMENT_TIMEOUT_DURATION);
+ /**
+ * If we're replacing the window, schedule a timer to clear the replaced window
+ * after a timeout, in case the replacing window is not coming.
+ *
+ * If we're not replacing the window, clear the replace window settings of the app.
+ *
+ * @param token Application token for the activity whose window might be replaced.
+ * @param replacing Whether the window is being replaced or not.
+ */
+ public void scheduleClearReplacingWindowIfNeeded(IBinder token, boolean replacing) {
+ AppWindowToken appWindowToken = null;
+ synchronized (mWindowMap) {
+ appWindowToken = findAppWindowToken(token);
+ if (appWindowToken == null) {
+ Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token "
+ + token);
+ return;
+ }
+ if (replacing) {
+ mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
+ mH.sendMessageDelayed(
+ mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken),
+ WINDOW_REPLACEMENT_TIMEOUT_DURATION);
+ } else {
+ appWindowToken.resetReplacingWindows();
+ }
}
}
@@ -10157,6 +10243,14 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ @Override
+ public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+ synchronized (mWindowMap) {
+ getDefaultDisplayContentLocked().getDockedDividerController().setResizeDimLayer(
+ visible, targetStackId, alpha);
+ }
+ }
+
public void setTaskResizeable(int taskId, boolean resizeable) {
synchronized (mWindowMap) {
Task task = mTaskIdToTask.get(taskId);
@@ -10175,26 +10269,14 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+ public void registerDockedStackListener(IDockedStackListener listener) {
if (!checkCallingPermission(android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS,
- "registerDockDividerVisibilityListener()")) {
+ "registerDockedStackListener()")) {
return;
}
// TODO(multi-display): The listener is registered on the default display only.
- final DockedStackDividerController controller =
- getDefaultDisplayContentLocked().getDockedDividerController();
- controller.registerDockDividerVisibilityListener(listener);
- try {
- listener.asBinder().linkToDeath(new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- getDefaultDisplayContentLocked().getDockedDividerController()
- .registerDockDividerVisibilityListener(null);
- }
- }, 0);
- } catch (RemoteException e) {
- controller.registerDockDividerVisibilityListener(null);
- }
+ getDefaultDisplayContentLocked().mDividerControllerLocked.registerDockedStackListener(
+ listener);
}
private final class LocalService extends WindowManagerInternal {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c63618527910..b7fd60f1c201 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -309,6 +309,12 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// possible to draw.
final Rect mOutsetFrame = new Rect();
+ /**
+ * Usually empty. Set to the task's tempInsetFrame. See
+ *{@link android.app.IActivityManager#resizeDockedStack}.
+ */
+ final Rect mInsetFrame = new Rect();
+
boolean mContentChanged;
// If a window showing a wallpaper: the requested offset for the
@@ -417,6 +423,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// the window is added and unset when this window reports its first draw.
WindowState mReplacingWindow = null;
+ // Whether this window is being moved via the resize API
+ boolean mMovedByResize;
/**
* Wake lock for drawing.
* Even though it's slightly more expensive to do so, we will use a separate wake lock
@@ -612,8 +620,18 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// We use the parent frame as the containing frame for fullscreen and child windows
mContainingFrame.set(pf);
mDisplayFrame.set(df);
+ mInsetFrame.setEmpty();
} else {
task.getBounds(mContainingFrame);
+ task.getTempInsetBounds(mInsetFrame);
+ if (mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) {
+
+ // If the bounds are frozen, we still want to translate the window freely and only
+ // freeze the size.
+ Rect frozen = mAppToken.mFrozenBounds.peek();
+ mContainingFrame.right = mContainingFrame.left + frozen.width();
+ mContainingFrame.bottom = mContainingFrame.top + frozen.height();
+ }
final WindowState imeWin = mService.mInputMethodWindow;
if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this
&& mContainingFrame.bottom > cf.bottom) {
@@ -672,6 +690,12 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mOutsets.set(0, 0, 0, 0);
}
+ // Denotes the actual frame used to calculate the insets. When resizing in docked mode,
+ // we'd like to freeze the layout, so we also need to freeze the insets temporarily. By the
+ // notion of a task having a different inset frame, we can achieve that while still moving
+ // the task around.
+ final Rect frame = !mInsetFrame.isEmpty() ? mInsetFrame : mFrame;
+
// Make sure the content and visible frames are inside of the
// final window frame.
if (freeformWorkspace && !mFrame.isEmpty()) {
@@ -707,42 +731,69 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mContentFrame.set(mFrame);
}
} else {
- mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
- Math.max(mContentFrame.top, mFrame.top),
- Math.min(mContentFrame.right, mFrame.right),
- Math.min(mContentFrame.bottom, mFrame.bottom));
-
- mVisibleFrame.set(Math.max(mVisibleFrame.left, mFrame.left),
- Math.max(mVisibleFrame.top, mFrame.top),
- Math.min(mVisibleFrame.right, mFrame.right),
- Math.min(mVisibleFrame.bottom, mFrame.bottom));
-
- mStableFrame.set(Math.max(mStableFrame.left, mFrame.left),
- Math.max(mStableFrame.top, mFrame.top),
- Math.min(mStableFrame.right, mFrame.right),
- Math.min(mStableFrame.bottom, mFrame.bottom));
- }
-
- mOverscanInsets.set(Math.max(mOverscanFrame.left - mFrame.left, 0),
- Math.max(mOverscanFrame.top - mFrame.top, 0),
- Math.max(mFrame.right - mOverscanFrame.right, 0),
- Math.max(mFrame.bottom - mOverscanFrame.bottom, 0));
-
- mContentInsets.set(mContentFrame.left - mFrame.left,
- mContentFrame.top - mFrame.top,
- mFrame.right - mContentFrame.right,
- mFrame.bottom - mContentFrame.bottom);
-
- mVisibleInsets.set(mVisibleFrame.left - mFrame.left,
- mVisibleFrame.top - mFrame.top,
- mFrame.right - mVisibleFrame.right,
- mFrame.bottom - mVisibleFrame.bottom);
-
- mStableInsets.set(Math.max(mStableFrame.left - mFrame.left, 0),
- Math.max(mStableFrame.top - mFrame.top, 0),
- Math.max(mFrame.right - mStableFrame.right, 0),
- Math.max(mFrame.bottom - mStableFrame.bottom, 0));
+ mContentFrame.set(Math.max(mContentFrame.left, frame.left),
+ Math.max(mContentFrame.top, frame.top),
+ Math.min(mContentFrame.right, frame.right),
+ Math.min(mContentFrame.bottom, frame.bottom));
+
+ mVisibleFrame.set(Math.max(mVisibleFrame.left, frame.left),
+ Math.max(mVisibleFrame.top, frame.top),
+ Math.min(mVisibleFrame.right, frame.right),
+ Math.min(mVisibleFrame.bottom, frame.bottom));
+
+ mStableFrame.set(Math.max(mStableFrame.left, frame.left),
+ Math.max(mStableFrame.top, frame.top),
+ Math.min(mStableFrame.right, frame.right),
+ Math.min(mStableFrame.bottom, frame.bottom));
+ }
+
+ mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
+ Math.max(mOverscanFrame.top - frame.top, 0),
+ Math.max(frame.right - mOverscanFrame.right, 0),
+ Math.max(frame.bottom - mOverscanFrame.bottom, 0));
+
+ mContentInsets.set(mContentFrame.left - frame.left,
+ mContentFrame.top - frame.top,
+ frame.right - mContentFrame.right,
+ frame.bottom - mContentFrame.bottom);
+
+ mVisibleInsets.set(mVisibleFrame.left - frame.left,
+ mVisibleFrame.top - frame.top,
+ frame.right - mVisibleFrame.right,
+ frame.bottom - mVisibleFrame.bottom);
+
+ if (mAttrs.type == TYPE_DOCK_DIVIDER) {
+
+ // For the docked divider, we calculate the stable insets like a full-screen window
+ // so it can use it to calculate the snap positions.
+ mStableInsets.set(Math.max(mStableFrame.left - mDisplayFrame.left, 0),
+ Math.max(mStableFrame.top - mDisplayFrame.top, 0),
+ Math.max(mDisplayFrame.right - mStableFrame.right, 0),
+ Math.max(mDisplayFrame.bottom - mStableFrame.bottom, 0));
+ } else {
+ mStableInsets.set(Math.max(mStableFrame.left - frame.left, 0),
+ Math.max(mStableFrame.top - frame.top, 0),
+ Math.max(frame.right - mStableFrame.right, 0),
+ Math.max(frame.bottom - mStableFrame.bottom, 0));
+ }
+ if (!mInsetFrame.isEmpty()) {
+ mContentFrame.set(mFrame);
+ mContentFrame.top += mContentInsets.top;
+ mContentFrame.bottom += mContentInsets.bottom;
+ mContentFrame.left += mContentInsets.left;
+ mContentFrame.right += mContentInsets.right;
+ mVisibleFrame.set(mFrame);
+ mVisibleFrame.top += mVisibleInsets.top;
+ mVisibleFrame.bottom += mVisibleInsets.bottom;
+ mVisibleFrame.left += mVisibleInsets.left;
+ mVisibleFrame.right += mVisibleInsets.right;
+ mStableFrame.set(mFrame);
+ mStableFrame.top += mStableInsets.top;
+ mStableFrame.bottom += mStableInsets.bottom;
+ mStableFrame.left += mStableInsets.left;
+ mStableFrame.right += mStableInsets.right;
+ }
mCompatFrame.set(mFrame);
if (mEnforceSizeCompat) {
// If there is a size compatibility scale being applied to the
@@ -1208,9 +1259,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
* sense to call from performLayoutAndPlaceSurfacesLockedInner().)
*/
boolean hasMoved() {
- return mHasSurface && mContentChanged && !mExiting && !mWinAnimator.mLastHidden
- && mService.okToDisplay() && (mFrame.top != mLastFrame.top
- || mFrame.left != mLastFrame.left)
+ return mHasSurface && (mContentChanged || mMovedByResize)
+ && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
+ && (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
&& (mAttachedWindow == null || !mAttachedWindow.hasMoved());
}
@@ -1556,12 +1607,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return isVisibleOrAdding()
&& (mViewVisibility == View.VISIBLE)
&& ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
- && stackCanReceiveKeys();
- }
-
- boolean stackCanReceiveKeys() {
- final TaskStack stack = getStack();
- return stack != null && StackId.canReceiveKeys(stack.mStackId);
+ && (mAppToken == null || mAppToken.windowsAreFocusable());
}
@Override
@@ -1953,8 +1999,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// isDragResizing() or isDragResizeChanged() is true.
boolean resizing = isDragResizing() || isDragResizeChanged();
final Rect backDropFrame = (inFreeformWorkspace() || !resizing) ? frame : mTmpRect;
- mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
- outsets, reportDraw, newConfig, backDropFrame);
+ mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
+ reportDraw, newConfig, backDropFrame);
}
public void registerFocusObserver(IWindowFocusObserver observer) {
@@ -2001,7 +2047,13 @@ final class WindowState implements WindowManagerPolicy.WindowState {
if (task.isDragResizing()) {
return true;
}
- return mDisplayContent.mDividerControllerLocked.isResizing() &&
+
+ // If the bounds are currently frozen, it means that the layout size that the app sees
+ // and the bounds we clip this window to might be different. In order to avoid holes, we
+ // simulate that we are still resizing so the app fills the hole with the resizing
+ // background.
+ return (mDisplayContent.mDividerControllerLocked.isResizing()
+ || mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) &&
!task.inFreeformWorkspace() && !task.isFullscreen();
}
@@ -2300,10 +2352,21 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
void setReplacing(boolean animate) {
- if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) == 0) {
- mWillReplaceWindow = true;
- mReplacingWindow = null;
- mAnimateReplacingWindow = animate;
+ if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) != 0
+ || mAttrs.type == TYPE_APPLICATION_STARTING) {
+ // We don't set replacing on starting windows since they are added by window manager and
+ // not the client so won't be replaced by the client.
+ return;
}
+
+ mWillReplaceWindow = true;
+ mReplacingWindow = null;
+ mAnimateReplacingWindow = animate;
+ }
+
+ void resetReplacing() {
+ mWillReplaceWindow = false;
+ mReplacingWindow = null;
+ mAnimateReplacingWindow = false;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 7605af0bf811..83ab19094fb0 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -37,6 +37,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowManagerService.localLOGV;
+import static com.android.server.wm.WindowState.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
import static com.android.server.wm.WindowState.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
@@ -705,14 +706,12 @@ class WindowStateAnimator {
}
// Something is wrong and SurfaceFlinger will not like this, try to revert to sane values.
+ // This doesn't necessarily mean that there is an error in the system. The sizes might be
+ // incorrect, because it is before the first layout or draw.
if (mTmpSize.width() < 1) {
- if (!mWin.mLayoutNeeded) Slog.w(TAG,
- "Width of " + w + " is not positive " + mTmpSize.width());
mTmpSize.right = mTmpSize.left + 1;
}
if (mTmpSize.height() < 1) {
- if (!mWin.mLayoutNeeded) Slog.w(TAG,
- "Height of " + w + " is not positive " + mTmpSize.height());
mTmpSize.bottom = mTmpSize.top + 1;
}
@@ -1065,7 +1064,16 @@ class WindowStateAnimator {
final int top = w.mYOffset + w.mFrame.top;
// Initialize the decor rect to the entire frame.
- mSystemDecorRect.set(0, 0, width, height);
+ if (w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER) {
+
+ // If we are resizing with the divider, the task bounds might be smaller than the
+ // stack bounds. The system decor is used to clip to the task bounds, which we don't
+ // want in this case in order to avoid holes.
+ final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
+ mSystemDecorRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+ } else {
+ mSystemDecorRect.set(0, 0, width, height);
+ }
// If a freeform window is animating from a position where it would be cutoff, it would be
// cutoff during the animation. We don't want that, so for the duration of the animation
@@ -1184,11 +1192,14 @@ class WindowStateAnimator {
// We don't apply the stack bounds crop if:
// 1. The window is currently animating docked mode or in freeform mode, otherwise the
// animating window will be suddenly (docked) or for whole animation (freeform) cut off.
+ // (Note that we still need to apply the crop if the task being docked is non-resizeable,
+ // in which case the task is running in fullscreen size but cropped to stack bounds.)
// 2. The window that is being replaced during animation, because it was living in a
// different stack. If we suddenly crop it to the new stack bounds, it might get cut off.
// We don't want it to happen, so we let it ignore the stack bounds until it gets removed.
// The window that will replace it will abide them.
- if (isAnimating() && (w.mWillReplaceWindow || w.inDockedWorkspace()
+ if (isAnimating() && (w.mWillReplaceWindow
+ || (w.inDockedWorkspace() && task.isResizeable())
|| w.inFreeformWorkspace())) {
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index cbfb201a529c..feeab27e8fae 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -709,6 +709,7 @@ class WindowSurfacePlacer {
//Slog.i(TAG_WM, "Window " + this + " clearing mContentChanged - done placing");
w.mContentChanged = false;
+ w.mMovedByResize = false;
// Moved from updateWindowsAndWallpaperLocked().
if (w.mHasSurface) {
@@ -738,13 +739,15 @@ class WindowSurfacePlacer {
}
}
}
- /*
- * Updates the shown frame before we set up the surface. This is needed because
- * the resizing could change the top-left position (in addition to size) of the
- * window. setSurfaceBoundariesLocked uses mShownPosition to position the
- * surface.
- */
- winAnimator.computeShownFrameLocked();
+ if (!winAnimator.isAnimating()) {
+ // Updates the shown frame before we set up the surface. This is needed
+ // because the resizing could change the top-left position (in addition to
+ // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to
+ // position the surface. We only apply it to windows that aren't animating,
+ // because we depend on the animation to calculate the correct shown frame
+ // on the next animation step.
+ winAnimator.computeShownFrameLocked();
+ }
winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2082911b58ac..53edc78960d0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -424,6 +424,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final String TAG_PACKAGE_LIST_ITEM = "item";
private static final String TAG_KEEP_UNINSTALLED_PACKAGES = "keep-uninstalled-packages";
private static final String TAG_USER_RESTRICTIONS = "user-restrictions";
+ private static final String TAG_SHORT_SUPPORT_MESSAGE = "short-support-message";
+ private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message";
final DeviceAdminInfo info;
@@ -509,6 +511,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Bundle userRestrictions;
+ // Support text provided by the admin to display to the user.
+ String shortSupportMessage = null;
+ String longSupportMessage = null;
+
ActiveAdmin(DeviceAdminInfo _info) {
info = _info;
}
@@ -688,6 +694,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
UserRestrictionsUtils.writeRestrictions(
out, userRestrictions, TAG_USER_RESTRICTIONS);
}
+ if (!TextUtils.isEmpty(shortSupportMessage)) {
+ out.startTag(null, TAG_SHORT_SUPPORT_MESSAGE);
+ out.text(shortSupportMessage);
+ out.endTag(null, TAG_SHORT_SUPPORT_MESSAGE);
+ }
+ if (!TextUtils.isEmpty(longSupportMessage)) {
+ out.startTag(null, TAG_LONG_SUPPORT_MESSAGE);
+ out.text(longSupportMessage);
+ out.endTag(null, TAG_LONG_SUPPORT_MESSAGE);
+ }
}
void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -801,6 +817,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
keepUninstalledPackages = readPackageList(parser, tag);
} else if (TAG_USER_RESTRICTIONS.equals(tag)) {
UserRestrictionsUtils.readRestrictions(parser, ensureUserRestrictions());
+ } else if (TAG_SHORT_SUPPORT_MESSAGE.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ shortSupportMessage = parser.getText();
+ } else {
+ Log.w(LOG_TAG, "Missing text when loading short support message");
+ }
+ } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ longSupportMessage = parser.getText();
+ } else {
+ Log.w(LOG_TAG, "Missing text when loading long support message");
+ }
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1599,6 +1629,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ /**
+ * Find the admin for the component and userId bit of the uid, then check
+ * the admin's uid matches the uid.
+ */
+ private ActiveAdmin getActiveAdminForUidLocked(ComponentName who, int uid) {
+ final int userId = UserHandle.getUserId(uid);
+ final DevicePolicyData policy = getUserData(userId);
+ ActiveAdmin admin = policy.mAdminMap.get(who);
+ if (admin == null) {
+ throw new SecurityException("No active admin " + who);
+ }
+ if (admin.getUid() != uid) {
+ throw new SecurityException("Admin " + who + " is not owned by uid " + uid);
+ }
+ return admin;
+ }
+
private ActiveAdmin getActiveAdminWithPolicyForUidLocked(ComponentName who, int reqPolicy,
int uid) {
// Try to find an admin which can use reqPolicy
@@ -1610,8 +1657,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new SecurityException("No active admin " + who);
}
if (admin.getUid() != uid) {
- throw new SecurityException("Admin " + who + " is not owned by uid "
- + mInjector.binderGetCallingUid());
+ throw new SecurityException("Admin " + who + " is not owned by uid " + uid);
}
if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) {
return admin;
@@ -1744,7 +1790,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
enforceCrossUserPermission(userHandle);
Intent resolveIntent = new Intent();
resolveIntent.setComponent(adminName);
- List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
+ List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceiversAsUser(
resolveIntent,
PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
userHandle);
@@ -3572,7 +3618,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
try {
- int uid = mContext.getPackageManager().getPackageUid(
+ int uid = mContext.getPackageManager().getPackageUidAsUser(
policy.mDelegatedCertInstallerPackage, userHandle);
return uid == callingUid;
} catch (NameNotFoundException e) {
@@ -4732,7 +4778,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Preconditions.checkNotNull(packageName, "packageName is null");
final int callingUid = mInjector.binderGetCallingUid();
try {
- int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
+ int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, 0);
if (uid != callingUid) {
throw new SecurityException("Invalid packageName");
}
@@ -5241,7 +5287,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
try {
- int uid = mContext.getPackageManager().getPackageUid(
+ int uid = mContext.getPackageManager().getPackageUidAsUser(
policy.mApplicationRestrictionsManagingPackage, userHandle);
return uid == callingUid;
} catch (NameNotFoundException e) {
@@ -5971,7 +6017,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (activeAdmin.getUid() != mInjector.binderGetCallingUid()) {
mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
+ "Calling uid " + mInjector.binderGetCallingUid() + " neither owns the admin"
+ + " " + who + " nor has MANAGE_PROFILE_AND_DEVICE_OWNERS permission");
}
return activeAdmin.userRestrictions;
}
@@ -7102,4 +7150,99 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ @Override
+ public void setShortSupportMessage(@NonNull ComponentName who, String message) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForUidLocked(who,
+ mInjector.binderGetCallingUid());
+ if (!TextUtils.equals(admin.shortSupportMessage, message)) {
+ admin.shortSupportMessage = message;
+ saveSettingsLocked(userHandle);
+ }
+ }
+ }
+
+ @Override
+ public String getShortSupportMessage(@NonNull ComponentName who) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForUidLocked(who,
+ mInjector.binderGetCallingUid());
+ return admin.shortSupportMessage;
+ }
+ }
+
+ @Override
+ public void setLongSupportMessage(@NonNull ComponentName who, String message) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForUidLocked(who,
+ mInjector.binderGetCallingUid());
+ if (!TextUtils.equals(admin.longSupportMessage, message)) {
+ admin.longSupportMessage = message;
+ saveSettingsLocked(userHandle);
+ }
+ }
+ }
+
+ @Override
+ public String getLongSupportMessage(@NonNull ComponentName who) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForUidLocked(who,
+ mInjector.binderGetCallingUid());
+ return admin.longSupportMessage;
+ }
+ }
+
+ @Override
+ public String getShortSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+ throw new SecurityException("Only the system can query support message for user");
+ }
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+ if (admin != null) {
+ return admin.shortSupportMessage;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getLongSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+ throw new SecurityException("Only the system can query support message for user");
+ }
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+ if (admin != null) {
+ return admin.longSupportMessage;
+ }
+ }
+ return null;
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0bbd23e0d80e..dd6493c585f7 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1322,7 +1322,7 @@ public final class SystemServer {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
- intent.addFlags(Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED);
+ intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
}
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index f18617ef4748..d5f384d3bbfb 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -27,6 +27,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
+import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -177,6 +178,25 @@ public final class PrintManagerService extends SystemService {
}
@Override
+ public Icon getCustomPrinterIcon(PrinterId printerId, int userId) {
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ synchronized (mLock) {
+ // Only the current group members can get the printer icons.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+ return null;
+ }
+ userState = getOrCreateUserStateLocked(resolvedUserId);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userState.getCustomPrinterIcon(printerId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index 77a47f81e62b..0af1525ff716 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ParceledListSlice;
+import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -98,6 +99,15 @@ final class RemotePrintService implements DeathRecipient {
public void onPrintersAdded(List<PrinterInfo> printers);
public void onPrintersRemoved(List<PrinterId> printerIds);
public void onServiceDied(RemotePrintService service);
+
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon);
}
public RemotePrintService(Context context, ComponentName componentName, int userId,
@@ -404,6 +414,22 @@ final class RemotePrintService implements DeathRecipient {
printerId).sendToTarget();
}
+ /**
+ * Request the custom printer icon for a printer.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public void requestCustomPrinterIcon(PrinterId printerId) {
+ try {
+ if (isBound()) {
+ mPrintService.requestCustomPrinterIcon(printerId);
+ }
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error requesting icon for " + printerId, re);
+ }
+ }
+
private void handleStartPrinterStateTracking(final PrinterId printerId) {
throwIfDestroyed();
// Take a note we are tracking the printer.
@@ -842,5 +868,19 @@ final class RemotePrintService implements DeathRecipient {
throw new IllegalArgumentException("Invalid printer id: " + printerId);
}
}
+
+ @Override
+ public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon)
+ throws RemoteException {
+ RemotePrintService service = mWeakService.get();
+ if (service != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ service.mCallbacks.onCustomPrinterIconLoaded(printerId, icon);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
}
}
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index c506b6f5f495..40a888041d2d 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -23,6 +23,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
@@ -35,6 +36,7 @@ import android.print.IPrintSpoolerCallbacks;
import android.print.IPrintSpoolerClient;
import android.print.PrintJobId;
import android.print.PrintJobInfo;
+import android.print.PrinterId;
import android.util.Slog;
import android.util.TimedRemoteCaller;
@@ -72,6 +74,15 @@ final class RemotePrintSpooler {
private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller();
+ private final OnCustomPrinterIconLoadedCaller mCustomPrinterIconLoadedCaller =
+ new OnCustomPrinterIconLoadedCaller();
+
+ private final ClearCustomPrinterIconCacheCaller mClearCustomPrinterIconCache =
+ new ClearCustomPrinterIconCacheCaller();
+
+ private final GetCustomPrinterIconCaller mGetCustomPrinterIconCaller =
+ new GetCustomPrinterIconCaller();
+
private final ServiceConnection mServiceConnection = new MyServiceConnection();
private final Context mContext;
@@ -287,6 +298,96 @@ final class RemotePrintSpooler {
}
}
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public final void onCustomPrinterIconLoaded(@NonNull PrinterId printerId,
+ @Nullable Icon icon) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ mCustomPrinterIconLoadedCaller.onCustomPrinterIconLoaded(getRemoteInstanceLazy(),
+ printerId, icon);
+ } catch (RemoteException|TimeoutException re) {
+ Slog.e(LOG_TAG, "Error loading new custom printer icon.", re);
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG,
+ "[user: " + mUserHandle.getIdentifier() + "] onCustomPrinterIconLoaded()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
+ /**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @return the custom icon to be used for the printer or null if the icon is
+ * not yet available
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public final @Nullable Icon getCustomPrinterIcon(@NonNull PrinterId printerId) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ return mGetCustomPrinterIconCaller.getCustomPrinterIcon(getRemoteInstanceLazy(),
+ printerId);
+ } catch (RemoteException|TimeoutException re) {
+ Slog.e(LOG_TAG, "Error getting custom printer icon.", re);
+ return null;
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG,
+ "[user: " + mUserHandle.getIdentifier() + "] getCustomPrinterIcon()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
+ /**
+ * Clear the custom printer icon cache
+ */
+ public void clearCustomPrinterIconCache() {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ mClearCustomPrinterIconCache.clearCustomPrinterIconCache(getRemoteInstanceLazy());
+ } catch (RemoteException|TimeoutException re) {
+ Slog.e(LOG_TAG, "Error clearing custom printer icon cache.", re);
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG,
+ "[user: " + mUserHandle.getIdentifier()
+ + "] clearCustomPrinterIconCache()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
public final boolean setPrintJobTag(PrintJobId printJobId, String tag) {
throwIfCalledOnMainThread();
synchronized (mLock) {
@@ -632,6 +733,69 @@ final class RemotePrintSpooler {
}
}
+ private static final class OnCustomPrinterIconLoadedCaller extends TimedRemoteCaller<Void> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public OnCustomPrinterIconLoadedCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void onCustomPrinterIconCached(int sequence) {
+ onRemoteMethodResult(null, sequence);
+ }
+ };
+ }
+
+ public Void onCustomPrinterIconLoaded(IPrintSpooler target, PrinterId printerId,
+ Icon icon) throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.onCustomPrinterIconLoaded(printerId, icon, mCallback, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
+ private static final class ClearCustomPrinterIconCacheCaller extends TimedRemoteCaller<Void> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public ClearCustomPrinterIconCacheCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void customPrinterIconCacheCleared(int sequence) {
+ onRemoteMethodResult(null, sequence);
+ }
+ };
+ }
+
+ public Void clearCustomPrinterIconCache(IPrintSpooler target)
+ throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.clearCustomPrinterIconCache(mCallback, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
+ private static final class GetCustomPrinterIconCaller extends TimedRemoteCaller<Icon> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public GetCustomPrinterIconCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void onGetCustomPrinterIconResult(Icon icon, int sequence) {
+ onRemoteMethodResult(icon, sequence);
+ }
+ };
+ }
+
+ public Icon getCustomPrinterIcon(IPrintSpooler target, PrinterId printerId)
+ throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.getCustomPrinterIcon(printerId, mCallback, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
private static abstract class BasePrintSpoolerServiceCallbacks
extends IPrintSpoolerCallbacks.Stub {
@Override
@@ -658,6 +822,21 @@ final class RemotePrintSpooler {
public void onSetPrintJobTagResult(boolean success, int sequence) {
/* do nothing */
}
+
+ @Override
+ public void onCustomPrinterIconCached(int sequence) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onGetCustomPrinterIconResult(@Nullable Icon icon, int sequence) {
+ /* do nothing */
+ }
+
+ @Override
+ public void customPrinterIconCacheCleared(int sequence) {
+ /* do nothing */
+ }
}
private static final class PrintSpoolerClient extends IPrintSpoolerClient.Stub {
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 6a50a6eaff21..63d330198488 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -26,6 +26,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -271,6 +272,28 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
return printJob;
}
+ /**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @return the custom icon to be used for the printer or null if the icon is
+ * not yet available
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public Icon getCustomPrinterIcon(PrinterId printerId) {
+ Icon icon = mSpooler.getCustomPrinterIcon(printerId);
+
+ if (icon == null) {
+ RemotePrintService service = mActiveServices.get(printerId.getServiceName());
+ if (service != null) {
+ service.requestCustomPrinterIcon(printerId);
+ }
+ }
+
+ return icon;
+ }
+
public void cancelPrintJob(PrintJobId printJobId, int appId) {
PrintJobInfo printJobInfo = mSpooler.getPrintJobInfo(printJobId, appId);
if (printJobInfo == null) {
@@ -345,6 +368,8 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
throwIfDestroyedLocked();
if (mPrinterDiscoverySession == null) {
+ mSpooler.clearCustomPrinterIconCache();
+
// If we do not have a session, tell all service to create one.
mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
@Override
@@ -533,6 +558,20 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
@Override
+ public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+
+ // No session - nothing to do.
+ if (mPrinterDiscoverySession == null) {
+ return;
+ }
+ mSpooler.onCustomPrinterIconLoaded(printerId, icon);
+ mPrinterDiscoverySession.onCustomPrinterIconLoadedLocked(printerId);
+ }
+ }
+
+ @Override
public void onServiceDied(RemotePrintService service) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -973,16 +1012,16 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>();
- private final Handler mHandler;
+ private final Handler mSessionHandler;
private boolean mIsDestroyed;
public PrinterDiscoverySessionMediator(Context context) {
- mHandler = new SessionHandler(context.getMainLooper());
+ mSessionHandler = new SessionHandler(context.getMainLooper());
// Kick off the session creation.
List<RemotePrintService> services = new ArrayList<RemotePrintService>(
mActiveServices.values());
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION, services)
.sendToTarget();
}
@@ -997,7 +1036,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
SomeArgs args = SomeArgs.obtain();
args.arg1 = observer;
args.arg2 = printers;
- mHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED,
+ mSessionHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED,
args).sendToTarget();
}
}
@@ -1040,7 +1079,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
SomeArgs args = SomeArgs.obtain();
args.arg1 = services;
args.arg2 = priorityList;
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_START_PRINTER_DISCOVERY, args)
.sendToTarget();
}
@@ -1060,7 +1099,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
List<RemotePrintService> services = new ArrayList<RemotePrintService>(
mActiveServices.values());
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_STOP_PRINTER_DISCOVERY, services)
.sendToTarget();
}
@@ -1094,7 +1133,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
SomeArgs args = SomeArgs.obtain();
args.arg1 = service;
args.arg2 = updateList;
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_VALIDATE_PRINTERS, args)
.sendToTarget();
}
@@ -1126,7 +1165,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
SomeArgs args = SomeArgs.obtain();
args.arg1 = service;
args.arg2 = printerId;
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_START_PRINTER_STATE_TRACKING, args)
.sendToTarget();
}
@@ -1153,7 +1192,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
SomeArgs args = SomeArgs.obtain();
args.arg1 = service;
args.arg2 = printerId;
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_STOP_PRINTER_STATE_TRACKING, args)
.sendToTarget();
}
@@ -1183,7 +1222,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
// Tell the services we are done.
List<RemotePrintService> services = new ArrayList<RemotePrintService>(
mActiveServices.values());
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION, services)
.sendToTarget();
}
@@ -1209,7 +1248,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
if (addedPrinters != null) {
- mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
+ mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
addedPrinters).sendToTarget();
}
}
@@ -1234,7 +1273,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
if (removedPrinterIds != null) {
- mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
+ mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
removedPrinterIds).sendToTarget();
}
}
@@ -1250,6 +1289,37 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
service.destroy();
}
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * This increments the icon generation and adds the printer again which triggers an update
+ * in all users of the currently known printers.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public void onCustomPrinterIconLoadedLocked(PrinterId printerId) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onCustomPrinterIconLoadedLocked()");
+ }
+ if (mIsDestroyed) {
+ Log.w(LOG_TAG, "Not updating printer - session destroyed");
+ return;
+ }
+
+ PrinterInfo printer = mPrinters.get(printerId);
+ if (printer != null) {
+ PrinterInfo newPrinter = (new PrinterInfo.Builder(printer))
+ .incCustomPrinterIconGen().build();
+ mPrinters.put(printerId, newPrinter);
+
+ ArrayList<PrinterInfo> addedPrinters = new ArrayList<>(1);
+ addedPrinters.add(newPrinter);
+ mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
+ addedPrinters).sendToTarget();
+ }
+ }
+
public void onServiceDiedLocked(RemotePrintService service) {
// Remove the reported by that service.
removePrintersForServiceLocked(service.getComponentName());
@@ -1261,12 +1331,12 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
return;
}
// Tell the service to create a session.
- mHandler.obtainMessage(
+ mSessionHandler.obtainMessage(
SessionHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION,
service).sendToTarget();
// Start printer discovery if necessary.
if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
- mHandler.obtainMessage(
+ mSessionHandler.obtainMessage(
SessionHandler.MSG_START_PRINTER_DISCOVERY,
service).sendToTarget();
}
@@ -1278,7 +1348,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
SomeArgs args = SomeArgs.obtain();
args.arg1 = service;
args.arg2 = printerId;
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_START_PRINTER_STATE_TRACKING, args)
.sendToTarget();
}
@@ -1348,7 +1418,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
for (int i = 0; i < removedPrinterCount; i++) {
mPrinters.remove(removedPrinterIds.get(i));
}
- mHandler.obtainMessage(
+ mSessionHandler.obtainMessage(
SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
removedPrinterIds).sendToTarget();
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 435b6026830e..90e4acfb9044 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -208,6 +208,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
}
@Override
+ void powerManagerReboot(String reason) {
+ context.powerManager.reboot(reason);
+ }
+
+ @Override
boolean systemPropertiesGetBoolean(String key, boolean def) {
return context.systemProperties.getBoolean(key, def);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 7747fd9a1cb5..672058bca8d7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -758,7 +758,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
when(mContext.userManager.getUserRestrictions()).thenReturn(new Bundle());
// Now call clear.
- doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUid(
+ doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUidAsUser(
eq(admin1.getPackageName()),
anyInt());
dpm.clearDeviceOwnerApp(admin1.getPackageName());
@@ -797,7 +797,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
// Now call clear.
- doReturn(DpmMockContext.CALLER_UID).when(mContext.packageManager).getPackageUid(
+ doReturn(DpmMockContext.CALLER_UID).when(mContext.packageManager).getPackageUidAsUser(
eq(admin1.getPackageName()),
anyInt());
try {
@@ -951,7 +951,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
final int appRestrictionsManagerAppId = 20987;
final int appRestrictionsManagerUid = UserHandle.getUid(
DpmMockContext.CALLER_USER_HANDLE, appRestrictionsManagerAppId);
- doReturn(appRestrictionsManagerUid).when(mContext.packageManager).getPackageUid(
+ doReturn(appRestrictionsManagerUid).when(mContext.packageManager).getPackageUidAsUser(
eq(appRestrictionsManagerPackage),
eq(DpmMockContext.CALLER_USER_HANDLE));
mContext.binder.callingUid = appRestrictionsManagerUid;
@@ -1349,4 +1349,131 @@ public class DevicePolicyManagerTest extends DpmTestBase {
when(mContext.wifiManager.getConnectionInfo()).thenReturn(wi);
assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress());
}
+
+ public void testRebootCanOnlyBeCalledByDeviceOwner() throws Exception {
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+ // In this test, change the caller user to "system".
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ // Make sure admin1 is installed on system user.
+ setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+
+ // Set admin1 as DA.
+ dpm.setActiveAdmin(admin1, false);
+ assertTrue(dpm.isAdminActive(admin1));
+ try {
+ dpm.reboot(admin1);
+ fail("DA calls DPM.reboot(), did not throw expected SecurityException");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex("does not own the device", expected.getMessage());
+ }
+
+ // Set admin1 as PO.
+ assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
+ try {
+ dpm.reboot(admin1);
+ fail("PO calls DPM.reboot(), did not throw expected SecurityException");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex("does not own the device", expected.getMessage());
+ }
+
+ // Remove PO and add DO.
+ dpm.clearProfileOwner(admin1);
+ assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
+
+ dpm.reboot(admin1);
+ }
+
+ public void testSetGetSupportText() {
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ dpm.setActiveAdmin(admin1, true);
+ dpm.setActiveAdmin(admin2, true);
+ mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS);
+
+ // Null default support messages.
+ {
+ assertNull(dpm.getLongSupportMessage(admin1));
+ assertNull(dpm.getShortSupportMessage(admin1));
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ assertNull(dpm.getShortSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ assertNull(dpm.getLongSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ }
+
+ // Only system can call the per user versions.
+ {
+ try {
+ dpm.getShortSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE);
+ fail("Only system should be able to call getXXXForUser versions");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex("message for user", expected.getMessage());
+ }
+ try {
+ dpm.getLongSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE);
+ fail("Only system should be able to call getXXXForUser versions");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex("message for user", expected.getMessage());
+ }
+ }
+
+ // Can't set message for admin in another uid.
+ {
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID + 1;
+ try {
+ dpm.setShortSupportMessage(admin1, "Some text");
+ fail("Admins should only be able to change their own support text.");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex("is not owned by uid", expected.getMessage());
+ }
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ }
+
+ // Set/Get short returns what it sets and other admins text isn't changed.
+ {
+ final String supportText = "Some text to test with.";
+ dpm.setShortSupportMessage(admin1, supportText);
+ assertEquals(supportText, dpm.getShortSupportMessage(admin1));
+ assertNull(dpm.getLongSupportMessage(admin1));
+ assertNull(dpm.getShortSupportMessage(admin2));
+
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ assertEquals(supportText, dpm.getShortSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ assertNull(dpm.getShortSupportMessageForUser(admin2,
+ DpmMockContext.CALLER_USER_HANDLE));
+ assertNull(dpm.getLongSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ dpm.setShortSupportMessage(admin1, null);
+ assertNull(dpm.getShortSupportMessage(admin1));
+ }
+
+ // Set/Get long returns what it sets and other admins text isn't changed.
+ {
+ final String supportText = "Some text to test with.\nWith more text.";
+ dpm.setLongSupportMessage(admin1, supportText);
+ assertEquals(supportText, dpm.getLongSupportMessage(admin1));
+ assertNull(dpm.getShortSupportMessage(admin1));
+ assertNull(dpm.getLongSupportMessage(admin2));
+
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ assertEquals(supportText, dpm.getLongSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ assertNull(dpm.getLongSupportMessageForUser(admin2,
+ DpmMockContext.CALLER_USER_HANDLE));
+ assertNull(dpm.getShortSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ dpm.setLongSupportMessage(admin1, null);
+ assertNull(dpm.getLongSupportMessage(admin1));
+ }
+ }
}
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 66d701d0a3ca..56667e5ac478 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -134,6 +134,9 @@ public class DpmMockContext extends MockContext {
public void goToSleep(long time, int reason, int flags) {
}
+
+ public void reboot(String reason) {
+ }
}
public static class SystemPropertiesForMock {
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 5b33e4d4ca40..c557ab7e1e93 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -117,7 +117,7 @@ public abstract class DpmTestBase extends AndroidTestCase {
// We need to rewrite the UID in the activity info.
realResolveInfo.get(0).activityInfo.applicationInfo = ai;
- doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceivers(
+ doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceiversAsUser(
MockUtils.checkIntentComponent(admin),
eq(PackageManager.GET_META_DATA
| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
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 df7b412a27fe..264088903777 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -35,7 +35,7 @@ import java.util.ArrayList;
public class RankingHelperTest extends AndroidTestCase {
@Mock NotificationUsageStats mUsageStats;
- @Mock Handler handler;
+ @Mock RankingHandler handler;
private Notification mNotiGroupGSortA;
private Notification mNotiGroupGSortB;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 2b0919b7bfc0..23e889406394 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -374,7 +374,7 @@ public class UsageStatsService extends SystemService implements
for (int i = 0; i < userIds.length; i++) {
final int userId = userIds[i];
List<PackageInfo> packages =
- getContext().getPackageManager().getInstalledPackages(
+ getContext().getPackageManager().getInstalledPackagesAsUser(
PackageManager.GET_DISABLED_COMPONENTS
| PackageManager.GET_UNINSTALLED_PACKAGES,
userId);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 5188e5fd1f7d..72621a422ce6 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -148,7 +148,7 @@ class UserUsageStatsService {
private void initializeDefaultsForApps(long currentTimeMillis, long deviceUsageTime,
boolean firstUpdate) {
PackageManager pm = mContext.getPackageManager();
- List<PackageInfo> packages = pm.getInstalledPackages(0, mUserId);
+ List<PackageInfo> packages = pm.getInstalledPackagesAsUser(0, mUserId);
final int packageCount = packages.size();
for (int i = 0; i < packageCount; i++) {
final PackageInfo pi = packages.get(i);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 92d5aa903397..aa95e1d69a10 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -242,8 +242,13 @@ public final class Call {
*/
public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
+ /**
+ * Whether the call is associated with the work profile.
+ */
+ public static final int PROPERTY_WORK_CALL = 0x00000020;
+
//******************************************************************************************
- // Next PROPERTY value: 0x00000020
+ // Next PROPERTY value: 0x00000040
//******************************************************************************************
private final Uri mHandle;
@@ -269,7 +274,7 @@ public final class Call {
* @return Whether the specified capability is supported.
*/
public static boolean can(int capabilities, int capability) {
- return (capabilities & capability) != 0;
+ return (capabilities & capability) == capability;
}
/**
@@ -351,7 +356,7 @@ public final class Call {
* @return Whether the specified property is supported.
*/
public static boolean hasProperty(int properties, int property) {
- return (properties & property) != 0;
+ return (properties & property) == property;
}
/**
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 17bd08c183c5..deb98f4211b1 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -294,7 +294,7 @@ public abstract class Connection extends Conferenceable {
* @hide
*/
public static boolean can(int capabilities, int capability) {
- return (capabilities & capability) != 0;
+ return (capabilities & capability) == capability;
}
/**
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index 27ee804bebd4..a915d37d653b 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -155,8 +155,7 @@ public class DefaultDialerManager {
// Get the list of apps registered for the DIAL intent with empty scheme
Intent intent = new Intent(Intent.ACTION_DIAL);
- List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent,
- PackageManager.MATCH_ENCRYPTION_DEFAULT);
+ List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);
List<String> packageNames = new ArrayList<>();
@@ -209,7 +208,7 @@ public class DefaultDialerManager {
final List<String> result = new ArrayList<>();
final List<ResolveInfo> resolveInfoList = context.getPackageManager()
- .queryIntentActivities(intent, PackageManager.MATCH_ENCRYPTION_DEFAULT);
+ .queryIntentActivities(intent, 0);
final int length = resolveInfoList.size();
for (int i = 0; i < length; i++) {
final ActivityInfo info = resolveInfoList.get(i).activityInfo;
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 5087080ebdf8..426b240e9c78 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -49,7 +49,7 @@ import java.util.List;
* <pre>
* {@code
* <service android:name="your.package.YourInCallServiceImplementation"
- * android:permission="android.permission.BIND_IN_CALL_SERVICE">
+ * android:permission="android.permission.BIND_INCALL_SERVICE">
* <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
* <intent-filter>
* <action android:name="android.telecom.InCallService"/>
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 8537f9cf2f86..c680999e6fb9 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -153,6 +153,17 @@ public class ServiceState implements Parcelable {
* @hide
*/
public static final int RIL_RADIO_TECHNOLOGY_IWLAN = 18;
+
+ /** @hide */
+ public static final int RIL_RADIO_CDMA_TECHNOLOGY_BITMASK =
+ (1 << (RIL_RADIO_TECHNOLOGY_IS95A - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_IS95B - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_1xRTT - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_0 - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_A - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_B - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_EHRPD - 1));
+
/**
* Available registration states for GSM, UMTS and CDMA.
*/
@@ -1141,16 +1152,8 @@ public class ServiceState implements Parcelable {
}
/** @hide */
- public static boolean hasCdma(int radioTechnologyBitmask) {
- int cdmaBitmask = (RIL_RADIO_TECHNOLOGY_IS95A
- | RIL_RADIO_TECHNOLOGY_IS95B
- | RIL_RADIO_TECHNOLOGY_1xRTT
- | RIL_RADIO_TECHNOLOGY_EVDO_0
- | RIL_RADIO_TECHNOLOGY_EVDO_A
- | RIL_RADIO_TECHNOLOGY_EVDO_B
- | RIL_RADIO_TECHNOLOGY_EHRPD);
-
- return ((radioTechnologyBitmask & cdmaBitmask) != 0);
+ public static boolean bearerBitmapHasCdma(int radioTechnologyBitmap) {
+ return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK & radioTechnologyBitmap) != 0;
}
/** @hide */
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 36407e195ac6..99989377c374 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1207,7 +1207,7 @@ public class SubscriptionManager {
}
} catch (RemoteException ex) {
}
- logd("getSimStateForSubscriber: simState=" + simState + " slotIdx=" + slotIdx);
+
return simState;
}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 2813df537457..85d567d8e369 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -34,7 +34,6 @@ import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
@@ -104,7 +103,7 @@ public class MockPackageManager extends PackageManager {
/** @hide */
@Override
- public int getPackageUid(String packageName, int userHandle)
+ public int getPackageUidAsUser(String packageName, int userHandle)
throws NameNotFoundException {
throw new UnsupportedOperationException();
}
@@ -175,7 +174,7 @@ public class MockPackageManager extends PackageManager {
/** @hide */
@Override
- public List<PackageInfo> getInstalledPackages(int flags, int userId) {
+ public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
throw new UnsupportedOperationException();
}
@@ -356,7 +355,7 @@ public class MockPackageManager extends PackageManager {
/** @hide */
@Override
- public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) {
+ public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
throw new UnsupportedOperationException();
}
@@ -747,7 +746,7 @@ public class MockPackageManager extends PackageManager {
* @hide - to match hiding in superclass
*/
@Override
- public void getPackageSizeInfo(String packageName, int userHandle,
+ public void getPackageSizeInfoAsUser(String packageName, int userHandle,
IPackageStatsObserver observer) {
throw new UnsupportedOperationException();
}
@@ -820,7 +819,7 @@ public class MockPackageManager extends PackageManager {
@Override
public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
int flags, String installerPackageName, Uri verificationURI,
- ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+ ContainerEncryptionParams encryptionParams) {
throw new UnsupportedOperationException();
}
@@ -891,7 +890,7 @@ public class MockPackageManager extends PackageManager {
* @hide
*/
@Override
- public int getIntentVerificationStatus(String packageName, int userId) {
+ public int getIntentVerificationStatusAsUser(String packageName, int userId) {
throw new UnsupportedOperationException();
}
@@ -899,7 +898,7 @@ public class MockPackageManager extends PackageManager {
* @hide
*/
@Override
- public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+ public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) {
throw new UnsupportedOperationException();
}
@@ -916,16 +915,30 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
- @Override
+ /** {@removed} */
+ @Deprecated
public String getDefaultBrowserPackageName(int userId) {
throw new UnsupportedOperationException();
}
+ /** {@hide} */
@Override
+ public String getDefaultBrowserPackageNameAsUser(int userId) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@removed} */
+ @Deprecated
public boolean setDefaultBrowserPackageName(String packageName, int userId) {
throw new UnsupportedOperationException();
}
+ /** {@hide} */
+ @Override
+ public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* @hide
*/
@@ -957,7 +970,7 @@ public class MockPackageManager extends PackageManager {
@Override
public void installPackageWithVerification(Uri packageURI,
PackageInstallObserver observer, int flags, String installerPackageName,
- Uri verificationURI, ManifestDigest manifestDigest,
+ Uri verificationURI,
ContainerEncryptionParams encryptionParams) {
throw new UnsupportedOperationException();
}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 3c2659f6ab59..b78fd494e555 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@ public class WindowManagerPermissionTests extends TestCase {
try {
mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
- Configuration.EMPTY, false);
+ Configuration.EMPTY, false, false);
fail("IWindowManager.addAppToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 0f839801ff81..a4f4ba928855 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -27,6 +27,8 @@ main := Main.cpp
sources := \
compile/IdAssigner.cpp \
compile/Png.cpp \
+ compile/PseudolocaleGenerator.cpp \
+ compile/Pseudolocalizer.cpp \
compile/XmlIdCollector.cpp \
flatten/Archive.cpp \
flatten/TableFlattener.cpp \
@@ -66,6 +68,8 @@ sources := \
testSources := \
compile/IdAssigner_test.cpp \
+ compile/PseudolocaleGenerator_test.cpp \
+ compile/Pseudolocalizer_test.cpp \
compile/XmlIdCollector_test.cpp \
flatten/FileExportWriter_test.cpp \
flatten/TableFlattener_test.cpp \
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index d864f664f9db..5fce2c16f630 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -52,13 +52,17 @@ struct PrintVisitor : public ValueVisitor {
void visit(Style* style) override {
std::cout << "(style)";
if (style->parent) {
+ const Reference& parentRef = style->parent.value();
std::cout << " parent=";
- if (style->parent.value().name) {
- std::cout << style->parent.value().name.value() << " ";
+ if (parentRef.name) {
+ if (parentRef.privateReference) {
+ std::cout << "*";
+ }
+ std::cout << parentRef.name.value() << " ";
}
- if (style->parent.value().id) {
- std::cout << style->parent.value().id.value();
+ if (parentRef.id) {
+ std::cout << parentRef.id.value();
}
}
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index d4c536f61c45..e1f9642d27d7 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -19,9 +19,12 @@
#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"
+#include <functional>
#include <sstream>
namespace aapt {
@@ -35,6 +38,111 @@ static bool shouldIgnoreElement(const StringPiece16& ns, const StringPiece16& na
return ns.empty() && (name == u"skip" || name == u"eat-comment");
}
+static uint32_t parseFormatType(const StringPiece16& piece) {
+ if (piece == u"reference") return android::ResTable_map::TYPE_REFERENCE;
+ else if (piece == u"string") return android::ResTable_map::TYPE_STRING;
+ else if (piece == u"integer") return android::ResTable_map::TYPE_INTEGER;
+ else if (piece == u"boolean") return android::ResTable_map::TYPE_BOOLEAN;
+ else if (piece == u"color") return android::ResTable_map::TYPE_COLOR;
+ else if (piece == u"float") return android::ResTable_map::TYPE_FLOAT;
+ else if (piece == u"dimension") return android::ResTable_map::TYPE_DIMENSION;
+ else if (piece == u"fraction") return android::ResTable_map::TYPE_FRACTION;
+ else if (piece == u"enum") return android::ResTable_map::TYPE_ENUM;
+ else if (piece == u"flags") return android::ResTable_map::TYPE_FLAGS;
+ return 0;
+}
+
+static uint32_t parseFormatAttribute(const StringPiece16& str) {
+ uint32_t mask = 0;
+ for (StringPiece16 part : util::tokenize(str, u'|')) {
+ StringPiece16 trimmedPart = util::trimWhitespace(part);
+ uint32_t type = parseFormatType(trimmedPart);
+ if (type == 0) {
+ return 0;
+ }
+ mask |= type;
+ }
+ return mask;
+}
+
+/**
+ * A parsed resource ready to be added to the ResourceTable.
+ */
+struct ParsedResource {
+ ResourceName name;
+ Source source;
+ ResourceId id;
+ Maybe<SymbolState> symbolState;
+ std::u16string comment;
+ std::unique_ptr<Value> value;
+ 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, const ConfigDescription& config,
+ IDiagnostics* diag, ParsedResource* res) {
+ if (res->symbolState) {
+ Symbol symbol;
+ symbol.state = res->symbolState.value();
+ symbol.source = res->source;
+ symbol.comment = res->comment;
+ if (!table->setSymbolState(res->name, res->id, symbol, diag)) {
+ return false;
+ }
+ }
+
+ if (res->value) {
+ // Attach the comment, source and config to the value.
+ res->value->setComment(std::move(res->comment));
+ res->value->setSource(std::move(res->source));
+
+ if (!table->addResource(res->name, res->id, config, std::move(res->value), diag)) {
+ return false;
+ }
+ }
+
+ bool error = false;
+ for (ParsedResource& child : res->childResources) {
+ error |= !addResourcesToTable(table, config, diag, &child);
+ }
+ return !error;
+}
+
+// Convenient aliases for more readable function calls.
+enum {
+ kAllowRawString = true,
+ kNoRawString = false
+};
+
ResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
const ConfigDescription& config,
const ResourceParserOptions& options) :
@@ -146,69 +254,6 @@ bool ResourceParser::parse(xml::XmlPullParser* parser) {
return !error;
}
-static bool shouldStripResource(const xml::XmlPullParser* parser,
- const Maybe<std::u16string> productToMatch) {
- assert(parser->getEvent() == xml::XmlPullParser::Event::kStartElement);
-
- if (Maybe<StringPiece16> maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) {
- if (!productToMatch) {
- if (maybeProduct.value() != u"default" && maybeProduct.value() != u"phone") {
- // We didn't specify a product and this is not a default product, so skip.
- return true;
- }
- } else {
- if (productToMatch && maybeProduct.value() != productToMatch.value()) {
- // We specified a product, but they don't match.
- return true;
- }
- }
- }
- return false;
-}
-
-/**
- * A parsed resource ready to be added to the ResourceTable.
- */
-struct ParsedResource {
- ResourceName name;
- Source source;
- ResourceId id;
- Maybe<SymbolState> symbolState;
- std::u16string comment;
- std::unique_ptr<Value> value;
- std::list<ParsedResource> childResources;
-};
-
-// Recursively adds resources to the ResourceTable.
-static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config,
- IDiagnostics* diag, ParsedResource* res) {
- if (res->symbolState) {
- Symbol symbol;
- symbol.state = res->symbolState.value();
- symbol.source = res->source;
- symbol.comment = res->comment;
- if (!table->setSymbolState(res->name, res->id, symbol, diag)) {
- return false;
- }
- }
-
- if (res->value) {
- // Attach the comment, source and config to the value.
- res->value->setComment(std::move(res->comment));
- res->value->setSource(std::move(res->source));
-
- if (!table->addResource(res->name, res->id, config, std::move(res->value), diag)) {
- return false;
- }
- }
-
- bool error = false;
- for (ParsedResource& child : res->childResources) {
- error |= !addResourcesToTable(table, config, diag, &child);
- }
- return !error;
-}
-
bool ResourceParser::parseResources(xml::XmlPullParser* parser) {
std::set<ResourceName> strippedResources;
@@ -244,118 +289,28 @@ bool ResourceParser::parseResources(xml::XmlPullParser* parser) {
continue;
}
- if (elementName == u"item") {
- // Items simply have their type encoded in the type attribute.
- if (Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type")) {
- elementName = maybeType.value().toString();
- } else {
- mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
- << "<item> must have a 'type' attribute");
- error = true;
- continue;
- }
- }
-
ParsedResource parsedResource;
parsedResource.source = mSource.withLine(parser->getLineNumber());
parsedResource.comment = std::move(comment);
- if (Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name")) {
- parsedResource.name.entry = maybeName.value().toString();
+ // Extract the product name if it exists.
+ Maybe<std::u16string> product;
+ if (Maybe<StringPiece16> maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) {
+ product = maybeProduct.value().toString();
+ }
- } else if (elementName != u"public-group") {
- mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
- << "<" << elementName << "> tag must have a 'name' attribute");
+ // Parse the resource regardless of product.
+ if (!parseResource(parser, &parsedResource)) {
error = true;
continue;
}
- // Check if we should skip this product.
- const bool stripResource = shouldStripResource(parser, mOptions.product);
-
- bool result = true;
- if (elementName == u"id") {
- parsedResource.name.type = ResourceType::kId;
- parsedResource.value = util::make_unique<Id>();
- } else if (elementName == u"string") {
- parsedResource.name.type = ResourceType::kString;
- result = parseString(parser, &parsedResource);
- } else if (elementName == u"color") {
- parsedResource.name.type = ResourceType::kColor;
- result = parseColor(parser, &parsedResource);
- } else if (elementName == u"drawable") {
- parsedResource.name.type = ResourceType::kDrawable;
- result = parseColor(parser, &parsedResource);
- } else if (elementName == u"bool") {
- parsedResource.name.type = ResourceType::kBool;
- result = parsePrimitive(parser, &parsedResource);
- } else if (elementName == u"integer") {
- parsedResource.name.type = ResourceType::kInteger;
- result = parsePrimitive(parser, &parsedResource);
- } else if (elementName == u"dimen") {
- parsedResource.name.type = ResourceType::kDimen;
- result = parsePrimitive(parser, &parsedResource);
- } else if (elementName == u"fraction") {
- parsedResource.name.type = ResourceType::kFraction;
- result = parsePrimitive(parser, &parsedResource);
- } else if (elementName == u"style") {
- parsedResource.name.type = ResourceType::kStyle;
- result = parseStyle(parser, &parsedResource);
- } else if (elementName == u"plurals") {
- parsedResource.name.type = ResourceType::kPlurals;
- result = parsePlural(parser, &parsedResource);
- } else if (elementName == u"array") {
- parsedResource.name.type = ResourceType::kArray;
- result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_ANY);
- } else if (elementName == u"string-array") {
- parsedResource.name.type = ResourceType::kArray;
- result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_STRING);
- } else if (elementName == u"integer-array") {
- parsedResource.name.type = ResourceType::kArray;
- result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_INTEGER);
- } else if (elementName == u"declare-styleable") {
- parsedResource.name.type = ResourceType::kStyleable;
- result = parseDeclareStyleable(parser, &parsedResource);
- } else if (elementName == u"attr") {
- parsedResource.name.type = ResourceType::kAttr;
- result = parseAttr(parser, &parsedResource);
- } else if (elementName == u"public") {
- result = parsePublic(parser, &parsedResource);
- } else if (elementName == u"java-symbol" || elementName == u"symbol") {
- result = parseSymbol(parser, &parsedResource);
- } else if (elementName == u"public-group") {
- result = parsePublicGroup(parser, &parsedResource);
- } else if (elementName == u"add-resource") {
- result = parseAddResource(parser, &parsedResource);
- } else {
- // Try parsing the elementName (or type) as a resource. These shall only be
- // resources like 'layout' or 'xml' and they can only be references.
- if (const ResourceType* type = parseResourceType(elementName)) {
- parsedResource.name.type = *type;
- parsedResource.value = parseXml(parser, android::ResTable_map::TYPE_REFERENCE,
- false);
- if (!parsedResource.value) {
- mDiag->error(DiagMessage(parsedResource.source) << "invalid value for type '"
- << *type << "'. Expected a reference");
- result = false;
- }
- } else {
- mDiag->warn(DiagMessage(mSource.withLine(parser->getLineNumber()))
- << "unknown resource type '" << elementName << "'");
- }
- }
-
- if (result) {
- // We successfully parsed the resource.
-
- if (stripResource) {
- // 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 {
- error |= !addResourcesToTable(mTable, mConfig, mDiag, &parsedResource);
- }
- } else {
+ // 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, mConfig, mDiag, &parsedResource)) {
error = true;
}
}
@@ -373,10 +328,173 @@ bool ResourceParser::parseResources(xml::XmlPullParser* parser) {
return !error;
}
-enum {
- kAllowRawString = true,
- kNoRawString = false
-};
+
+bool ResourceParser::parseResource(xml::XmlPullParser* parser, ParsedResource* outResource) {
+ struct ItemTypeFormat {
+ ResourceType type;
+ uint32_t format;
+ };
+
+ using BagParseFunc = std::function<bool(ResourceParser*, xml::XmlPullParser*, ParsedResource*)>;
+
+ static const auto elToItemMap = ImmutableMap<std::u16string, ItemTypeFormat>::createPreSorted({
+ { u"bool", { ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN } },
+ { u"color", { ResourceType::kColor, android::ResTable_map::TYPE_COLOR } },
+ { u"dimen", { ResourceType::kDimen, android::ResTable_map::TYPE_FLOAT
+ | android::ResTable_map::TYPE_FRACTION
+ | android::ResTable_map::TYPE_DIMENSION } },
+ { u"drawable", { ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR } },
+ { u"fraction", { ResourceType::kFraction, android::ResTable_map::TYPE_FLOAT
+ | android::ResTable_map::TYPE_FRACTION
+ | android::ResTable_map::TYPE_DIMENSION } },
+ { u"integer", { ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER } },
+ { u"string", { ResourceType::kString, android::ResTable_map::TYPE_STRING } },
+ });
+
+ static const auto elToBagMap = ImmutableMap<std::u16string, BagParseFunc>::createPreSorted({
+ { u"add-resource", std::mem_fn(&ResourceParser::parseAddResource) },
+ { u"array", std::mem_fn(&ResourceParser::parseArray) },
+ { u"attr", std::mem_fn(&ResourceParser::parseAttr) },
+ { u"declare-styleable", std::mem_fn(&ResourceParser::parseDeclareStyleable) },
+ { u"integer-array", std::mem_fn(&ResourceParser::parseIntegerArray) },
+ { u"java-symbol", std::mem_fn(&ResourceParser::parseSymbol) },
+ { u"plurals", std::mem_fn(&ResourceParser::parsePlural) },
+ { u"public", std::mem_fn(&ResourceParser::parsePublic) },
+ { u"public-group", std::mem_fn(&ResourceParser::parsePublicGroup) },
+ { u"string-array", std::mem_fn(&ResourceParser::parseStringArray) },
+ { u"style", std::mem_fn(&ResourceParser::parseStyle) },
+ { u"symbol", std::mem_fn(&ResourceParser::parseSymbol) },
+ });
+
+ std::u16string resourceType = parser->getElementName();
+
+ // The value format accepted for this resource.
+ uint32_t resourceFormat = 0u;
+
+ if (resourceType == u"item") {
+ // Items have their type encoded in the type attribute.
+ if (Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type")) {
+ resourceType = maybeType.value().toString();
+ } else {
+ mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
+ << "<item> must have a 'type' attribute");
+ return false;
+ }
+
+ if (Maybe<StringPiece16> maybeFormat = xml::findNonEmptyAttribute(parser, u"format")) {
+ // An explicit format for this resource was specified. The resource will retain
+ // its type in its name, but the accepted value for this type is overridden.
+ resourceFormat = parseFormatType(maybeFormat.value());
+ if (!resourceFormat) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "'" << maybeFormat.value() << "' is an invalid format");
+ return false;
+ }
+ }
+ }
+
+ // Get the name of the resource. This will be checked later, because not all
+ // XML elements require a name.
+ Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name");
+
+ if (resourceType == u"id") {
+ if (!maybeName) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "<" << parser->getElementName() << "> missing 'name' attribute");
+ return false;
+ }
+
+ outResource->name.type = ResourceType::kId;
+ outResource->name.entry = maybeName.value().toString();
+ outResource->value = util::make_unique<Id>();
+ return true;
+ }
+
+ const auto itemIter = elToItemMap.find(resourceType);
+ if (itemIter != elToItemMap.end()) {
+ // This is an item, record its type and format and start parsing.
+
+ if (!maybeName) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "<" << parser->getElementName() << "> missing 'name' attribute");
+ return false;
+ }
+
+ outResource->name.type = itemIter->second.type;
+ outResource->name.entry = maybeName.value().toString();
+
+ // Only use the implicit format for this type if it wasn't overridden.
+ if (!resourceFormat) {
+ resourceFormat = itemIter->second.format;
+ }
+
+ if (!parseItem(parser, outResource, resourceFormat)) {
+ return false;
+ }
+ return true;
+ }
+
+ // This might be a bag or something.
+ const auto bagIter = elToBagMap.find(resourceType);
+ if (bagIter != elToBagMap.end()) {
+ // Ensure we have a name (unless this is a <public-group>).
+ if (resourceType != u"public-group") {
+ if (!maybeName) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "<" << parser->getElementName() << "> missing 'name' attribute");
+ return false;
+ }
+
+ outResource->name.entry = maybeName.value().toString();
+ }
+
+ // Call the associated parse method. The type will be filled in by the
+ // parse func.
+ if (!bagIter->second(this, parser, outResource)) {
+ return false;
+ }
+ return true;
+ }
+
+ // Try parsing the elementName (or type) as a resource. These shall only be
+ // resources like 'layout' or 'xml' and they can only be references.
+ const ResourceType* parsedType = parseResourceType(resourceType);
+ if (parsedType) {
+ if (!maybeName) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "<" << parser->getElementName() << "> missing 'name' attribute");
+ return false;
+ }
+
+ outResource->name.type = *parsedType;
+ outResource->name.entry = maybeName.value().toString();
+ outResource->value = parseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
+ if (!outResource->value) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid value for type '" << *parsedType << "'. Expected a reference");
+ return false;
+ }
+ return true;
+ }
+
+ mDiag->warn(DiagMessage(outResource->source)
+ << "unknown resource type '" << parser->getElementName() << "'");
+ return false;
+}
+
+bool ResourceParser::parseItem(xml::XmlPullParser* parser, ParsedResource* outResource,
+ const uint32_t format) {
+ if (format == android::ResTable_map::TYPE_STRING) {
+ return parseString(parser, outResource);
+ }
+
+ outResource->value = parseXml(parser, format, kNoRawString);
+ if (!outResource->value) {
+ mDiag->error(DiagMessage(outResource->source) << "invalid " << outResource->name.type);
+ return false;
+ }
+ return true;
+}
/**
* Reads the entire XML subtree and attempts to parse it as some Item,
@@ -431,17 +549,15 @@ std::unique_ptr<Item> ResourceParser::parseXml(xml::XmlPullParser* parser, const
return util::make_unique<RawString>(
mTable->stringPool.makeRef(rawValue, StringPool::Context{ 1, mConfig }));
}
-
return {};
}
bool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
bool formatted = true;
if (Maybe<StringPiece16> formattedAttr = xml::findAttribute(parser, u"formatted")) {
if (!ResourceUtils::tryParseBool(formattedAttr.value(), &formatted)) {
- mDiag->error(DiagMessage(source) << "invalid value for 'formatted'. Must be a boolean");
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid value for 'formatted'. Must be a boolean");
return false;
}
}
@@ -449,7 +565,7 @@ bool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* out
bool translateable = mOptions.translatable;
if (Maybe<StringPiece16> translateableAttr = xml::findAttribute(parser, u"translatable")) {
if (!ResourceUtils::tryParseBool(translateableAttr.value(), &translateable)) {
- mDiag->error(DiagMessage(source)
+ mDiag->error(DiagMessage(outResource->source)
<< "invalid value for 'translatable'. Must be a boolean");
return false;
}
@@ -457,81 +573,39 @@ bool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* out
outResource->value = parseXml(parser, android::ResTable_map::TYPE_STRING, kNoRawString);
if (!outResource->value) {
- mDiag->error(DiagMessage(source) << "not a valid string");
+ mDiag->error(DiagMessage(outResource->source) << "not a valid string");
return false;
}
- if (formatted && translateable) {
- if (String* stringValue = valueCast<String>(outResource->value.get())) {
+ if (String* stringValue = valueCast<String>(outResource->value.get())) {
+ stringValue->setTranslateable(translateable);
+
+ if (formatted && translateable) {
if (!util::verifyJavaStringFormat(*stringValue->value)) {
- mDiag->error(DiagMessage(source)
+ mDiag->error(DiagMessage(outResource->source)
<< "multiple substitutions specified in non-positional format; "
"did you mean to add the formatted=\"false\" attribute?");
return false;
}
}
- }
- return true;
-}
-
-bool ResourceParser::parseColor(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
- outResource->value = parseXml(parser, android::ResTable_map::TYPE_COLOR, kNoRawString);
- if (!outResource->value) {
- mDiag->error(DiagMessage(source) << "invalid color");
- return false;
- }
- return true;
-}
-
-bool ResourceParser::parsePrimitive(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
- uint32_t typeMask = 0;
- switch (outResource->name.type) {
- case ResourceType::kInteger:
- typeMask |= android::ResTable_map::TYPE_INTEGER;
- break;
-
- case ResourceType::kFraction:
- // fallthrough
- case ResourceType::kDimen:
- typeMask |= android::ResTable_map::TYPE_DIMENSION
- | android::ResTable_map::TYPE_FLOAT
- | android::ResTable_map::TYPE_FRACTION;
- break;
-
- case ResourceType::kBool:
- typeMask |= android::ResTable_map::TYPE_BOOLEAN;
- break;
-
- default:
- assert(false);
- break;
- }
- outResource->value = parseXml(parser, typeMask, kNoRawString);
- if (!outResource->value) {
- mDiag->error(DiagMessage(source) << "invalid " << outResource->name.type);
- return false;
+ } else if (StyledString* stringValue = valueCast<StyledString>(outResource->value.get())) {
+ stringValue->setTranslateable(translateable);
}
return true;
}
bool ResourceParser::parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
if (!maybeType) {
- mDiag->error(DiagMessage(source) << "<public> must have a 'type' attribute");
+ mDiag->error(DiagMessage(outResource->source) << "<public> must have a 'type' attribute");
return false;
}
const ResourceType* parsedType = parseResourceType(maybeType.value());
if (!parsedType) {
- mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value()
- << "' in <public>");
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid resource type '" << maybeType.value() << "' in <public>");
return false;
}
@@ -543,8 +617,8 @@ bool ResourceParser::parsePublic(xml::XmlPullParser* parser, ParsedResource* out
maybeId.value().size(), &val);
ResourceId resourceId(val.data);
if (!result || !resourceId.isValid()) {
- mDiag->error(DiagMessage(source) << "invalid resource ID '" << maybeId.value()
- << "' in <public>");
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid resource ID '" << maybeId.value() << "' in <public>");
return false;
}
outResource->id = resourceId;
@@ -560,24 +634,24 @@ bool ResourceParser::parsePublic(xml::XmlPullParser* parser, ParsedResource* out
}
bool ResourceParser::parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
if (!maybeType) {
- mDiag->error(DiagMessage(source) << "<public-group> must have a 'type' attribute");
+ mDiag->error(DiagMessage(outResource->source)
+ << "<public-group> must have a 'type' attribute");
return false;
}
const ResourceType* parsedType = parseResourceType(maybeType.value());
if (!parsedType) {
- mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value()
- << "' in <public-group>");
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid resource type '" << maybeType.value() << "' in <public-group>");
return false;
}
Maybe<StringPiece16> maybeId = xml::findNonEmptyAttribute(parser, u"first-id");
if (!maybeId) {
- mDiag->error(DiagMessage(source) << "<public-group> must have a 'first-id' attribute");
+ mDiag->error(DiagMessage(outResource->source)
+ << "<public-group> must have a 'first-id' attribute");
return false;
}
@@ -586,8 +660,8 @@ bool ResourceParser::parsePublicGroup(xml::XmlPullParser* parser, ParsedResource
maybeId.value().size(), &val);
ResourceId nextId(val.data);
if (!result || !nextId.isValid()) {
- mDiag->error(DiagMessage(source) << "invalid resource ID '" << maybeId.value()
- << "' in <public-group>");
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid resource ID '" << maybeId.value() << "' in <public-group>");
return false;
}
@@ -646,18 +720,17 @@ bool ResourceParser::parsePublicGroup(xml::XmlPullParser* parser, ParsedResource
}
bool ResourceParser::parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
if (!maybeType) {
- mDiag->error(DiagMessage(source) << "<" << parser->getElementName() << "> must have a "
- "'type' attribute");
+ mDiag->error(DiagMessage(outResource->source)
+ << "<" << parser->getElementName() << "> must have a 'type' attribute");
return false;
}
const ResourceType* parsedType = parseResourceType(maybeType.value());
if (!parsedType) {
- mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value()
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid resource type '" << maybeType.value()
<< "' in <" << parser->getElementName() << ">");
return false;
}
@@ -682,40 +755,15 @@ bool ResourceParser::parseAddResource(xml::XmlPullParser* parser, ParsedResource
return false;
}
-static uint32_t parseFormatType(const StringPiece16& piece) {
- if (piece == u"reference") return android::ResTable_map::TYPE_REFERENCE;
- else if (piece == u"string") return android::ResTable_map::TYPE_STRING;
- else if (piece == u"integer") return android::ResTable_map::TYPE_INTEGER;
- else if (piece == u"boolean") return android::ResTable_map::TYPE_BOOLEAN;
- else if (piece == u"color") return android::ResTable_map::TYPE_COLOR;
- else if (piece == u"float") return android::ResTable_map::TYPE_FLOAT;
- else if (piece == u"dimension") return android::ResTable_map::TYPE_DIMENSION;
- else if (piece == u"fraction") return android::ResTable_map::TYPE_FRACTION;
- else if (piece == u"enum") return android::ResTable_map::TYPE_ENUM;
- else if (piece == u"flags") return android::ResTable_map::TYPE_FLAGS;
- return 0;
-}
-
-static uint32_t parseFormatAttribute(const StringPiece16& str) {
- uint32_t mask = 0;
- for (StringPiece16 part : util::tokenize(str, u'|')) {
- StringPiece16 trimmedPart = util::trimWhitespace(part);
- uint32_t type = parseFormatType(trimmedPart);
- if (type == 0) {
- return 0;
- }
- mask |= type;
- }
- return mask;
-}
bool ResourceParser::parseAttr(xml::XmlPullParser* parser, ParsedResource* outResource) {
- outResource->source = mSource.withLine(parser->getLineNumber());
return parseAttrImpl(parser, outResource, false);
}
bool ResourceParser::parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* outResource,
bool weak) {
+ outResource->name.type = ResourceType::kAttr;
+
uint32_t typeMask = 0;
Maybe<StringPiece16> maybeFormat = xml::findAttribute(parser, u"format");
@@ -949,7 +997,8 @@ bool ResourceParser::parseStyleItem(xml::XmlPullParser* parser, Style* style) {
}
bool ResourceParser::parseStyle(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
+ outResource->name.type = ResourceType::kStyle;
+
std::unique_ptr<Style> style = util::make_unique<Style>();
Maybe<StringPiece16> maybeParent = xml::findAttribute(parser, u"parent");
@@ -959,7 +1008,7 @@ bool ResourceParser::parseStyle(xml::XmlPullParser* parser, ParsedResource* outR
std::string errStr;
style->parent = ResourceUtils::parseStyleParentReference(maybeParent.value(), &errStr);
if (!style->parent) {
- mDiag->error(DiagMessage(source) << errStr);
+ mDiag->error(DiagMessage(outResource->source) << errStr);
return false;
}
@@ -1007,9 +1056,22 @@ bool ResourceParser::parseStyle(xml::XmlPullParser* parser, ParsedResource* outR
return true;
}
-bool ResourceParser::parseArray(xml::XmlPullParser* parser, ParsedResource* outResource,
- uint32_t typeMask) {
- const Source source = mSource.withLine(parser->getLineNumber());
+bool ResourceParser::parseArray(xml::XmlPullParser* parser, ParsedResource* outResource) {
+ return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_ANY);
+}
+
+bool ResourceParser::parseIntegerArray(xml::XmlPullParser* parser, ParsedResource* outResource) {
+ return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_INTEGER);
+}
+
+bool ResourceParser::parseStringArray(xml::XmlPullParser* parser, ParsedResource* outResource) {
+ return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_STRING);
+}
+
+bool ResourceParser::parseArrayImpl(xml::XmlPullParser* parser, ParsedResource* outResource,
+ const uint32_t typeMask) {
+ outResource->name.type = ResourceType::kArray;
+
std::unique_ptr<Array> array = util::make_unique<Array>();
bool error = false;
@@ -1049,7 +1111,8 @@ bool ResourceParser::parseArray(xml::XmlPullParser* parser, ParsedResource* outR
}
bool ResourceParser::parsePlural(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
+ outResource->name.type = ResourceType::kPlurals;
+
std::unique_ptr<Plural> plural = util::make_unique<Plural>();
bool error = false;
@@ -1123,12 +1186,13 @@ bool ResourceParser::parsePlural(xml::XmlPullParser* parser, ParsedResource* out
}
bool ResourceParser::parseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
- std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+ outResource->name.type = ResourceType::kStyleable;
// Declare-styleable is kPrivate by default, because it technically only exists in R.java.
outResource->symbolState = SymbolState::kPublic;
+ std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+
std::u16string comment;
bool error = false;
const size_t depth = parser->getDepth();
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 04db5778a456..9ad749e27dbc 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -34,11 +34,11 @@ struct ParsedResource;
struct ResourceParserOptions {
/**
- * Optional product name by which to filter resources.
+ * 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.
*/
- Maybe<std::u16string> product;
+ std::vector<std::u16string> products;
/**
* Whether the default setting for this parser is to allow translation.
@@ -78,9 +78,11 @@ private:
const bool allowRawValue);
bool parseResources(xml::XmlPullParser* parser);
+ bool parseResource(xml::XmlPullParser* parser, ParsedResource* outResource);
+
+ bool parseItem(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t format);
bool parseString(xml::XmlPullParser* parser, ParsedResource* outResource);
- bool parseColor(xml::XmlPullParser* parser, ParsedResource* outResource);
- bool parsePrimitive(xml::XmlPullParser* parser, ParsedResource* outResource);
+
bool parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource);
bool parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource);
bool parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource);
@@ -93,9 +95,15 @@ private:
bool parseStyle(xml::XmlPullParser* parser, ParsedResource* outResource);
bool parseStyleItem(xml::XmlPullParser* parser, Style* style);
bool parseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* outResource);
- bool parseArray(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t typeMask);
+ bool parseArray(xml::XmlPullParser* parser, ParsedResource* outResource);
+ bool parseIntegerArray(xml::XmlPullParser* parser, ParsedResource* outResource);
+ bool parseStringArray(xml::XmlPullParser* parser, ParsedResource* outResource);
+ 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 84f67c6be005..8d10ba14924b 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -48,11 +48,11 @@ struct ResourceParserTest : public ::testing::Test {
}
::testing::AssertionResult testParse(const StringPiece& str,
- Maybe<std::u16string> product = {}) {
+ std::initializer_list<std::u16string> products = {}) {
std::stringstream input(kXmlPreamble);
input << "<resources>\n" << str << "\n</resources>" << std::endl;
ResourceParserOptions parserOptions;
- parserOptions.product = product;
+ parserOptions.products = products;
ResourceParser parser(mContext->getDiagnostics(), &mTable, Source{ "test" }, {},
parserOptions);
xml::XmlPullParser xmlParser(input);
@@ -215,7 +215,7 @@ TEST_F(ResourceParserTest, ParseFlagAttr) {
ASSERT_TRUE(testParse(input));
Attribute* flagAttr = test::getValue<Attribute>(&mTable, u"@attr/foo");
- ASSERT_NE(flagAttr, nullptr);
+ ASSERT_NE(nullptr, flagAttr);
EXPECT_EQ(flagAttr->typeMask, android::ResTable_map::TYPE_FLAGS);
ASSERT_EQ(flagAttr->symbols.size(), 3u);
@@ -233,7 +233,7 @@ TEST_F(ResourceParserTest, ParseFlagAttr) {
std::unique_ptr<BinaryPrimitive> flagValue = ResourceUtils::tryParseFlagSymbol(flagAttr,
u"baz|bat");
- ASSERT_NE(flagValue, nullptr);
+ ASSERT_NE(nullptr, flagValue);
EXPECT_EQ(flagValue->value.data, 1u | 2u);
}
@@ -255,7 +255,7 @@ TEST_F(ResourceParserTest, ParseStyle) {
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
EXPECT_EQ(test::parseNameOrDie(u"@style/fu"), style->parent.value().name.value());
@@ -276,7 +276,7 @@ TEST_F(ResourceParserTest, ParseStyleWithShorthandParent) {
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
EXPECT_EQ(test::parseNameOrDie(u"@com.app:style/Theme"), style->parent.value().name.value());
@@ -288,7 +288,7 @@ TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) {
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
EXPECT_EQ(test::parseNameOrDie(u"@android:style/Theme"), style->parent.value().name.value());
@@ -302,7 +302,7 @@ TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) {
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
ASSERT_EQ(1u, style->entries.size());
EXPECT_EQ(test::parseNameOrDie(u"@android:attr/bar"), style->entries[0].key.name.value());
}
@@ -312,7 +312,7 @@ TEST_F(ResourceParserTest, ParseStyleWithInferredParent) {
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
EXPECT_EQ(style->parent.value().name.value(), test::parseNameOrDie(u"@style/foo"));
@@ -324,11 +324,21 @@ TEST_F(ResourceParserTest, ParseStyleWithInferredParentOverridenByEmptyParentAtt
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
AAPT_EXPECT_FALSE(style->parent);
EXPECT_FALSE(style->parentInferred);
}
+TEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) {
+ std::string input = R"EOF(<style name="foo" parent="*android:style/bar" />)EOF";
+ ASSERT_TRUE(testParse(input));
+
+ Style* style = test::getValue<Style>(&mTable, u"@style/foo");
+ ASSERT_NE(nullptr, style);
+ AAPT_ASSERT_TRUE(style->parent);
+ EXPECT_TRUE(style->parent.value().privateReference);
+}
+
TEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
std::string input = "<string name=\"foo\">@+id/bar</string>";
ASSERT_TRUE(testParse(input));
@@ -504,11 +514,15 @@ TEST_F(ResourceParserTest, ParsePublicIdAsDefinition) {
}
TEST_F(ResourceParserTest, FilterProductsThatDontMatch) {
- std::string input = "<string name=\"foo\" product=\"phone\">hi</string>\n"
- "<string name=\"foo\" product=\"no-sdcard\">ho</string>\n"
- "<string name=\"bar\" product=\"\">wee</string>\n"
- "<string name=\"baz\">woo</string>\n";
- ASSERT_TRUE(testParse(input, std::u16string(u"no-sdcard")));
+ std::string input = R"EOF(
+ <string name="foo" product="phone">hi</string>
+ <string name="foo" product="no-sdcard">ho</string>
+ <string name="bar" product="">wee</string>
+ <string name="baz">woo</string>
+ <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);
@@ -516,11 +530,25 @@ TEST_F(ResourceParserTest, FilterProductsThatDontMatch) {
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);
}
TEST_F(ResourceParserTest, FailWhenProductFilterStripsOutAllVersionsOfResource) {
std::string input = "<string name=\"foo\" product=\"tablet\">hello</string>\n";
- ASSERT_FALSE(testParse(input, std::u16string(u"phone")));
+ ASSERT_FALSE(testParse(input, { std::u16string(u"phone") }));
}
TEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
@@ -575,4 +603,14 @@ TEST_F(ResourceParserTest, AddResourcesElementShouldAddEntryWithUndefinedSymbol)
EXPECT_EQ(SymbolState::kUndefined, entry->symbolStatus.state);
}
+TEST_F(ResourceParserTest, ParseItemElementWithFormat) {
+ std::string input = R"EOF(<item name="foo" type="integer" format="float">0.3</item>)EOF";
+ ASSERT_TRUE(testParse(input));
+
+ BinaryPrimitive* val = test::getValue<BinaryPrimitive>(&mTable, u"@integer/foo");
+ ASSERT_NE(nullptr, val);
+
+ EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType);
+}
+
} // namespace aapt
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 36c3e702574e..1dc123e45949 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -176,10 +176,10 @@ bool isAttributeReference(const StringPiece16& str) {
/*
* Style parent's are a bit different. We accept the following formats:
*
- * @[package:]style/<entry>
- * ?[package:]style/<entry>
- * <package>:[style/]<entry>
- * [package:style/]<entry>
+ * @[[*]package:]style/<entry>
+ * ?[[*]package:]style/<entry>
+ * <[*]package>:[style/]<entry>
+ * [[*]package:style/]<entry>
*/
Maybe<Reference> parseStyleParentReference(const StringPiece16& str, std::string* outError) {
if (str.empty()) {
@@ -195,10 +195,11 @@ Maybe<Reference> parseStyleParentReference(const StringPiece16& str, std::string
if (name.data()[0] == u'@' || name.data()[0] == u'?') {
hasLeadingIdentifiers = true;
name = name.substr(1, name.size() - 1);
- if (name.data()[0] == u'*') {
- privateRef = true;
- name = name.substr(1, name.size() - 1);
- }
+ }
+
+ if (name.data()[0] == u'*') {
+ privateRef = true;
+ name = name.substr(1, name.size() - 1);
}
ResourceNameRef ref;
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 4bbfc32b9b37..88efa6779021 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -157,6 +157,11 @@ TEST(ResourceUtilsTest, ParseStyleParentReference) {
ref = ResourceUtils::parseStyleParentReference(u"foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kStyleFooName);
+
+ ref = ResourceUtils::parseStyleParentReference(u"*android:style/foo", &errStr);
+ AAPT_ASSERT_TRUE(ref);
+ EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
+ EXPECT_TRUE(ref.value().privateReference);
}
} // namespace aapt
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 04c375f5f974..b93e6d889ad0 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -36,10 +36,6 @@ void BaseItem<Derived>::accept(RawValueVisitor* visitor) {
visitor->visit(static_cast<Derived*>(this));
}
-bool Value::isWeak() const {
- return false;
-}
-
RawString::RawString(const StringPool::Ref& ref) : value(ref) {
}
@@ -101,10 +97,6 @@ void Reference::print(std::ostream* out) const {
}
}
-bool Id::isWeak() const {
- return true;
-}
-
bool Id::flatten(android::Res_value* out) const {
out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
out->data = util::hostToDevice32(0);
@@ -119,7 +111,15 @@ void Id::print(std::ostream* out) const {
*out << "(id)";
}
-String::String(const StringPool::Ref& ref) : value(ref) {
+String::String(const StringPool::Ref& ref) : value(ref), mTranslateable(true) {
+}
+
+void String::setTranslateable(bool val) {
+ mTranslateable = val;
+}
+
+bool String::isTranslateable() const {
+ return mTranslateable;
}
bool String::flatten(android::Res_value* outValue) const {
@@ -144,7 +144,15 @@ void String::print(std::ostream* out) const {
*out << "(string) \"" << *value << "\"";
}
-StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
+StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref), mTranslateable(true) {
+}
+
+void StyledString::setTranslateable(bool val) {
+ mTranslateable = val;
+}
+
+bool StyledString::isTranslateable() const {
+ return mTranslateable;
}
bool StyledString::flatten(android::Res_value* outValue) const {
@@ -238,13 +246,10 @@ void BinaryPrimitive::print(std::ostream* out) const {
}
Attribute::Attribute(bool w, uint32_t t) :
- weak(w), typeMask(t),
+ typeMask(t),
minInt(std::numeric_limits<int32_t>::min()),
maxInt(std::numeric_limits<int32_t>::max()) {
-}
-
-bool Attribute::isWeak() const {
- return weak;
+ mWeak = w;
}
Attribute* Attribute::clone(StringPool* /*newPool*/) const {
@@ -359,7 +364,7 @@ void Attribute::print(std::ostream* out) const {
<< "]";
}
- if (weak) {
+ if (isWeak()) {
*out << " [weak]";
}
}
@@ -457,6 +462,9 @@ Style* Style::clone(StringPool* newPool) const {
void Style::print(std::ostream* out) const {
*out << "(style) ";
if (parent && parent.value().name) {
+ if (parent.value().privateReference) {
+ *out << "*";
+ }
*out << parent.value().name.value();
}
*out << " ["
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index a03828206c91..8e317dbcd1b1 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -43,9 +43,15 @@ struct Value {
/**
* Whether this value is weak and can be overridden without
- * warning or error. Default for base class is false.
+ * warning or error. Default is false.
*/
- virtual bool isWeak() const;
+ bool isWeak() const {
+ return mWeak;
+ }
+
+ void setWeak(bool val) {
+ mWeak = val;
+ }
/**
* Returns the source where this value was defined.
@@ -95,6 +101,7 @@ struct Value {
protected:
Source mSource;
std::u16string mComment;
+ bool mWeak = false;
};
/**
@@ -159,7 +166,7 @@ struct Reference : public BaseItem<Reference> {
* An ID resource. Has no real value, just a place holder.
*/
struct Id : public BaseItem<Id> {
- bool isWeak() const override;
+ Id() { mWeak = true; }
bool flatten(android::Res_value* out) const override;
Id* clone(StringPool* newPool) const override;
void print(std::ostream* out) const override;
@@ -185,9 +192,17 @@ struct String : public BaseItem<String> {
String(const StringPool::Ref& ref);
+ // Whether the string is marked as translateable. This does not persist when flattened.
+ // It is only used during compilation phase.
+ void setTranslateable(bool val);
+ bool isTranslateable() const;
+
bool flatten(android::Res_value* outValue) const override;
String* clone(StringPool* newPool) const override;
void print(std::ostream* out) const override;
+
+private:
+ bool mTranslateable;
};
struct StyledString : public BaseItem<StyledString> {
@@ -195,9 +210,17 @@ struct StyledString : public BaseItem<StyledString> {
StyledString(const StringPool::StyleRef& ref);
+ // Whether the string is marked as translateable. This does not persist when flattened.
+ // It is only used during compilation phase.
+ void setTranslateable(bool val);
+ bool isTranslateable() const;
+
bool flatten(android::Res_value* outValue) const override;
StyledString* clone(StringPool* newPool) const override;
void print(std::ostream* out) const override;
+
+private:
+ bool mTranslateable;
};
struct FileReference : public BaseItem<FileReference> {
@@ -232,7 +255,6 @@ struct Attribute : public BaseValue<Attribute> {
uint32_t value;
};
- bool weak;
uint32_t typeMask;
int32_t minInt;
int32_t maxInt;
@@ -240,7 +262,6 @@ struct Attribute : public BaseValue<Attribute> {
Attribute(bool w, uint32_t t = 0u);
- bool isWeak() const override;
Attribute* clone(StringPool* newPool) const override;
void printMask(std::ostream* out) const;
void print(std::ostream* out) const override;
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index 90e35d52788c..b3b0f65e54da 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -21,6 +21,7 @@
#include "ResourceTable.h"
#include "compile/IdAssigner.h"
#include "compile/Png.h"
+#include "compile/PseudolocaleGenerator.h"
#include "compile/XmlIdCollector.h"
#include "flatten/Archive.h"
#include "flatten/FileExportWriter.h"
@@ -104,7 +105,8 @@ static Maybe<ResourcePathData> extractResourcePathData(const std::string& path,
struct CompileOptions {
std::string outputPath;
Maybe<std::string> resDir;
- Maybe<std::u16string> product;
+ std::vector<std::u16string> products;
+ bool pseudolocalize = false;
bool verbose = false;
};
@@ -189,7 +191,7 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options,
xml::XmlPullParser xmlParser(fin);
ResourceParserOptions parserOptions;
- parserOptions.product = options.product;
+ parserOptions.products = options.products;
// If the filename includes donottranslate, then the default translatable is false.
parserOptions.translatable = pathData.name.find(u"donottranslate") == std::string::npos;
@@ -203,6 +205,16 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options,
fin.close();
}
+ if (options.pseudolocalize) {
+ // Generate pseudo-localized strings (en-XA and ar-XB).
+ // These are created as weak symbols, and are only generated from default configuration
+ // strings and plurals.
+ PseudolocaleGenerator pseudolocaleGenerator;
+ if (!pseudolocaleGenerator.consume(context, &table)) {
+ return false;
+ }
+ }
+
// Ensure we have the compilation package at least.
table.createPackage(context->getCompilationPackage());
@@ -418,18 +430,23 @@ public:
int compile(const std::vector<StringPiece>& args) {
CompileOptions options;
- Maybe<std::string> product;
+ Maybe<std::string> productList;
Flags flags = Flags()
.requiredFlag("-o", "Output path", &options.outputPath)
- .optionalFlag("--product", "Product type to compile", &product)
+ .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("-v", "Enables verbose logging", &options.verbose);
if (!flags.parse("aapt2 compile", args, &std::cerr)) {
return 1;
}
- if (product) {
- options.product = util::utf8ToUtf16(product.value());
+ if (productList) {
+ for (StringPiece part : util::tokenize<char>(productList.value(), ',')) {
+ options.products.push_back(util::utf8ToUtf16(part));
+ }
}
CompileContext context;
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
new file mode 100644
index 000000000000..2963d135cbca
--- /dev/null
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "ValueVisitor.h"
+#include "compile/PseudolocaleGenerator.h"
+#include "compile/Pseudolocalizer.h"
+#include "util/Comparators.h"
+
+namespace aapt {
+
+std::unique_ptr<StyledString> pseudolocalizeStyledString(StyledString* string,
+ Pseudolocalizer::Method method,
+ StringPool* pool) {
+ Pseudolocalizer localizer(method);
+
+ const StringPiece16 originalText = *string->value->str;
+
+ StyleString localized;
+
+ // Copy the spans. We will update their offsets when we localize.
+ localized.spans.reserve(string->value->spans.size());
+ for (const StringPool::Span& span : string->value->spans) {
+ localized.spans.push_back(Span{ *span.name, span.firstChar, span.lastChar });
+ }
+
+ // The ranges are all represented with a single value. This is the start of one range and
+ // end of another.
+ struct Range {
+ size_t start;
+
+ // Once the new string is localized, these are the pointers to the spans to adjust.
+ // Since this struct represents the start of one range and end of another, we have
+ // the two pointers respectively.
+ uint32_t* updateStart;
+ uint32_t* updateEnd;
+ };
+
+ auto cmp = [](const Range& r, size_t index) -> bool {
+ return r.start < index;
+ };
+
+ // Construct the ranges. The ranges are represented like so: [0, 2, 5, 7]
+ // The ranges are the spaces in between. In this example, with a total string length of 9,
+ // the vector represents: (0,1], (2,4], (5,6], (7,9]
+ //
+ std::vector<Range> ranges;
+ ranges.push_back(Range{ 0 });
+ ranges.push_back(Range{ originalText.size() - 1 });
+ for (size_t i = 0; i < string->value->spans.size(); i++) {
+ const StringPool::Span& span = string->value->spans[i];
+
+ // Insert or update the Range marker for the start of this span.
+ auto iter = std::lower_bound(ranges.begin(), ranges.end(), span.firstChar, cmp);
+ if (iter != ranges.end() && iter->start == span.firstChar) {
+ iter->updateStart = &localized.spans[i].firstChar;
+ } else {
+ ranges.insert(iter,
+ Range{ span.firstChar, &localized.spans[i].firstChar, nullptr });
+ }
+
+ // Insert or update the Range marker for the end of this span.
+ iter = std::lower_bound(ranges.begin(), ranges.end(), span.lastChar, cmp);
+ if (iter != ranges.end() && iter->start == span.lastChar) {
+ iter->updateEnd = &localized.spans[i].lastChar;
+ } else {
+ ranges.insert(iter,
+ Range{ span.lastChar, nullptr, &localized.spans[i].lastChar });
+ }
+ }
+
+ localized.str += localizer.start();
+
+ // Iterate over the ranges and localize each section.
+ for (size_t i = 0; i < ranges.size(); i++) {
+ const size_t start = ranges[i].start;
+ size_t len = originalText.size() - start;
+ if (i + 1 < ranges.size()) {
+ len = ranges[i + 1].start - start;
+ }
+
+ if (ranges[i].updateStart) {
+ *ranges[i].updateStart = localized.str.size();
+ }
+
+ if (ranges[i].updateEnd) {
+ *ranges[i].updateEnd = localized.str.size();
+ }
+
+ localized.str += localizer.text(originalText.substr(start, len));
+ }
+
+ localized.str += localizer.end();
+
+ std::unique_ptr<StyledString> localizedString = util::make_unique<StyledString>(
+ pool->makeRef(localized));
+ localizedString->setSource(string->getSource());
+ return localizedString;
+}
+
+namespace {
+
+struct Visitor : public RawValueVisitor {
+ StringPool* mPool;
+ Pseudolocalizer::Method mMethod;
+ Pseudolocalizer mLocalizer;
+
+ // Either value or item will be populated upon visiting the value.
+ std::unique_ptr<Value> mValue;
+ std::unique_ptr<Item> mItem;
+
+ Visitor(StringPool* pool, Pseudolocalizer::Method method) :
+ mPool(pool), mMethod(method), mLocalizer(method) {
+ }
+
+ void visit(Array* array) override {
+ std::unique_ptr<Array> localized = util::make_unique<Array>();
+ localized->items.resize(array->items.size());
+ for (size_t i = 0; i < array->items.size(); i++) {
+ Visitor subVisitor(mPool, mMethod);
+ array->items[i]->accept(&subVisitor);
+ if (subVisitor.mItem) {
+ localized->items[i] = std::move(subVisitor.mItem);
+ } else {
+ localized->items[i] = std::unique_ptr<Item>(array->items[i]->clone(mPool));
+ }
+ }
+ localized->setSource(array->getSource());
+ localized->setWeak(true);
+ mValue = std::move(localized);
+ }
+
+ void visit(Plural* plural) override {
+ std::unique_ptr<Plural> localized = util::make_unique<Plural>();
+ for (size_t i = 0; i < plural->values.size(); i++) {
+ Visitor subVisitor(mPool, mMethod);
+ if (plural->values[i]) {
+ plural->values[i]->accept(&subVisitor);
+ if (subVisitor.mValue) {
+ localized->values[i] = std::move(subVisitor.mItem);
+ } else {
+ localized->values[i] = std::unique_ptr<Item>(plural->values[i]->clone(mPool));
+ }
+ }
+ }
+ localized->setSource(plural->getSource());
+ localized->setWeak(true);
+ mValue = std::move(localized);
+ }
+
+ void visit(String* string) override {
+ if (!string->isTranslateable()) {
+ return;
+ }
+
+ std::u16string result = mLocalizer.start() + mLocalizer.text(*string->value) +
+ mLocalizer.end();
+ std::unique_ptr<String> localized = util::make_unique<String>(mPool->makeRef(result));
+ localized->setSource(string->getSource());
+ localized->setWeak(true);
+ mItem = std::move(localized);
+ }
+
+ void visit(StyledString* string) override {
+ if (!string->isTranslateable()) {
+ return;
+ }
+
+ mItem = pseudolocalizeStyledString(string, mMethod, mPool);
+ mItem->setWeak(true);
+ }
+};
+
+ConfigDescription modifyConfigForPseudoLocale(const ConfigDescription& base,
+ Pseudolocalizer::Method m) {
+ ConfigDescription modified = base;
+ switch (m) {
+ case Pseudolocalizer::Method::kAccent:
+ modified.language[0] = 'e';
+ modified.language[1] = 'n';
+ modified.country[0] = 'X';
+ modified.country[1] = 'A';
+ break;
+
+ case Pseudolocalizer::Method::kBidi:
+ modified.language[0] = 'a';
+ modified.language[1] = 'r';
+ modified.country[0] = 'X';
+ modified.country[1] = 'B';
+ break;
+ default:
+ break;
+ }
+ return modified;
+}
+
+void pseudolocalizeIfNeeded(std::vector<ResourceConfigValue>* configValues,
+ Pseudolocalizer::Method method, StringPool* pool, Value* value) {
+ Visitor visitor(pool, method);
+ value->accept(&visitor);
+
+ std::unique_ptr<Value> localizedValue;
+ if (visitor.mValue) {
+ localizedValue = std::move(visitor.mValue);
+ } else if (visitor.mItem) {
+ 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) });
+ }
+ }
+}
+
+} // namespace
+
+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);
+ }
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.h b/tools/aapt2/compile/PseudolocaleGenerator.h
new file mode 100644
index 000000000000..4fbc51607595
--- /dev/null
+++ b/tools/aapt2/compile/PseudolocaleGenerator.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_COMPILE_PSEUDOLOCALEGENERATOR_H
+#define AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H
+
+#include "StringPool.h"
+#include "compile/Pseudolocalizer.h"
+#include "process/IResourceTableConsumer.h"
+
+namespace aapt {
+
+std::unique_ptr<StyledString> pseudolocalizeStyledString(StyledString* string,
+ Pseudolocalizer::Method method,
+ StringPool* pool);
+
+struct PseudolocaleGenerator : public IResourceTableConsumer {
+ bool consume(IAaptContext* context, ResourceTable* table) override;
+};
+
+} // namespace aapt
+
+#endif /* AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H */
diff --git a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
new file mode 100644
index 000000000000..4cb6ea2db565
--- /dev/null
+++ b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "compile/PseudolocaleGenerator.h"
+#include "test/Builders.h"
+#include "test/Common.h"
+#include "test/Context.h"
+#include "util/Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
+ StringPool pool;
+ StyleString originalStyle;
+ originalStyle.str = u"Hello world!";
+ originalStyle.spans = { Span{ u"b", 2, 3 }, Span{ u"b", 6, 7 }, Span{ u"i", 1, 10 } };
+
+ std::unique_ptr<StyledString> newString = pseudolocalizeStyledString(
+ util::make_unique<StyledString>(pool.makeRef(originalStyle)).get(),
+ Pseudolocalizer::Method::kNone, &pool);
+
+ EXPECT_EQ(originalStyle.str, *newString->value->str);
+ ASSERT_EQ(originalStyle.spans.size(), newString->value->spans.size());
+
+ EXPECT_EQ(2u, newString->value->spans[0].firstChar);
+ EXPECT_EQ(3u, newString->value->spans[0].lastChar);
+ EXPECT_EQ(std::u16string(u"b"), *newString->value->spans[0].name);
+
+ EXPECT_EQ(6u, newString->value->spans[1].firstChar);
+ EXPECT_EQ(7u, newString->value->spans[1].lastChar);
+ EXPECT_EQ(std::u16string(u"b"), *newString->value->spans[1].name);
+
+ EXPECT_EQ(1u, newString->value->spans[2].firstChar);
+ EXPECT_EQ(10u, newString->value->spans[2].lastChar);
+ EXPECT_EQ(std::u16string(u"i"), *newString->value->spans[2].name);
+
+ originalStyle.spans.push_back(Span{ u"em", 0, 11u });
+
+ newString = pseudolocalizeStyledString(
+ util::make_unique<StyledString>(pool.makeRef(originalStyle)).get(),
+ Pseudolocalizer::Method::kAccent, &pool);
+
+ EXPECT_EQ(std::u16string(u"[Ĥéļļö ŵöŕļð¡ one two]"), *newString->value->str);
+ ASSERT_EQ(originalStyle.spans.size(), newString->value->spans.size());
+
+ EXPECT_EQ(3u, newString->value->spans[0].firstChar);
+ EXPECT_EQ(4u, newString->value->spans[0].lastChar);
+
+ EXPECT_EQ(7u, newString->value->spans[1].firstChar);
+ EXPECT_EQ(8u, newString->value->spans[1].lastChar);
+
+ EXPECT_EQ(2u, newString->value->spans[2].firstChar);
+ EXPECT_EQ(11u, newString->value->spans[2].lastChar);
+
+ EXPECT_EQ(1u, newString->value->spans[3].firstChar);
+ EXPECT_EQ(12u, newString->value->spans[3].lastChar);
+}
+
+TEST(PseudolocaleGeneratorTest, PseudolocalizeOnlyDefaultConfigs) {
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+ .addString(u"@android:string/one", u"one")
+ .addString(u"@android:string/two", ResourceId{}, test::parseConfigOrDie("en"), u"two")
+ .addString(u"@android:string/three", u"three")
+ .addString(u"@android:string/three", ResourceId{}, test::parseConfigOrDie("en-rXA"),
+ u"three")
+ .addString(u"@android:string/four", u"four")
+ .build();
+
+ String* val = test::getValue<String>(table.get(), u"@android:string/four");
+ val->setTranslateable(false);
+
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+ PseudolocaleGenerator generator;
+ ASSERT_TRUE(generator.consume(context.get(), table.get()));
+
+ // Normal pseudolocalization should take place.
+ ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/one",
+ test::parseConfigOrDie("en-rXA")));
+ ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/one",
+ test::parseConfigOrDie("ar-rXB")));
+
+ // No default config for android:string/two, so no pseudlocales should exist.
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/two",
+ test::parseConfigOrDie("en-rXA")));
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/two",
+ test::parseConfigOrDie("ar-rXB")));
+
+
+ // Check that we didn't override manual pseudolocalization.
+ val = test::getValueForConfig<String>(table.get(), u"@android:string/three",
+ test::parseConfigOrDie("en-rXA"));
+ ASSERT_NE(nullptr, val);
+ EXPECT_EQ(std::u16string(u"three"), *val->value);
+
+ ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/three",
+ test::parseConfigOrDie("ar-rXB")));
+
+ // Check that four's translateable marker was honored.
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/four",
+ test::parseConfigOrDie("en-rXA")));
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/four",
+ test::parseConfigOrDie("ar-rXB")));
+
+}
+
+} // namespace aapt
+
diff --git a/tools/aapt2/compile/Pseudolocalizer.cpp b/tools/aapt2/compile/Pseudolocalizer.cpp
new file mode 100644
index 000000000000..eae52d778744
--- /dev/null
+++ b/tools/aapt2/compile/Pseudolocalizer.cpp
@@ -0,0 +1,394 @@
+/*
+ * 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 "compile/Pseudolocalizer.h"
+#include "util/Util.h"
+
+namespace aapt {
+
+// String basis to generate expansion
+static const std::u16string k_expansion_string = u"one two three "
+ "four five six seven eight nine ten eleven twelve thirteen "
+ "fourteen fiveteen sixteen seventeen nineteen twenty";
+
+// Special unicode characters to override directionality of the words
+static const std::u16string k_rlm = u"\u200f";
+static const std::u16string k_rlo = u"\u202e";
+static const std::u16string k_pdf = u"\u202c";
+
+// Placeholder marks
+static const std::u16string k_placeholder_open = u"\u00bb";
+static const std::u16string k_placeholder_close = u"\u00ab";
+
+static const char16_t k_arg_start = u'{';
+static const char16_t k_arg_end = u'}';
+
+class PseudoMethodNone : public PseudoMethodImpl {
+public:
+ std::u16string text(const StringPiece16& text) override { return text.toString(); }
+ std::u16string placeholder(const StringPiece16& text) override { return text.toString(); }
+};
+
+class PseudoMethodBidi : public PseudoMethodImpl {
+public:
+ std::u16string text(const StringPiece16& text) override;
+ std::u16string placeholder(const StringPiece16& text) override;
+};
+
+class PseudoMethodAccent : public PseudoMethodImpl {
+public:
+ PseudoMethodAccent() : mDepth(0), mWordCount(0), mLength(0) {}
+ std::u16string start() override;
+ std::u16string end() override;
+ std::u16string text(const StringPiece16& text) override;
+ std::u16string placeholder(const StringPiece16& text) override;
+private:
+ size_t mDepth;
+ size_t mWordCount;
+ size_t mLength;
+};
+
+Pseudolocalizer::Pseudolocalizer(Method method) : mLastDepth(0) {
+ setMethod(method);
+}
+
+void Pseudolocalizer::setMethod(Method method) {
+ switch (method) {
+ case Method::kNone:
+ mImpl = util::make_unique<PseudoMethodNone>();
+ break;
+ case Method::kAccent:
+ mImpl = util::make_unique<PseudoMethodAccent>();
+ break;
+ case Method::kBidi:
+ mImpl = util::make_unique<PseudoMethodBidi>();
+ break;
+ }
+}
+
+std::u16string Pseudolocalizer::text(const StringPiece16& text) {
+ std::u16string out;
+ size_t depth = mLastDepth;
+ size_t lastpos, pos;
+ const size_t length = text.size();
+ const char16_t* str = text.data();
+ bool escaped = false;
+ for (lastpos = pos = 0; pos < length; pos++) {
+ char16_t c = str[pos];
+ if (escaped) {
+ escaped = false;
+ continue;
+ }
+ if (c == '\'') {
+ escaped = true;
+ continue;
+ }
+
+ if (c == k_arg_start) {
+ depth++;
+ } else if (c == k_arg_end && depth) {
+ depth--;
+ }
+
+ if (mLastDepth != depth || pos == length - 1) {
+ bool pseudo = ((mLastDepth % 2) == 0);
+ size_t nextpos = pos;
+ if (!pseudo || depth == mLastDepth) {
+ nextpos++;
+ }
+ size_t size = nextpos - lastpos;
+ if (size) {
+ std::u16string chunk = text.substr(lastpos, size).toString();
+ if (pseudo) {
+ chunk = mImpl->text(chunk);
+ } else if (str[lastpos] == k_arg_start && str[nextpos - 1] == k_arg_end) {
+ chunk = mImpl->placeholder(chunk);
+ }
+ out.append(chunk);
+ }
+ if (pseudo && depth < mLastDepth) { // End of message
+ out.append(mImpl->end());
+ } else if (!pseudo && depth > mLastDepth) { // Start of message
+ out.append(mImpl->start());
+ }
+ lastpos = nextpos;
+ mLastDepth = depth;
+ }
+ }
+ return out;
+}
+
+static const char16_t* pseudolocalizeChar(const char16_t c) {
+ switch (c) {
+ case 'a': return u"\u00e5";
+ case 'b': return u"\u0253";
+ case 'c': return u"\u00e7";
+ case 'd': return u"\u00f0";
+ case 'e': return u"\u00e9";
+ case 'f': return u"\u0192";
+ case 'g': return u"\u011d";
+ case 'h': return u"\u0125";
+ case 'i': return u"\u00ee";
+ case 'j': return u"\u0135";
+ case 'k': return u"\u0137";
+ case 'l': return u"\u013c";
+ case 'm': return u"\u1e3f";
+ case 'n': return u"\u00f1";
+ case 'o': return u"\u00f6";
+ case 'p': return u"\u00fe";
+ case 'q': return u"\u0051";
+ case 'r': return u"\u0155";
+ case 's': return u"\u0161";
+ case 't': return u"\u0163";
+ case 'u': return u"\u00fb";
+ case 'v': return u"\u0056";
+ case 'w': return u"\u0175";
+ case 'x': return u"\u0445";
+ case 'y': return u"\u00fd";
+ case 'z': return u"\u017e";
+ case 'A': return u"\u00c5";
+ case 'B': return u"\u03b2";
+ case 'C': return u"\u00c7";
+ case 'D': return u"\u00d0";
+ case 'E': return u"\u00c9";
+ case 'G': return u"\u011c";
+ case 'H': return u"\u0124";
+ case 'I': return u"\u00ce";
+ case 'J': return u"\u0134";
+ case 'K': return u"\u0136";
+ case 'L': return u"\u013b";
+ case 'M': return u"\u1e3e";
+ case 'N': return u"\u00d1";
+ case 'O': return u"\u00d6";
+ case 'P': return u"\u00de";
+ case 'Q': return u"\u0071";
+ case 'R': return u"\u0154";
+ case 'S': return u"\u0160";
+ case 'T': return u"\u0162";
+ case 'U': return u"\u00db";
+ case 'V': return u"\u03bd";
+ case 'W': return u"\u0174";
+ case 'X': return u"\u00d7";
+ case 'Y': return u"\u00dd";
+ case 'Z': return u"\u017d";
+ case '!': return u"\u00a1";
+ case '?': return u"\u00bf";
+ case '$': return u"\u20ac";
+ default: return NULL;
+ }
+}
+
+static bool isPossibleNormalPlaceholderEnd(const char16_t c) {
+ switch (c) {
+ case 's': return true;
+ case 'S': return true;
+ case 'c': return true;
+ case 'C': return true;
+ case 'd': return true;
+ case 'o': return true;
+ case 'x': return true;
+ case 'X': return true;
+ case 'f': return true;
+ case 'e': return true;
+ case 'E': return true;
+ case 'g': return true;
+ case 'G': return true;
+ case 'a': return true;
+ case 'A': return true;
+ case 'b': return true;
+ case 'B': return true;
+ case 'h': return true;
+ case 'H': return true;
+ case '%': return true;
+ case 'n': return true;
+ default: return false;
+ }
+}
+
+static std::u16string pseudoGenerateExpansion(const unsigned int length) {
+ std::u16string result = k_expansion_string;
+ const char16_t* s = result.data();
+ if (result.size() < length) {
+ result += u" ";
+ result += pseudoGenerateExpansion(length - result.size());
+ } else {
+ int ext = 0;
+ // Should contain only whole words, so looking for a space
+ for (unsigned int i = length + 1; i < result.size(); ++i) {
+ ++ext;
+ if (s[i] == ' ') {
+ break;
+ }
+ }
+ result = result.substr(0, length + ext);
+ }
+ return result;
+}
+
+std::u16string PseudoMethodAccent::start() {
+ std::u16string result;
+ if (mDepth == 0) {
+ result = u"[";
+ }
+ mWordCount = mLength = 0;
+ mDepth++;
+ return result;
+}
+
+std::u16string PseudoMethodAccent::end() {
+ std::u16string result;
+ if (mLength) {
+ result += u" ";
+ result += pseudoGenerateExpansion(mWordCount > 3 ? mLength : mLength / 2);
+ }
+ mWordCount = mLength = 0;
+ mDepth--;
+ if (mDepth == 0) {
+ result += u"]";
+ }
+ return result;
+}
+
+/**
+ * Converts characters so they look like they've been localized.
+ *
+ * Note: This leaves placeholder syntax untouched.
+ */
+std::u16string PseudoMethodAccent::text(const StringPiece16& source)
+{
+ const char16_t* s = source.data();
+ std::u16string result;
+ const size_t I = source.size();
+ bool lastspace = true;
+ for (size_t i = 0; i < I; i++) {
+ char16_t c = s[i];
+ if (c == '%') {
+ // Placeholder syntax, no need to pseudolocalize
+ std::u16string chunk;
+ bool end = false;
+ chunk.append(&c, 1);
+ while (!end && i < I) {
+ ++i;
+ c = s[i];
+ chunk.append(&c, 1);
+ if (isPossibleNormalPlaceholderEnd(c)) {
+ end = true;
+ } else if (c == 't') {
+ ++i;
+ c = s[i];
+ chunk.append(&c, 1);
+ end = true;
+ }
+ }
+ // Treat chunk as a placeholder unless it ends with %.
+ result += ((c == '%') ? chunk : placeholder(chunk));
+ } else if (c == '<' || c == '&') {
+ // html syntax, no need to pseudolocalize
+ bool tag_closed = false;
+ while (!tag_closed && i < I) {
+ if (c == '&') {
+ std::u16string escapeText;
+ escapeText.append(&c, 1);
+ bool end = false;
+ size_t htmlCodePos = i;
+ while (!end && htmlCodePos < I) {
+ ++htmlCodePos;
+ c = s[htmlCodePos];
+ escapeText.append(&c, 1);
+ // Valid html code
+ if (c == ';') {
+ end = true;
+ i = htmlCodePos;
+ }
+ // Wrong html code
+ else if (!((c == '#' ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9')))) {
+ end = true;
+ }
+ }
+ result += escapeText;
+ if (escapeText != u"&lt;") {
+ tag_closed = true;
+ }
+ continue;
+ }
+ if (c == '>') {
+ tag_closed = true;
+ result.append(&c, 1);
+ continue;
+ }
+ result.append(&c, 1);
+ i++;
+ c = s[i];
+ }
+ } else {
+ // This is a pure text that should be pseudolocalized
+ const char16_t* p = pseudolocalizeChar(c);
+ if (p != nullptr) {
+ result += p;
+ } else {
+ bool space = util::isspace16(c);
+ if (lastspace && !space) {
+ mWordCount++;
+ }
+ lastspace = space;
+ result.append(&c, 1);
+ }
+ // Count only pseudolocalizable chars and delimiters
+ mLength++;
+ }
+ }
+ return result;
+}
+
+std::u16string PseudoMethodAccent::placeholder(const StringPiece16& source) {
+ // Surround a placeholder with brackets
+ return k_placeholder_open + source.toString() + k_placeholder_close;
+}
+
+std::u16string PseudoMethodBidi::text(const StringPiece16& source) {
+ const char16_t* s = source.data();
+ std::u16string result;
+ bool lastspace = true;
+ bool space = true;
+ for (size_t i = 0; i < source.size(); i++) {
+ char16_t c = s[i];
+ space = util::isspace16(c);
+ if (lastspace && !space) {
+ // Word start
+ result += k_rlm + k_rlo;
+ } else if (!lastspace && space) {
+ // Word end
+ result += k_pdf + k_rlm;
+ }
+ lastspace = space;
+ result.append(&c, 1);
+ }
+ if (!lastspace) {
+ // End of last word
+ result += k_pdf + k_rlm;
+ }
+ return result;
+}
+
+std::u16string PseudoMethodBidi::placeholder(const StringPiece16& source) {
+ // Surround a placeholder with directionality change sequence
+ return k_rlm + k_rlo + source.toString() + k_pdf + k_rlm;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/Pseudolocalizer.h b/tools/aapt2/compile/Pseudolocalizer.h
new file mode 100644
index 000000000000..8818c1725617
--- /dev/null
+++ b/tools/aapt2/compile/Pseudolocalizer.h
@@ -0,0 +1,58 @@
+/*
+ * 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_COMPILE_PSEUDOLOCALIZE_H
+#define AAPT_COMPILE_PSEUDOLOCALIZE_H
+
+#include "ResourceValues.h"
+#include "StringPool.h"
+#include "util/StringPiece.h"
+
+#include <android-base/macros.h>
+#include <memory>
+
+namespace aapt {
+
+class PseudoMethodImpl {
+public:
+ virtual ~PseudoMethodImpl() {}
+ virtual std::u16string start() { return {}; }
+ virtual std::u16string end() { return {}; }
+ virtual std::u16string text(const StringPiece16& text) = 0;
+ virtual std::u16string placeholder(const StringPiece16& text) = 0;
+};
+
+class Pseudolocalizer {
+public:
+ enum class Method {
+ kNone,
+ kAccent,
+ kBidi,
+ };
+
+ Pseudolocalizer(Method method);
+ void setMethod(Method method);
+ std::u16string start() { return mImpl->start(); }
+ std::u16string end() { return mImpl->end(); }
+ std::u16string text(const StringPiece16& text);
+private:
+ std::unique_ptr<PseudoMethodImpl> mImpl;
+ size_t mLastDepth;
+};
+
+} // namespace aapt
+
+#endif /* AAPT_COMPILE_PSEUDOLOCALIZE_H */
diff --git a/tools/aapt2/compile/Pseudolocalizer_test.cpp b/tools/aapt2/compile/Pseudolocalizer_test.cpp
new file mode 100644
index 000000000000..b0bc2c10fbe0
--- /dev/null
+++ b/tools/aapt2/compile/Pseudolocalizer_test.cpp
@@ -0,0 +1,227 @@
+/*
+ * 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 "compile/Pseudolocalizer.h"
+#include "util/Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+// In this context, 'Axis' represents a particular field in the configuration,
+// such as language or density.
+
+static ::testing::AssertionResult simpleHelper(const char* input, const char* expected,
+ Pseudolocalizer::Method method) {
+ Pseudolocalizer pseudo(method);
+ std::string result = util::utf16ToUtf8(
+ pseudo.start() + pseudo.text(util::utf8ToUtf16(input)) + pseudo.end());
+ if (StringPiece(expected) != result) {
+ return ::testing::AssertionFailure() << expected << " != " << result;
+ }
+ return ::testing::AssertionSuccess();
+}
+
+static ::testing::AssertionResult compoundHelper(const char* in1, const char* in2, const char *in3,
+ const char* expected,
+ Pseudolocalizer::Method method) {
+ Pseudolocalizer pseudo(method);
+ std::string result = util::utf16ToUtf8(pseudo.start() +
+ pseudo.text(util::utf8ToUtf16(in1)) +
+ pseudo.text(util::utf8ToUtf16(in2)) +
+ pseudo.text(util::utf8ToUtf16(in3)) +
+ pseudo.end());
+ if (StringPiece(expected) != result) {
+ return ::testing::AssertionFailure() << expected << " != " << result;
+ }
+ return ::testing::AssertionSuccess();
+}
+
+TEST(PseudolocalizerTest, NoPseudolocalization) {
+ EXPECT_TRUE(simpleHelper("", "", Pseudolocalizer::Method::kNone));
+ EXPECT_TRUE(simpleHelper("Hello, world", "Hello, world", Pseudolocalizer::Method::kNone));
+
+ EXPECT_TRUE(compoundHelper("Hello,", " world", "",
+ "Hello, world", Pseudolocalizer::Method::kNone));
+}
+
+TEST(PseudolocalizerTest, PlaintextAccent) {
+ EXPECT_TRUE(simpleHelper("", "[]", Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(simpleHelper("Hello, world",
+ "[Ĥéļļö, ŵöŕļð one two]", Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(simpleHelper("Hello, %1d",
+ "[Ĥéļļö, »%1d« one two]", Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(simpleHelper("Battery %1d%%",
+ "[βåţţéŕý »%1d«%% one two]", Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(compoundHelper("", "", "", "[]", Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(compoundHelper("Hello,", " world", "",
+ "[Ĥéļļö, ŵöŕļð one two]", Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, PlaintextBidi) {
+ EXPECT_TRUE(simpleHelper("", "", Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(simpleHelper("word",
+ "\xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f",
+ Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(simpleHelper(" word ",
+ " \xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f ",
+ Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(simpleHelper(" word ",
+ " \xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f ",
+ Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(simpleHelper("hello\n world\n",
+ "\xe2\x80\x8f\xE2\x80\xaehello\xE2\x80\xac\xe2\x80\x8f\n" \
+ " \xe2\x80\x8f\xE2\x80\xaeworld\xE2\x80\xac\xe2\x80\x8f\n",
+ Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(compoundHelper("hello", "\n ", " world\n",
+ "\xe2\x80\x8f\xE2\x80\xaehello\xE2\x80\xac\xe2\x80\x8f\n" \
+ " \xe2\x80\x8f\xE2\x80\xaeworld\xE2\x80\xac\xe2\x80\x8f\n",
+ Pseudolocalizer::Method::kBidi));
+}
+
+TEST(PseudolocalizerTest, SimpleICU) {
+ // Single-fragment messages
+ EXPECT_TRUE(simpleHelper("{placeholder}", "[»{placeholder}«]",
+ Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(simpleHelper("{USER} is offline",
+ "[»{USER}« îš öƒƒļîñé one two]", Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(simpleHelper("Copy from {path1} to {path2}",
+ "[Çöþý ƒŕöḿ »{path1}« ţö »{path2}« one two three]",
+ Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(simpleHelper("Today is {1,date} {1,time}",
+ "[Ţöðåý îš »{1,date}« »{1,time}« one two]",
+ Pseudolocalizer::Method::kAccent));
+
+ // Multi-fragment messages
+ EXPECT_TRUE(compoundHelper("{USER}", " ", "is offline",
+ "[»{USER}« îš öƒƒļîñé one two]",
+ Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(compoundHelper("Copy from ", "{path1}", " to {path2}",
+ "[Çöþý ƒŕöḿ »{path1}« ţö »{path2}« one two three]",
+ Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, ICUBidi) {
+ // Single-fragment messages
+ EXPECT_TRUE(simpleHelper("{placeholder}",
+ "\xe2\x80\x8f\xE2\x80\xae{placeholder}\xE2\x80\xac\xe2\x80\x8f",
+ Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(simpleHelper(
+ "{COUNT, plural, one {one} other {other}}",
+ "{COUNT, plural, " \
+ "one {\xe2\x80\x8f\xE2\x80\xaeone\xE2\x80\xac\xe2\x80\x8f} " \
+ "other {\xe2\x80\x8f\xE2\x80\xaeother\xE2\x80\xac\xe2\x80\x8f}}",
+ Pseudolocalizer::Method::kBidi));
+}
+
+TEST(PseudolocalizerTest, Escaping) {
+ // Single-fragment messages
+ EXPECT_TRUE(simpleHelper("'{USER'} is offline",
+ "['{ÛŠÉŔ'} îš öƒƒļîñé one two three]",
+ Pseudolocalizer::Method::kAccent));
+
+ // Multi-fragment messages
+ EXPECT_TRUE(compoundHelper("'{USER}", " ", "''is offline",
+ "['{ÛŠÉŔ} ''îš öƒƒļîñé one two three]",
+ Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, PluralsAndSelects) {
+ EXPECT_TRUE(simpleHelper(
+ "{COUNT, plural, one {Delete a file} other {Delete {COUNT} files}}",
+ "[{COUNT, plural, one {Ðéļéţé å ƒîļé one two} " \
+ "other {Ðéļéţé »{COUNT}« ƒîļéš one two}}]",
+ Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(simpleHelper(
+ "Distance is {COUNT, plural, one {# mile} other {# miles}}",
+ "[Ðîšţåñçé îš {COUNT, plural, one {# ḿîļé one two} " \
+ "other {# ḿîļéš one two}}]",
+ Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(simpleHelper(
+ "{1, select, female {{1} added you} " \
+ "male {{1} added you} other {{1} added you}}",
+ "[{1, select, female {»{1}« åððéð ýöû one two} " \
+ "male {»{1}« åððéð ýöû one two} other {»{1}« åððéð ýöû one two}}]",
+ Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(compoundHelper(
+ "{COUNT, plural, one {Delete a file} " \
+ "other {Delete ", "{COUNT}", " files}}",
+ "[{COUNT, plural, one {Ðéļéţé å ƒîļé one two} " \
+ "other {Ðéļéţé »{COUNT}« ƒîļéš one two}}]",
+ Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, NestedICU) {
+ EXPECT_TRUE(simpleHelper(
+ "{person, select, " \
+ "female {" \
+ "{num_circles, plural," \
+ "=0{{person} didn't add you to any of her circles.}" \
+ "=1{{person} added you to one of her circles.}" \
+ "other{{person} added you to her # circles.}}}" \
+ "male {" \
+ "{num_circles, plural," \
+ "=0{{person} didn't add you to any of his circles.}" \
+ "=1{{person} added you to one of his circles.}" \
+ "other{{person} added you to his # circles.}}}" \
+ "other {" \
+ "{num_circles, plural," \
+ "=0{{person} didn't add you to any of their circles.}" \
+ "=1{{person} added you to one of their circles.}" \
+ "other{{person} added you to their # circles.}}}}",
+ "[{person, select, " \
+ "female {" \
+ "{num_circles, plural," \
+ "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ĥéŕ çîŕçļéš." \
+ " one two three four five}" \
+ "=1{»{person}« åððéð ýöû ţö öñé öƒ ĥéŕ çîŕçļéš." \
+ " one two three four}" \
+ "other{»{person}« åððéð ýöû ţö ĥéŕ # çîŕçļéš." \
+ " one two three four}}}" \
+ "male {" \
+ "{num_circles, plural," \
+ "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ĥîš çîŕçļéš." \
+ " one two three four five}" \
+ "=1{»{person}« åððéð ýöû ţö öñé öƒ ĥîš çîŕçļéš." \
+ " one two three four}" \
+ "other{»{person}« åððéð ýöû ţö ĥîš # çîŕçļéš." \
+ " one two three four}}}" \
+ "other {{num_circles, plural," \
+ "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ţĥéîŕ çîŕçļéš." \
+ " one two three four five}" \
+ "=1{»{person}« åððéð ýöû ţö öñé öƒ ţĥéîŕ çîŕçļéš." \
+ " one two three four}" \
+ "other{»{person}« åððéð ýöû ţö ţĥéîŕ # çîŕçļéš." \
+ " one two three four}}}}]",
+ Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, RedefineMethod) {
+ Pseudolocalizer pseudo(Pseudolocalizer::Method::kAccent);
+ std::u16string result = pseudo.text(u"Hello, ");
+ pseudo.setMethod(Pseudolocalizer::Method::kNone);
+ result += pseudo.text(u"world!");
+ ASSERT_EQ(StringPiece("Ĥéļļö, world!"), util::utf16ToUtf8(result));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/XmlIdCollector_test.cpp b/tools/aapt2/compile/XmlIdCollector_test.cpp
index 45b7af240abe..a37ea86c317f 100644
--- a/tools/aapt2/compile/XmlIdCollector_test.cpp
+++ b/tools/aapt2/compile/XmlIdCollector_test.cpp
@@ -37,13 +37,13 @@ TEST(XmlIdCollectorTest, CollectsIds) {
XmlIdCollector collector;
ASSERT_TRUE(collector.consume(context.get(), doc.get()));
- EXPECT_EQ(1u, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
+ EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
SourcedResourceName{ test::parseNameOrDie(u"@id/foo"), 3u }));
- EXPECT_EQ(1u, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
+ EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
SourcedResourceName{ test::parseNameOrDie(u"@id/bar"), 3u }));
- EXPECT_EQ(1u, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
+ EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
SourcedResourceName{ test::parseNameOrDie(u"@id/car"), 6u }));
}
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index a2f53e15df69..26d7c2ca055c 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -113,8 +113,7 @@ struct MapFlattenVisitor : public RawValueVisitor {
bool mUseExtendedChunks;
size_t mEntryCount = 0;
- Maybe<uint32_t> mParentIdent;
- Maybe<ResourceNameRef> mParentName;
+ const Reference* mParent = nullptr;
MapFlattenVisitor(SymbolWriter* symbols, FlatEntry* entry, BigBuffer* buffer,
StringPool* sourcePool, StringPool* commentPool,
@@ -227,13 +226,8 @@ struct MapFlattenVisitor : public RawValueVisitor {
void visit(Style* style) override {
if (style->parent) {
- bool privateRef = style->parent.value().privateReference && mUseExtendedChunks;
- if (!style->parent.value().id || privateRef) {
- assert(style->parent.value().name && "reference must have a name");
- mParentName = style->parent.value().name;
- } else {
- mParentIdent = style->parent.value().id.value().id;
- }
+ // Parents are treated a bit differently, so record the existence and move on.
+ mParent = &style->parent.value();
}
// Sort the style.
@@ -427,11 +421,16 @@ private:
mOptions.useExtendedChunks);
entry->value->accept(&visitor);
outEntry->count = util::hostToDevice32(visitor.mEntryCount);
- if (visitor.mParentName) {
- mSymbols->addSymbol(visitor.mParentName.value(),
- beforeEntry + offsetof(ResTable_entry_ext, parent));
- } else if (visitor.mParentIdent) {
- outEntry->parent.ident = util::hostToDevice32(visitor.mParentIdent.value());
+ 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);
+ }
}
}
return true;
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index c0968545ad81..c610bb0f2ff2 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -227,14 +227,14 @@ bool collectProguardRules(const Source& source, xml::XmlResource* res, KeepSet*
bool writeKeepSet(std::ostream* out, const KeepSet& keepSet) {
for (const auto& entry : keepSet.mKeepSet) {
for (const Source& source : entry.second) {
- *out << "// Referenced at " << source << "\n";
+ *out << "# Referenced at " << source << "\n";
}
*out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
}
for (const auto& entry : keepSet.mKeepMethodSet) {
for (const Source& source : entry.second) {
- *out << "// Referenced at " << source << "\n";
+ *out << "# Referenced at " << source << "\n";
}
*out << "-keepclassmembers class * { *** " << entry.first << "(...); }\n" << std::endl;
}
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index f8e3d031fb67..93a11b9334a8 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -68,6 +68,12 @@ public:
return addValue(name, id, util::make_unique<String>(mTable->stringPool.makeRef(str)));
}
+ ResourceTableBuilder& addString(const StringPiece16& name, const ResourceId id,
+ const ConfigDescription& config, const StringPiece16& str) {
+ return addValue(name, id, config,
+ util::make_unique<String>(mTable->stringPool.makeRef(str)));
+ }
+
ResourceTableBuilder& addFileReference(const StringPiece16& name, const StringPiece16& path) {
return addFileReference(name, {}, path);
}
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index 21e476fc9c29..6b7a63cf7bf2 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -585,6 +585,13 @@ bool BinaryResourceParser::parseType(const ResourceTablePackage* package,
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,
diff --git a/tools/aapt2/util/ImmutableMap.h b/tools/aapt2/util/ImmutableMap.h
new file mode 100644
index 000000000000..b1f9e9d2fb57
--- /dev/null
+++ b/tools/aapt2/util/ImmutableMap.h
@@ -0,0 +1,84 @@
+/*
+ * 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_UTIL_IMMUTABLEMAP_H
+#define AAPT_UTIL_IMMUTABLEMAP_H
+
+#include "util/TypeTraits.h"
+
+#include <utility>
+#include <vector>
+
+namespace aapt {
+
+template <typename TKey, typename TValue>
+class ImmutableMap {
+ static_assert(is_comparable<TKey, TKey>::value, "key is not comparable");
+
+private:
+ std::vector<std::pair<TKey, TValue>> mData;
+
+ explicit ImmutableMap(std::vector<std::pair<TKey, TValue>> data) : mData(std::move(data)) {
+ }
+
+public:
+ using const_iterator = typename decltype(mData)::const_iterator;
+
+ ImmutableMap(ImmutableMap&&) = default;
+ ImmutableMap& operator=(ImmutableMap&&) = default;
+
+ ImmutableMap(const ImmutableMap&) = delete;
+ ImmutableMap& operator=(const ImmutableMap&) = delete;
+
+ static ImmutableMap<TKey, TValue> createPreSorted(
+ std::initializer_list<std::pair<TKey, TValue>> list) {
+ return ImmutableMap(std::vector<std::pair<TKey, TValue>>(list.begin(), list.end()));
+ }
+
+ static ImmutableMap<TKey, TValue> createAndSort(
+ std::initializer_list<std::pair<TKey, TValue>> list) {
+ std::vector<std::pair<TKey, TValue>> data(list.begin(), list.end());
+ std::sort(data.begin(), data.end());
+ return ImmutableMap(std::move(data));
+ }
+
+ template <typename TKey2,
+ typename = typename std::enable_if<is_comparable<TKey, TKey2>::value>::type>
+ const_iterator find(const TKey2& key) const {
+ auto cmp = [](const std::pair<TKey, TValue>& candidate, const TKey2& target) -> bool {
+ return candidate.first < target;
+ };
+
+ const_iterator endIter = end();
+ auto iter = std::lower_bound(mData.begin(), endIter, key, cmp);
+ if (iter == endIter || iter->first == key) {
+ return iter;
+ }
+ return endIter;
+ }
+
+ const_iterator begin() const {
+ return mData.begin();
+ }
+
+ const_iterator end() const {
+ return mData.end();
+ }
+};
+
+} // namespace aapt
+
+#endif /* AAPT_UTIL_IMMUTABLEMAP_H */
diff --git a/tools/aapt2/util/TypeTraits.h b/tools/aapt2/util/TypeTraits.h
new file mode 100644
index 000000000000..76c13d615e41
--- /dev/null
+++ b/tools/aapt2/util/TypeTraits.h
@@ -0,0 +1,51 @@
+/*
+ * 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_UTIL_TYPETRAITS_H
+#define AAPT_UTIL_TYPETRAITS_H
+
+#include <type_traits>
+
+namespace aapt {
+
+#define DEFINE_HAS_BINARY_OP_TRAIT(name, op) \
+ template <typename T, typename U> \
+ struct name { \
+ template <typename V, typename W> \
+ static constexpr decltype(std::declval<V>() op std::declval<W>(), bool()) test(int) { \
+ return true; \
+ } \
+ template <typename V, typename W> \
+ static constexpr bool test(...) { \
+ return false; \
+ } \
+ static constexpr bool value = test<T, U>(int()); \
+}
+
+DEFINE_HAS_BINARY_OP_TRAIT(has_eq_op, ==);
+DEFINE_HAS_BINARY_OP_TRAIT(has_lt_op, <);
+
+/**
+ * Type trait that checks if two types can be equated (==) and compared (<).
+ */
+template <typename T, typename U>
+struct is_comparable {
+ static constexpr bool value = has_eq_op<T, U>::value && has_lt_op<T, U>::value;
+};
+
+} // namespace aapt
+
+#endif /* AAPT_UTIL_TYPETRAITS_H */
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 40437fac0092..01ee18b1649c 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -76,7 +76,7 @@ public class IWindowManagerImpl implements IWindowManager {
@Override
public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
- Rect arg11, Configuration arg12, boolean arg13) throws RemoteException {
+ Rect arg11, Configuration arg12, boolean arg13, boolean arg14) throws RemoteException {
// TODO Auto-generated method stub
}
@@ -543,6 +543,11 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
- public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+ public void registerDockedStackListener(IDockedStackListener listener) throws RemoteException {
+ }
+
+ @Override
+ public void setResizeDimLayer(boolean visible, int targetStackId, float alpha)
+ throws RemoteException {
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 683c4aabf6d9..c8e3d03169e8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -183,7 +183,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
*/
private static LayoutLog sCurrentLog = sDefaultLog;
- private static final int LAST_SUPPORTED_FEATURE = Features.CHOREOGRAPHER;
+ private static final int LAST_SUPPORTED_FEATURE = Features.THEME_PREVIEW_NAVIGATION_BAR;
@Override
public int getApiLevel() {
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 a2fad13e7b2c..27751eb7d267 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
@@ -34,7 +34,6 @@ import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
@@ -98,7 +97,7 @@ public class BridgePackageManager extends PackageManager {
}
@Override
- public int getPackageUid(String packageName, int userHandle) throws NameNotFoundException {
+ public int getPackageUidAsUser(String packageName, int userHandle) throws NameNotFoundException {
return 0;
}
@@ -165,7 +164,7 @@ public class BridgePackageManager extends PackageManager {
}
@Override
- public List<PackageInfo> getInstalledPackages(int flags, int userId) {
+ public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
return null;
}
@@ -329,7 +328,7 @@ public class BridgePackageManager extends PackageManager {
}
@Override
- public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) {
+ public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
return null;
}
@@ -522,7 +521,7 @@ public class BridgePackageManager extends PackageManager {
@Override
public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
int flags, String installerPackageName, Uri verificationURI,
- ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+ ContainerEncryptionParams encryptionParams) {
}
@Override
@@ -544,7 +543,7 @@ public class BridgePackageManager extends PackageManager {
@Override
public void installPackageWithVerification(Uri packageURI, PackageInstallObserver observer,
int flags, String installerPackageName, Uri verificationURI,
- ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+ ContainerEncryptionParams encryptionParams) {
}
@Override
@@ -579,12 +578,12 @@ public class BridgePackageManager extends PackageManager {
}
@Override
- public int getIntentVerificationStatus(String packageName, int userId) {
+ public int getIntentVerificationStatusAsUser(String packageName, int userId) {
return 0;
}
@Override
- public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+ public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) {
return false;
}
@@ -599,12 +598,12 @@ public class BridgePackageManager extends PackageManager {
}
@Override
- public String getDefaultBrowserPackageName(int userId) {
+ public String getDefaultBrowserPackageNameAsUser(int userId) {
return null;
}
@Override
- public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+ public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
return false;
}
@@ -644,7 +643,7 @@ public class BridgePackageManager extends PackageManager {
}
@Override
- public void getPackageSizeInfo(String packageName, int userHandle,
+ public void getPackageSizeInfoAsUser(String packageName, int userHandle,
IPackageStatsObserver observer) {
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index 9c89bfe2a28f..dfbc69bee59c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -19,9 +19,6 @@ package com.android.layoutlib.bridge.bars;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.resources.Density;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.LinearLayout;
@@ -41,29 +38,18 @@ public class NavigationBar extends CustomBar {
private static final int WIDTH_DEFAULT = 36;
private static final int WIDTH_SW360 = 40;
private static final int WIDTH_SW600 = 48;
- private static final String LAYOUT_XML = "/bars/navigation_bar.xml";
+ protected static final String LAYOUT_XML = "/bars/navigation_bar.xml";
private static final String LAYOUT_600DP_XML = "/bars/navigation_bar600dp.xml";
-
- /**
- * Constructor to be used when creating the {@link NavigationBar} as a regular control.
- * This is currently used by the theme editor.
- */
- @SuppressWarnings("unused")
- public NavigationBar(Context context, AttributeSet attrs) {
- this((BridgeContext) context,
- Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
- LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
- ((BridgeContext) context).getConfiguration().getLayoutDirection() ==
- View.LAYOUT_DIRECTION_RTL,
- (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
- 0);
+ public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
+ boolean rtlEnabled, int simulatedPlatformVersion) {
+ this(context, density, orientation, isRtl, rtlEnabled, simulatedPlatformVersion,
+ getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML);
}
- public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
- boolean rtlEnabled, int simulatedPlatformVersion) {
- super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
- "navigation_bar.xml", simulatedPlatformVersion);
+ protected NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
+ boolean rtlEnabled, int simulatedPlatformVersion, String layoutPath) {
+ super(context, orientation, layoutPath, "navigation_bar.xml", simulatedPlatformVersion);
int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
setBackgroundColor(color == 0 ? 0xFF000000 : color);
@@ -117,7 +103,7 @@ public class NavigationBar extends CustomBar {
view.setLayoutParams(layoutParams);
}
- private static int getSidePadding(float sw) {
+ protected int getSidePadding(float sw) {
if (sw >= 400) {
return PADDING_WIDTH_SW400;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java
new file mode 100644
index 000000000000..043528016c2d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java
@@ -0,0 +1,58 @@
+/*
+ * 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.layoutlib.bridge.bars;
+
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.resources.Density;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * Navigation Bar for the Theme Editor preview.
+ *
+ * For small bars, it is identical to {@link NavigationBar}.
+ * But wide bars from {@link NavigationBar} are too wide for the Theme Editor preview.
+ * To solve that problem, {@link ThemePreviewNavigationBar} use the layout for small bars,
+ * and have no padding on the sides. That way, they have a similar look as the true ones,
+ * and they fit in the Theme Editor preview.
+ */
+public class ThemePreviewNavigationBar extends NavigationBar {
+ private static final int PADDING_WIDTH_SW600 = 0;
+
+ @SuppressWarnings("unused")
+ public ThemePreviewNavigationBar(Context context, AttributeSet attrs) {
+ super((BridgeContext) context,
+ Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
+ LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
+ ((BridgeContext) context).getConfiguration().getLayoutDirection() ==
+ View.LAYOUT_DIRECTION_RTL,
+ (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
+ 0, LAYOUT_XML);
+ }
+
+ @Override
+ protected int getSidePadding(float sw) {
+ if (sw >= 600) {
+ return PADDING_WIDTH_SW600;
+ }
+ return super.getSidePadding(sw);
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 5534cad16872..76c679ce6b9f 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -170,18 +170,14 @@ public class WifiScanner {
public int maxScansToCache;
/**
* if maxPeriodInMs is non zero or different than period, then this bucket is
- * an exponential backoff bucket and the scan period will grow exponentially
- * as per formula: actual_period(N) = period ^ (N/(step_count+1))
- * to a maximum period of max_period.
+ * a truncated binary exponential backoff bucket and the scan period will grow
+ * exponentially as per formula: actual_period(N) = period * (2 ^ (N/stepCount))
+ * to maxPeriodInMs
*/
public int maxPeriodInMs;
/**
- * for exponential back off bucket: multiplier: new_period=old_period*exponent
- */
- public int exponent;
- /**
- * for exponential back off bucket, number of scans performed at a given
- * period and until the exponent is applied
+ * for truncated binary exponential back off bucket, number of scans to perform
+ * for a given period
*/
public int stepCount;
@@ -198,7 +194,6 @@ public class WifiScanner {
dest.writeInt(numBssidsPerScan);
dest.writeInt(maxScansToCache);
dest.writeInt(maxPeriodInMs);
- dest.writeInt(exponent);
dest.writeInt(stepCount);
if (channels != null) {
@@ -226,7 +221,6 @@ public class WifiScanner {
settings.numBssidsPerScan = in.readInt();
settings.maxScansToCache = in.readInt();
settings.maxPeriodInMs = in.readInt();
- settings.exponent = in.readInt();
settings.stepCount = in.readInt();
int num_channels = in.readInt();
settings.channels = new ChannelSpec[num_channels];