summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
author Xin Li <delphij@google.com> 2023-08-14 15:42:50 -0700
committer Xin Li <delphij@google.com> 2023-08-14 15:42:50 -0700
commit80bfff1f0eef6db4e061d9892450737e110bad59 (patch)
treee586dfb61c90c1aec759f551cbac857895edaf83 /java
parenta0c4477fdbbae9857ead667a5227c3d93d9d3167 (diff)
parent5e86e4846a4326b05fa747eaf7f1ba0fa89cd623 (diff)
Merge Android U (ab/10368041)
Bug: 291102124 Merged-In: If40fe5329a6f3835d1edaebdef2ff47a947a9943 Change-Id: Ide948ae0ca758570ba7dae69fdcaa6c066522a20
Diffstat (limited to 'java')
-rw-r--r--java/res/color/resolver_profile_tab_text.xml (renamed from java/res/values/bools.xml)11
-rw-r--r--java/res/drawable-h480dp/content_preview_badge_bg.xml27
-rw-r--r--java/res/drawable/bottomsheet_background.xml6
-rw-r--r--java/res/drawable/chevron_right.xml33
-rw-r--r--java/res/drawable/chooser_action_button_bg.xml5
-rw-r--r--java/res/drawable/chooser_content_preview_rounded.xml (renamed from java/res/layout/chooser_image_preview_view.xml)19
-rw-r--r--java/res/drawable/chooser_row_layer_list.xml2
-rw-r--r--java/res/drawable/content_preview_badge_bg.xml28
-rw-r--r--java/res/drawable/edit_action_background.xml (renamed from java/res/layout/chooser_action_button.xml)30
-rw-r--r--java/res/drawable/ic_drag_handle.xml3
-rw-r--r--java/res/drawable/ic_file_copy.xml2
-rw-r--r--java/res/drawable/ic_file_video.xml (renamed from java/res/layout/scrollable_image_preview_view.xml)19
-rw-r--r--java/res/drawable/resolver_outlined_button_bg.xml2
-rw-r--r--java/res/drawable/resolver_profile_tab_bg.xml4
-rw-r--r--java/res/drawable/single_file.xml25
-rw-r--r--java/res/layout-h480dp/image_preview_image_item.xml77
-rw-r--r--java/res/layout/chooser_action_row.xml31
-rw-r--r--java/res/layout/chooser_action_view.xml22
-rw-r--r--java/res/layout/chooser_az_label_row.xml4
-rw-r--r--java/res/layout/chooser_grid.xml9
-rw-r--r--java/res/layout/chooser_grid_preview_file.xml109
-rw-r--r--java/res/layout/chooser_grid_preview_files_text.xml62
-rw-r--r--java/res/layout/chooser_grid_preview_image.xml61
-rw-r--r--java/res/layout/chooser_grid_preview_text.xml130
-rw-r--r--java/res/layout/chooser_headline_row.xml77
-rw-r--r--java/res/layout/chooser_image_preview_view_internals.xml73
-rw-r--r--java/res/layout/chooser_list_per_profile.xml2
-rw-r--r--java/res/layout/chooser_row.xml1
-rw-r--r--java/res/layout/image_preview_image_item.xml41
-rw-r--r--java/res/layout/image_preview_other_item.xml (renamed from java/res/layout/scrollable_chooser_action_row.xml)21
-rw-r--r--java/res/layout/resolve_grid_item.xml24
-rw-r--r--java/res/layout/resolver_profile_tab_button.xml2
-rw-r--r--java/res/values-af/strings.xml89
-rw-r--r--java/res/values-am/strings.xml89
-rw-r--r--java/res/values-ar/strings.xml89
-rw-r--r--java/res/values-as/strings.xml89
-rw-r--r--java/res/values-az/strings.xml89
-rw-r--r--java/res/values-b+sr+Latn/strings.xml89
-rw-r--r--java/res/values-be/strings.xml89
-rw-r--r--java/res/values-bg/strings.xml89
-rw-r--r--java/res/values-bn/strings.xml89
-rw-r--r--java/res/values-bs/strings.xml89
-rw-r--r--java/res/values-ca/strings.xml89
-rw-r--r--java/res/values-cs/strings.xml89
-rw-r--r--java/res/values-da/strings.xml89
-rw-r--r--java/res/values-de/strings.xml89
-rw-r--r--java/res/values-el/strings.xml89
-rw-r--r--java/res/values-en-rAU/strings.xml89
-rw-r--r--java/res/values-en-rCA/strings.xml89
-rw-r--r--java/res/values-en-rGB/strings.xml89
-rw-r--r--java/res/values-en-rIN/strings.xml89
-rw-r--r--java/res/values-en-rXC/strings.xml89
-rw-r--r--java/res/values-es-rUS/strings.xml89
-rw-r--r--java/res/values-es/strings.xml89
-rw-r--r--java/res/values-et/strings.xml89
-rw-r--r--java/res/values-eu/strings.xml89
-rw-r--r--java/res/values-fa/strings.xml89
-rw-r--r--java/res/values-fi/strings.xml89
-rw-r--r--java/res/values-fr-rCA/strings.xml89
-rw-r--r--java/res/values-fr/strings.xml89
-rw-r--r--java/res/values-gl/strings.xml89
-rw-r--r--java/res/values-gu/strings.xml89
-rw-r--r--java/res/values-h480dp/dimens.xml7
-rw-r--r--java/res/values-h480dp/integers.xml (renamed from java/res/values-h480dp/bools.xml)9
-rw-r--r--java/res/values-hi/strings.xml89
-rw-r--r--java/res/values-hr/strings.xml89
-rw-r--r--java/res/values-hu/strings.xml89
-rw-r--r--java/res/values-hy/strings.xml89
-rw-r--r--java/res/values-in/strings.xml89
-rw-r--r--java/res/values-is/strings.xml89
-rw-r--r--java/res/values-it/strings.xml89
-rw-r--r--java/res/values-iw/strings.xml89
-rw-r--r--java/res/values-ja/strings.xml89
-rw-r--r--java/res/values-ka/strings.xml89
-rw-r--r--java/res/values-kk/strings.xml89
-rw-r--r--java/res/values-km/strings.xml89
-rw-r--r--java/res/values-kn/strings.xml89
-rw-r--r--java/res/values-ko/strings.xml89
-rw-r--r--java/res/values-ky/strings.xml89
-rw-r--r--java/res/values-land/dimens.xml23
-rw-r--r--java/res/values-lo/strings.xml89
-rw-r--r--java/res/values-lt/strings.xml89
-rw-r--r--java/res/values-lv/strings.xml89
-rw-r--r--java/res/values-mk/strings.xml89
-rw-r--r--java/res/values-ml/strings.xml89
-rw-r--r--java/res/values-mn/strings.xml89
-rw-r--r--java/res/values-mr/strings.xml89
-rw-r--r--java/res/values-ms/strings.xml89
-rw-r--r--java/res/values-my/strings.xml89
-rw-r--r--java/res/values-nb/strings.xml89
-rw-r--r--java/res/values-ne/strings.xml89
-rw-r--r--java/res/values-nl/strings.xml89
-rw-r--r--java/res/values-or/strings.xml89
-rw-r--r--java/res/values-pa/strings.xml89
-rw-r--r--java/res/values-pl/strings.xml89
-rw-r--r--java/res/values-pt-rBR/strings.xml89
-rw-r--r--java/res/values-pt-rPT/strings.xml89
-rw-r--r--java/res/values-pt/strings.xml89
-rw-r--r--java/res/values-ro/strings.xml89
-rw-r--r--java/res/values-ru/strings.xml89
-rw-r--r--java/res/values-si/strings.xml89
-rw-r--r--java/res/values-sk/strings.xml89
-rw-r--r--java/res/values-sl/strings.xml89
-rw-r--r--java/res/values-sq/strings.xml89
-rw-r--r--java/res/values-sr/strings.xml89
-rw-r--r--java/res/values-sv/strings.xml89
-rw-r--r--java/res/values-sw/strings.xml89
-rw-r--r--java/res/values-sw600dp/dimens.xml3
-rw-r--r--java/res/values-ta/strings.xml89
-rw-r--r--java/res/values-te/strings.xml89
-rw-r--r--java/res/values-th/strings.xml89
-rw-r--r--java/res/values-tl/strings.xml89
-rw-r--r--java/res/values-tr/strings.xml89
-rw-r--r--java/res/values-uk/strings.xml89
-rw-r--r--java/res/values-ur/strings.xml89
-rw-r--r--java/res/values-uz/strings.xml89
-rw-r--r--java/res/values-vi/strings.xml89
-rw-r--r--java/res/values-zh-rCN/strings.xml89
-rw-r--r--java/res/values-zh-rHK/strings.xml89
-rw-r--r--java/res/values-zh-rTW/strings.xml89
-rw-r--r--java/res/values-zu/strings.xml89
-rw-r--r--java/res/values/attrs.xml10
-rw-r--r--java/res/values/config.xml2
-rw-r--r--java/res/values/dimens.xml24
-rw-r--r--java/res/values/integers.xml21
-rw-r--r--java/res/values/strings.xml220
-rw-r--r--java/res/values/styles.xml5
-rw-r--r--java/src/com/android/intentresolver/AbstractMultiProfilePagerAdapter.java9
-rw-r--r--java/src/com/android/intentresolver/AnnotatedUserHandles.java138
-rw-r--r--java/src/com/android/intentresolver/ChooserActionFactory.java217
-rw-r--r--java/src/com/android/intentresolver/ChooserActivity.java425
-rw-r--r--java/src/com/android/intentresolver/ChooserActivityReEnabler.kt39
-rw-r--r--java/src/com/android/intentresolver/ChooserListAdapter.java178
-rw-r--r--java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java33
-rw-r--r--java/src/com/android/intentresolver/ChooserRefinementManager.java176
-rw-r--r--java/src/com/android/intentresolver/ChooserRequestParameters.java59
-rw-r--r--java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java6
-rw-r--r--java/src/com/android/intentresolver/GenericMultiProfilePagerAdapter.java24
-rw-r--r--java/src/com/android/intentresolver/ImagePreviewImageLoader.kt87
-rw-r--r--java/src/com/android/intentresolver/IntentForwarderActivity.java4
-rw-r--r--java/src/com/android/intentresolver/ItemRevealAnimationTracker.kt70
-rw-r--r--java/src/com/android/intentresolver/NoAppsAvailableEmptyStateProvider.java11
-rw-r--r--java/src/com/android/intentresolver/NoCrossProfileEmptyStateProvider.java11
-rw-r--r--java/src/com/android/intentresolver/ResolverActivity.java393
-rw-r--r--java/src/com/android/intentresolver/ResolverListAdapter.java263
-rw-r--r--java/src/com/android/intentresolver/ResolverListController.java45
-rw-r--r--java/src/com/android/intentresolver/ResolverMultiProfilePagerAdapter.java10
-rw-r--r--java/src/com/android/intentresolver/WorkProfilePausedEmptyStateProvider.java1
-rw-r--r--java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java7
-rw-r--r--java/src/com/android/intentresolver/chooser/ImmutableTargetInfo.java4
-rw-r--r--java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java27
-rw-r--r--java/src/com/android/intentresolver/chooser/TargetInfo.java45
-rw-r--r--java/src/com/android/intentresolver/contentpreview/BasePreviewViewModel.kt31
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java256
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java109
-rw-r--r--java/src/com/android/intentresolver/contentpreview/DefaultMimeTypeClassifier.kt (renamed from java/src/com/android/intentresolver/ImageLoader.kt)13
-rw-r--r--java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java208
-rw-r--r--java/src/com/android/intentresolver/contentpreview/FileInfo.kt36
-rw-r--r--java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java231
-rw-r--r--java/src/com/android/intentresolver/contentpreview/HeadlineGenerator.kt37
-rw-r--r--java/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImpl.kt77
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ImageContentPreviewUi.java179
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ImageLoader.kt48
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt156
-rw-r--r--java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java36
-rw-r--r--java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt394
-rw-r--r--java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt69
-rw-r--r--java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java102
-rw-r--r--java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java151
-rw-r--r--java/src/com/android/intentresolver/flags/Flags.kt32
-rw-r--r--java/src/com/android/intentresolver/grid/ChooserGridAdapter.java115
-rw-r--r--java/src/com/android/intentresolver/grid/DirectShareViewHolder.java87
-rw-r--r--java/src/com/android/intentresolver/icons/BaseLoadIconTask.java50
-rw-r--r--java/src/com/android/intentresolver/icons/DefaultTargetDataLoader.kt127
-rw-r--r--java/src/com/android/intentresolver/icons/LoadDirectShareIconTask.java131
-rw-r--r--java/src/com/android/intentresolver/icons/LoadIconTask.java71
-rw-r--r--java/src/com/android/intentresolver/icons/LoadLabelTask.java94
-rw-r--r--java/src/com/android/intentresolver/icons/TargetDataLoader.kt50
-rw-r--r--java/src/com/android/intentresolver/measurements/Tracer.kt155
-rw-r--r--java/src/com/android/intentresolver/model/AbstractResolverComparator.java69
-rw-r--r--java/src/com/android/intentresolver/model/AppPredictionServiceResolverComparator.java47
-rw-r--r--java/src/com/android/intentresolver/model/ResolverComparatorModel.java7
-rw-r--r--java/src/com/android/intentresolver/model/ResolverRankerServiceResolverComparator.java283
-rw-r--r--java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt298
-rw-r--r--java/src/com/android/intentresolver/util/Flow.kt84
-rw-r--r--java/src/com/android/intentresolver/util/UriFilters.kt75
-rw-r--r--java/src/com/android/intentresolver/widget/ChooserActionRow.kt81
-rw-r--r--java/src/com/android/intentresolver/widget/ChooserImagePreviewView.kt163
-rw-r--r--java/src/com/android/intentresolver/widget/ImagePreviewView.kt7
-rw-r--r--java/src/com/android/intentresolver/widget/ResolverDrawerLayout.java24
-rw-r--r--java/src/com/android/intentresolver/widget/RoundedRectImageView.java13
-rw-r--r--java/src/com/android/intentresolver/widget/ScrollableActionRow.kt48
-rw-r--r--java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt527
-rw-r--r--java/tests/Android.bp2
-rw-r--r--java/tests/AndroidManifest.xml4
-rw-r--r--java/tests/src/com/android/intentresolver/AnnotatedUserHandlesTest.kt79
-rw-r--r--java/tests/src/com/android/intentresolver/ChooserActionFactoryTest.kt22
-rw-r--r--java/tests/src/com/android/intentresolver/ChooserActivityOverrideData.java24
-rw-r--r--java/tests/src/com/android/intentresolver/ChooserListAdapterTest.kt87
-rw-r--r--java/tests/src/com/android/intentresolver/ChooserRefinementManagerTest.kt225
-rw-r--r--java/tests/src/com/android/intentresolver/ChooserRequestParametersTest.kt88
-rw-r--r--java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java52
-rw-r--r--java/tests/src/com/android/intentresolver/ImagePreviewImageLoaderTest.kt101
-rw-r--r--java/tests/src/com/android/intentresolver/ResolverActivityTest.java475
-rw-r--r--java/tests/src/com/android/intentresolver/ResolverDataProvider.java48
-rw-r--r--java/tests/src/com/android/intentresolver/ResolverWrapperActivity.java131
-rw-r--r--java/tests/src/com/android/intentresolver/ResolverWrapperAdapter.java84
-rw-r--r--java/tests/src/com/android/intentresolver/ShortcutSelectionLogicTest.kt9
-rw-r--r--java/tests/src/com/android/intentresolver/TestContentPreviewViewModel.kt56
-rw-r--r--java/tests/src/com/android/intentresolver/TestContentProvider.kt55
-rw-r--r--java/tests/src/com/android/intentresolver/TestPreviewImageLoader.kt19
-rw-r--r--java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java571
-rw-r--r--java/tests/src/com/android/intentresolver/UnbundledChooserActivityWorkProfileTest.java19
-rw-r--r--java/tests/src/com/android/intentresolver/chooser/ImmutableTargetInfoTest.kt12
-rw-r--r--java/tests/src/com/android/intentresolver/chooser/TargetInfoTest.kt9
-rw-r--r--java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt233
-rw-r--r--java/tests/src/com/android/intentresolver/contentpreview/ContentPreviewUiTest.kt41
-rw-r--r--java/tests/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImplTest.kt61
-rw-r--r--java/tests/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoaderTest.kt366
-rw-r--r--java/tests/src/com/android/intentresolver/contentpreview/PreviewDataProviderTest.kt351
-rw-r--r--java/tests/src/com/android/intentresolver/model/AbstractResolverComparatorTest.java80
-rw-r--r--java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt230
-rw-r--r--java/tests/src/com/android/intentresolver/util/UriFiltersTest.kt95
-rw-r--r--java/tests/src/com/android/intentresolver/widget/BatchPreviewLoaderTest.kt215
224 files changed, 15922 insertions, 3826 deletions
diff --git a/java/res/values/bools.xml b/java/res/color/resolver_profile_tab_text.xml
index a84081b6..7c2723ce 100644
--- a/java/res/values/bools.xml
+++ b/java/res/color/resolver_profile_tab_text.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,7 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<resources>
- <bool name="resolver_landscape_phone">@*android:bool/resolver_landscape_phone</bool>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/materialColorOnPrimary" android:state_selected="true"/>
+ <item android:color="?androidprv:attr/materialColorOnSurfaceVariant"/>
+</selector>
diff --git a/java/res/drawable-h480dp/content_preview_badge_bg.xml b/java/res/drawable-h480dp/content_preview_badge_bg.xml
new file mode 100644
index 00000000..98a17e0c
--- /dev/null
+++ b/java/res/drawable-h480dp/content_preview_badge_bg.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+android:shape="rectangle">
+ <corners android:radius="@dimen/chooser_corner_radius_small" />
+ <gradient
+ android:type="radial"
+ android:centerX="1"
+ android:centerY="0"
+ android:gradientRadius="@dimen/chooser_preview_image_height_tall"
+ android:startColor="#20000000"
+ android:endColor="#00000000" />
+</shape>
diff --git a/java/res/drawable/bottomsheet_background.xml b/java/res/drawable/bottomsheet_background.xml
index 60fd7e21..f4386b7d 100644
--- a/java/res/drawable/bottomsheet_background.xml
+++ b/java/res/drawable/bottomsheet_background.xml
@@ -14,9 +14,11 @@
limitations under the License.
-->
-<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
<corners
android:topLeftRadius="@*android:dimen/config_bottomDialogCornerRadius"
android:topRightRadius="@*android:dimen/config_bottomDialogCornerRadius"/>
- <solid android:color="?android:attr/colorBackground" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainer" />
</shape>
diff --git a/java/res/drawable/chevron_right.xml b/java/res/drawable/chevron_right.xml
new file mode 100644
index 00000000..747e06dd
--- /dev/null
+++ b/java/res/drawable/chevron_right.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<!-- This is based off of the chevron_right icon seen elsewhere, but the padding
+ on the right side of the icon has been removed (so the chevron can align with
+ other UI elements. This was done by reducing the viewport width to the maximum
+ extent of the path itself. -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:width="16dp"
+ android:height="24dp"
+ android:viewportWidth="16"
+ android:viewportHeight="24"
+ android:autoMirrored="true"
+ android:tint="?androidprv:attr/materialColorOnSurface">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M10,4.5L8.59,5.91 13.17,10.5l-4.58,4.59L10,16.5l6,-6 -6,-6z"/>
+</vector>
diff --git a/java/res/drawable/chooser_action_button_bg.xml b/java/res/drawable/chooser_action_button_bg.xml
index b984a067..300be831 100644
--- a/java/res/drawable/chooser_action_button_bg.xml
+++ b/java/res/drawable/chooser_action_button_bg.xml
@@ -24,9 +24,8 @@
android:insetRight="0dp"
android:insetBottom="8dp">
<shape android:shape="rectangle">
- <corners android:radius="8dp" />
- <stroke android:width="1dp"
- android:color="?androidprv:attr/colorAccentPrimaryVariant"/>
+ <corners android:radius="@dimen/chooser_action_corner_radius" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/>
</shape>
</inset>
</item>
diff --git a/java/res/layout/chooser_image_preview_view.xml b/java/res/drawable/chooser_content_preview_rounded.xml
index e81349c7..a1b204bd 100644
--- a/java/res/layout/chooser_image_preview_view.xml
+++ b/java/res/drawable/chooser_content_preview_rounded.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -15,12 +15,13 @@
~ limitations under the License.
-->
-<com.android.intentresolver.widget.ChooserImagePreviewView
+<shape
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:paddingStart="@dimen/chooser_edge_margin_normal"
- android:paddingEnd="@dimen/chooser_edge_margin_normal"
- android:paddingBottom="@dimen/chooser_view_spacing"
- android:background="?android:attr/colorBackground" />
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+
+ <solid
+ android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
+
+ <corners android:radius="16dp" />
+</shape>
diff --git a/java/res/drawable/chooser_row_layer_list.xml b/java/res/drawable/chooser_row_layer_list.xml
index 43f0cf6f..868ac8aa 100644
--- a/java/res/drawable/chooser_row_layer_list.xml
+++ b/java/res/drawable/chooser_row_layer_list.xml
@@ -20,7 +20,7 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<item>
<shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorAccentSecondary"/>
+ <solid android:color="?androidprv:attr/materialColorSecondary"/>
<size android:width="128dp" android:height="2dp"/>
<corners android:radius="2dp" />
</shape>
diff --git a/java/res/drawable/content_preview_badge_bg.xml b/java/res/drawable/content_preview_badge_bg.xml
new file mode 100644
index 00000000..56ac31cc
--- /dev/null
+++ b/java/res/drawable/content_preview_badge_bg.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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 that this is the drawable for landscape phones, the default is in drawable-480dp -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <corners android:radius="@dimen/chooser_corner_radius_small" />
+ <gradient
+ android:type="radial"
+ android:centerX="0.5"
+ android:centerY="0.5"
+ android:gradientRadius="23dp"
+ android:startColor="#20000000"
+ android:endColor="#00000000" />
+</shape>
diff --git a/java/res/layout/chooser_action_button.xml b/java/res/drawable/edit_action_background.xml
index 2b68ccca..91726f49 100644
--- a/java/res/layout/chooser_action_button.xml
+++ b/java/res/drawable/edit_action_background.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2019 The Android Open Source Project
~
@@ -13,19 +14,16 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
-<Button xmlns:android="http://schemas.android.com/apk/res/android"
- android:gravity="center_vertical|start"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:drawablePadding="8dp"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="12sp"
- android:maxWidth="192dp"
- android:singleLine="true"
- android:clickable="true"
- android:background="@drawable/chooser_action_button_bg"
- android:drawableTint="?android:attr/textColorPrimary"
- android:drawableTintMode="src_in"
- style="?android:attr/borderlessButtonStyle"
- />
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:color="?android:attr/colorControlHighlight"
+ >
+ <item>
+ <inset android:inset="8dp">
+ <shape android:shape="rectangle">
+ <corners android:radius="12dp" />
+ <solid android:color="?androidprv:attr/materialColorSecondaryFixed"/>
+ </shape>
+ </inset>
+ </item>
+</ripple>
diff --git a/java/res/drawable/ic_drag_handle.xml b/java/res/drawable/ic_drag_handle.xml
index 9b0e2046..f22e8c30 100644
--- a/java/res/drawable/ic_drag_handle.xml
+++ b/java/res/drawable/ic_drag_handle.xml
@@ -15,7 +15,8 @@
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle" >
- <solid android:color="#FFFFFFFF" />
+ <solid android:color="?androidprv:attr/materialColorOutlineVariant" />
<corners android:radius="2dp" />
</shape>
diff --git a/java/res/drawable/ic_file_copy.xml b/java/res/drawable/ic_file_copy.xml
index d05b55f1..0667e474 100644
--- a/java/res/drawable/ic_file_copy.xml
+++ b/java/res/drawable/ic_file_copy.xml
@@ -20,6 +20,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5l6,6v10c0,1.1 -0.9,2 -2,2L7.99,23C6.89,23 6,22.1 6,21l0.01,-14c0,-1.1 0.89,-2 1.99,-2h7zM14,12h5.5L14,6.5L14,12z"
+ android:pathData="m19.5,19l-11,0c-0.55,0 -1.03,-0.19 -1.42,-0.57c-0.39,-0.41 -0.58,-0.88 -0.58,-1.43l0,-14c0,-0.55 0.19,-1.02 0.58,-1.4c0.39,-0.4 0.87,-0.6 1.42,-0.6l7,0l6,6l0,10c0,0.55 -0.2,1.02 -0.6,1.43c-0.38,0.38 -0.85,0.57 -1.4,0.57zm-5,-11l0,-5l-6,0l0,14l11,0l0,-9l-5,0zm-10,15c-0.55,0 -1.02,-0.19 -1.42,-0.57c-0.39,-0.41 -0.58,-0.88 -0.58,-1.43l0,-14l2,0l0,14l11,0l0,2l-11,0zm4,-20l0,5l0,-5l0,5l0,9l0,-14z"
android:fillColor="@android:color/white"/>
</vector>
diff --git a/java/res/layout/scrollable_image_preview_view.xml b/java/res/drawable/ic_file_video.xml
index c6c310e6..ec6e290b 100644
--- a/java/res/layout/scrollable_image_preview_view.xml
+++ b/java/res/drawable/ic_file_video.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8" ?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -15,12 +14,14 @@
~ limitations under the License.
-->
-<com.android.intentresolver.widget.ScrollableImagePreviewView
+<vector
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:paddingStart="@dimen/chooser_edge_margin_normal"
- android:paddingEnd="@dimen/chooser_edge_margin_normal"
- android:paddingBottom="@dimen/chooser_view_spacing"
- android:background="?android:attr/colorBackground" />
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m4,20c-0.55,0 -1.02,-0.19 -1.42,-0.57c-0.39,-0.4 -0.58,-0.88 -0.58,-1.43l0,-12c0,-0.55 0.19,-1.02 0.58,-1.4c0.39,-0.4 0.87,-0.6 1.42,-0.6l12,0c0.55,0 1.02,0.2 1.4,0.6c0.4,0.38 0.6,0.85 0.6,1.4l0,4.5l4,-4l0,11l-4,-4l0,4.5c0,0.55 -0.2,1.03 -0.6,1.43c-0.38,0.38 -0.85,0.57 -1.4,0.57l-12,0zm0,-2l12,0l0,-12l-12,0l0,12zm0,0l0,-12l0,12z"/>
+</vector>
diff --git a/java/res/drawable/resolver_outlined_button_bg.xml b/java/res/drawable/resolver_outlined_button_bg.xml
index da569e72..3469a06e 100644
--- a/java/res/drawable/resolver_outlined_button_bg.xml
+++ b/java/res/drawable/resolver_outlined_button_bg.xml
@@ -26,7 +26,7 @@
<shape android:shape="rectangle">
<corners android:radius="8dp" />
<stroke android:width="1dp"
- android:color="?androidprv:attr/colorAccentPrimaryVariant"/>
+ android:color="?androidprv:attr/materialColorPrimaryContainer"/>
</shape>
</inset>
</item>
diff --git a/java/res/drawable/resolver_profile_tab_bg.xml b/java/res/drawable/resolver_profile_tab_bg.xml
index 66cd6d88..8bb23a53 100644
--- a/java/res/drawable/resolver_profile_tab_bg.xml
+++ b/java/res/drawable/resolver_profile_tab_bg.xml
@@ -29,14 +29,14 @@
<item android:state_selected="false">
<shape android:shape="rectangle">
<corners android:radius="12dp" />
- <solid android:color="?androidprv:attr/colorSurface" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHighest" />
</shape>
</item>
<item android:state_selected="true">
<shape android:shape="rectangle">
<corners android:radius="12dp" />
- <solid android:color="@androidprv:color/resolver_profile_tab_selected_bg" />
+ <solid android:color="?androidprv:attr/materialColorPrimary" />
</shape>
</item>
</selector>
diff --git a/java/res/drawable/single_file.xml b/java/res/drawable/single_file.xml
new file mode 100644
index 00000000..af46c97e
--- /dev/null
+++ b/java/res/drawable/single_file.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="@*android:color/material_grey_600"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="m6,22c-0.55,0 -1.02,-0.19 -1.42,-0.57c-0.39,-0.41 -0.58,-0.88 -0.58,-1.43l0,-16c0,-0.55 0.19,-1.02 0.58,-1.4c0.39,-0.4 0.87,-0.6 1.42,-0.6l8,0l6,6l0,12c0,0.55 -0.2,1.02 -0.6,1.43c-0.38,0.38 -0.85,0.57 -1.4,0.57l-12,0zm7,-13l0,-5l-7,0l0,16l12,0l0,-11l-5,0zm-7,-5l0,5l0,-5l0,5l0,11l0,-16z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/java/res/layout-h480dp/image_preview_image_item.xml b/java/res/layout-h480dp/image_preview_image_item.xml
new file mode 100644
index 00000000..ac63b2d5
--- /dev/null
+++ b/java/res/layout-h480dp/image_preview_image_item.xml
@@ -0,0 +1,77 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/chooser_preview_image_height_tall">
+
+ <com.android.intentresolver.widget.RoundedRectImageView
+ android:id="@+id/image"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ app:layout_constraintDimensionRatio="W,1:1"
+ android:layout_alignParentTop="true"
+ android:adjustViewBounds="false"
+ android:scaleType="centerCrop"
+ app:radius="@dimen/chooser_corner_radius_small"
+ android:importantForAccessibility="no" />
+
+ <FrameLayout
+ android:id="@+id/badge_frame"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toStartOf="@+id/image"
+ app:layout_constraintEnd_toEndOf="@+id/image"
+ app:layout_constraintTop_toTopOf="@+id/image"
+ app:layout_constraintBottom_toBottomOf="@+id/image"
+ android:background="@drawable/content_preview_badge_bg"
+ android:importantForAccessibility="noHideDescendants">
+
+ <ImageView
+ android:id="@+id/badge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scaleType="center"
+ android:layout_marginEnd="6dp"
+ android:layout_marginTop="6dp"
+ android:tint="@android:color/white"
+ android:layout_gravity="top|end" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/edit"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:background="@drawable/edit_action_background"
+ android:drawableTint="?androidprv:attr/materialColorSecondaryFixed"
+ android:contentDescription="@string/screenshot_edit"
+ android:visibility="gone"
+ >
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:padding="4dp"
+ android:tint="?androidprv:attr/materialColorOnSecondaryFixed"
+ android:src="@androidprv:drawable/ic_screenshot_edit"
+ />
+ </FrameLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/java/res/layout/chooser_action_row.xml b/java/res/layout/chooser_action_row.xml
index 620ff704..55d6adf7 100644
--- a/java/res/layout/chooser_action_row.xml
+++ b/java/res/layout/chooser_action_row.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -11,22 +11,27 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT 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.
-->
-<FrameLayout
+
+<merge
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <com.android.intentresolver.widget.ChooserActionRow
+ <com.android.intentresolver.widget.ScrollableActionRow
android:id="@androidprv:id/chooser_action_row"
- android:layout_width="@dimen/chooser_preview_width"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingLeft="@dimen/chooser_edge_margin_normal"
- android:paddingRight="@dimen/chooser_edge_margin_normal"
- android:layout_marginBottom="@dimen/chooser_view_spacing"
android:layout_gravity="center_horizontal"
- android:gravity="center" />
+ android:gravity="center"/>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginHorizontal="@dimen/chooser_edge_margin_normal"
+ android:layout_marginBottom="10dp"
+ android:background="?androidprv:attr/materialColorSurfaceContainerHighest"
+ />
+</merge>
-</FrameLayout> \ No newline at end of file
diff --git a/java/res/layout/chooser_action_view.xml b/java/res/layout/chooser_action_view.xml
index d74798e2..ba9134cc 100644
--- a/java/res/layout/chooser_action_view.xml
+++ b/java/res/layout/chooser_action_view.xml
@@ -15,14 +15,18 @@
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:gravity="center"
- android:drawablePadding="8dp"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="12sp"
- android:maxWidth="192dp"
- android:singleLine="true"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ style="?android:attr/borderlessButtonStyle"
+ android:background="@drawable/chooser_action_button_bg"
+ android:paddingBottom="8dp"
+ android:paddingHorizontal="@dimen/chooser_edge_margin_normal_half"
android:clickable="true"
- android:drawableTint="?android:attr/textColorPrimary"
+ android:drawablePadding="6dp"
+ android:drawableTint="?androidprv:attr/materialColorOnSurface"
android:drawableTintMode="src_in"
- style="?android:attr/borderlessButtonStyle"
- />
+ android:ellipsize="end"
+ android:gravity="center"
+ android:maxLines="1"
+ android:maxWidth="@dimen/chooser_action_max_width"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
+ android:textSize="12sp" />
diff --git a/java/res/layout/chooser_az_label_row.xml b/java/res/layout/chooser_az_label_row.xml
index baf07cec..6a077ded 100644
--- a/java/res/layout/chooser_az_label_row.xml
+++ b/java/res/layout/chooser_az_label_row.xml
@@ -16,9 +16,9 @@
-->
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:contentDescription="@string/chooser_all_apps_button_label"
+ android:importantForAccessibility="no"
android:src="@drawable/chooser_row_layer_list"
- android:paddingTop="16dp"
+ android:paddingVertical="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="center"
diff --git a/java/res/layout/chooser_grid.xml b/java/res/layout/chooser_grid.xml
index d863495d..8320b284 100644
--- a/java/res/layout/chooser_grid.xml
+++ b/java/res/layout/chooser_grid.xml
@@ -36,14 +36,13 @@
android:elevation="0dp"
android:background="@drawable/bottomsheet_background">
- <ImageView
+ <View
android:id="@androidprv:id/drag"
- android:layout_width="24dp"
+ android:layout_width="64dp"
android:layout_height="4dp"
- android:src="@drawable/ic_drag_handle"
+ android:background="@drawable/ic_drag_handle"
android:layout_marginTop="@dimen/chooser_edge_margin_thin"
android:layout_marginBottom="@dimen/chooser_edge_margin_thin"
- android:tint="?androidprv:attr/colorSurfaceVariant"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true" />
@@ -72,7 +71,7 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
- android:background="?android:attr/colorBackground">
+ android:background="?androidprv:attr/materialColorSurfaceContainer">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
diff --git a/java/res/layout/chooser_grid_preview_file.xml b/java/res/layout/chooser_grid_preview_file.xml
index 095e5d62..3c836b4c 100644
--- a/java/res/layout/chooser_grid_preview_file.xml
+++ b/java/res/layout/chooser_grid_preview_file.xml
@@ -24,64 +24,67 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingBottom="@dimen/chooser_view_spacing"
- android:background="?android:attr/colorBackground">
+ android:background="?androidprv:attr/materialColorSurfaceContainer">
- <LinearLayout
- android:layout_width="@dimen/chooser_preview_width"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:orientation="horizontal"
- android:paddingLeft="@dimen/chooser_edge_margin_normal"
- android:paddingRight="@dimen/chooser_edge_margin_normal"
- android:layout_marginBottom="@dimen/chooser_view_spacing"
- android:id="@androidprv:id/content_preview_file_layout">
+ <include layout="@layout/chooser_headline_row"/>
- <com.android.intentresolver.widget.RoundedRectImageView
- android:id="@androidprv:id/content_preview_file_thumbnail"
- android:layout_width="75dp"
- android:layout_height="75dp"
- android:layout_marginRight="16dp"
- android:adjustViewBounds="true"
- android:layout_gravity="center_vertical"
- android:gravity="center"
- android:scaleType="centerCrop"/>
- <ImageView
- android:id="@androidprv:id/content_preview_file_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_marginRight="16dp"
- android:adjustViewBounds="true"
- android:layout_gravity="center_vertical"
- android:gravity="center"
- android:scaleType="fitCenter"
- android:visibility="gone"/>
- <TextView
- android:id="@androidprv:id/content_preview_filename"
- android:layout_width="0dp"
- android:layout_weight="1"
+ <RelativeLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:ellipsize="middle"
- android:gravity="start|top"
- android:paddingRight="24dp"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.ChooserDefault" />
- </LinearLayout>
+ android:layout_gravity="center"
+ android:layout_marginHorizontal="@dimen/chooser_edge_margin_normal"
+ android:layout_marginBottom="8dp"
+ android:padding="@dimen/chooser_edge_margin_normal"
+ android:background="@drawable/chooser_content_preview_rounded"
+ android:id="@androidprv:id/content_preview_file_layout">
- <TextView
- android:id="@+id/reselection_action"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:text="@string/select_files"
- android:gravity="center"
- style="@style/ReselectionAction" />
+ <ImageView
+ android:id="@+id/content_preview_file_icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginEnd="16dp"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:src="@drawable/ic_file_copy"
+ android:scaleType="fitCenter"/>
- <ViewStub
- android:id="@+id/action_row_stub"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_centerVertical="true"
+ android:layout_toEndOf="@id/content_preview_file_icon"
+ android:layout_alignParentTop="true"
+ android:layout_alignWithParentIfMissing="true">
+
+ <TextView
+ android:id="@+id/content_preview_filename"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="middle"
+ android:gravity="start|top"
+ android:singleLine="true"
+ android:textStyle="bold"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
+ android:textSize="12sp"
+ android:lineHeight="16sp"
+ android:textAppearance="@style/TextAppearance.ChooserDefault"/>
+
+ <TextView
+ android:id="@+id/content_preview_more_files"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="start|top"
+ android:singleLine="true"
+ android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
+ android:textSize="12sp"
+ android:lineHeight="16sp"
+ android:textAppearance="@style/TextAppearance.ChooserDefault"/>
+
+ </LinearLayout>
+ </RelativeLayout>
+
+ <include layout="@layout/chooser_action_row"/>
</LinearLayout>
diff --git a/java/res/layout/chooser_grid_preview_files_text.xml b/java/res/layout/chooser_grid_preview_files_text.xml
new file mode 100644
index 00000000..c64d7ddd
--- /dev/null
+++ b/java/res/layout/chooser_grid_preview_files_text.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2019, The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:background="?androidprv:attr/materialColorSurfaceContainer">
+
+ <include layout="@layout/chooser_headline_row" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_horizontal"
+ android:layout_marginBottom="8dp"
+ android:layout_marginHorizontal="@dimen/chooser_edge_margin_normal"
+ android:padding="@dimen/chooser_edge_margin_normal_half"
+ android:background="@drawable/chooser_content_preview_rounded">
+
+ <com.android.intentresolver.widget.RoundedRectImageView
+ android:id="@+id/image_view"
+ android:layout_width="@dimen/width_text_image_preview_size"
+ android:layout_height="@dimen/width_text_image_preview_size"
+ android:scaleType="centerCrop"
+ app:radius="@dimen/chooser_corner_radius_small"
+ />
+
+ <TextView
+ android:id="@+id/content_preview_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/chooser_edge_margin_normal_half"
+ android:maxLines="@integer/text_preview_lines"
+ android:ellipsize="end"
+ android:linksClickable="false"
+ android:textAppearance="@style/TextAppearance.ChooserDefault"/>
+ </LinearLayout>
+
+ <include layout="@layout/chooser_action_row"/>
+</LinearLayout>
diff --git a/java/res/layout/chooser_grid_preview_image.xml b/java/res/layout/chooser_grid_preview_image.xml
index 792b7d4d..4a832324 100644
--- a/java/res/layout/chooser_grid_preview_image.xml
+++ b/java/res/layout/chooser_grid_preview_image.xml
@@ -18,59 +18,24 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:background="?android:attr/colorBackground">
+ android:importantForAccessibility="no"
+ android:background="?androidprv:attr/materialColorSurfaceContainer">
- <CheckBox
- android:id="@+id/include_text_action"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end"
- android:layout_marginEnd="@dimen/chooser_edge_margin_normal"
- android:visibility="gone" />
+ <include layout="@layout/chooser_headline_row"/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center_horizontal"
- android:layout_marginBottom="@dimen/chooser_view_spacing">
-
- <ViewStub
- android:id="@+id/image_preview_stub"
- android:inflatedId="@androidprv:id/content_preview_image_area"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <TextView
- android:id="@androidprv:id/content_preview_text"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center_vertical"
- android:paddingEnd="@dimen/chooser_edge_margin_normal"
- android:maxLines="6"
- android:ellipsize="end"
- android:linksClickable="false"
- android:visibility="gone"
- android:textAppearance="@style/TextAppearance.ChooserDefault" />
- </LinearLayout>
-
- <TextView
- android:id="@+id/reselection_action"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:text="@string/select_images"
- android:gravity="center"
- style="@style/ReselectionAction" />
-
- <ViewStub
- android:id="@+id/action_row_stub"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ <com.android.intentresolver.widget.ScrollableImagePreviewView
+ android:id="@+id/scrollable_image_preview"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/chooser_preview_image_height_tall"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="8dp"
+ app:itemInnerSpacing="3dp"
+ app:itemOuterSpacing="@dimen/chooser_edge_margin_normal"/>
+ <include layout="@layout/chooser_action_row"/>
</LinearLayout>
diff --git a/java/res/layout/chooser_grid_preview_text.xml b/java/res/layout/chooser_grid_preview_text.xml
index 49a2edff..df906cce 100644
--- a/java/res/layout/chooser_grid_preview_text.xml
+++ b/java/res/layout/chooser_grid_preview_text.xml
@@ -20,88 +20,100 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@androidprv:id/content_preview_text_area"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:background="?android:attr/colorBackground">
+ android:background="?androidprv:attr/materialColorSurfaceContainer">
- <RelativeLayout
- android:layout_width="@dimen/chooser_preview_width"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:orientation="horizontal"
- android:paddingLeft="@dimen/chooser_edge_margin_normal"
- android:paddingRight="@dimen/chooser_edge_margin_normal"
- android:layout_marginBottom="@dimen/chooser_view_spacing"
- android:id="@androidprv:id/content_preview_text_layout">
+ <include layout="@layout/chooser_headline_row" />
- <TextView
- android:id="@androidprv:id/content_preview_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- android:layout_centerVertical="true"
- android:ellipsize="end"
- android:fontFamily="@androidprv:string/config_headlineFontFamily"
- android:textColor="?android:attr/textColorPrimary"
- android:textAlignment="gravity"
- android:textDirection="locale"
- android:maxLines="2"
- android:focusable="true"/>
-
- </RelativeLayout>
-
- <TextView
- android:id="@+id/reselection_action"
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:visibility="gone"
- android:text="@string/select_text"
- android:gravity="center"
- style="@style/ReselectionAction" />
-
- <ViewStub
- android:id="@+id/action_row_stub"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <!-- Required sub-layout so we can get the nice rounded corners-->
- <!-- around this section -->
- <LinearLayout
- android:layout_width="@dimen/chooser_preview_width"
- android:layout_height="wrap_content"
android:layout_gravity="center"
- android:orientation="horizontal"
- android:layout_marginLeft="@dimen/chooser_edge_margin_normal"
- android:layout_marginRight="@dimen/chooser_edge_margin_normal"
- android:layout_marginBottom="@dimen/chooser_view_spacing"
- android:minHeight="80dp"
- android:background="@androidprv:drawable/chooser_content_preview_rounded"
- android:id="@androidprv:id/content_preview_title_layout">
+ android:layout_marginHorizontal="@dimen/chooser_edge_margin_normal"
+ android:layout_marginBottom="8dp"
+ android:paddingVertical="@dimen/chooser_edge_margin_normal_half"
+ android:paddingStart="@dimen/chooser_edge_margin_normal_half"
+ android:paddingEnd="0dp"
+ android:background="@drawable/chooser_content_preview_rounded"
+ android:id="@+id/text_preview_layout">
<com.android.intentresolver.widget.RoundedRectImageView
android:id="@androidprv:id/content_preview_thumbnail"
- android:layout_width="75dp"
- android:layout_height="75dp"
- android:layout_marginRight="16dp"
+ android:layout_width="@dimen/width_text_image_preview_size"
+ android:layout_height="@dimen/width_text_image_preview_size"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
android:adjustViewBounds="true"
- android:layout_gravity="center_vertical"
android:gravity="center"
+ app:radius="@dimen/chooser_corner_radius_small"
android:scaleType="centerCrop"/>
<TextView
android:id="@androidprv:id/content_preview_title"
android:layout_width="0dp"
- android:layout_weight="1"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
+ app:layout_constraintStart_toEndOf="@androidprv:id/content_preview_thumbnail"
+ app:layout_constraintEnd_toStartOf="@id/copy"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@androidprv:id/content_preview_text"
+ android:layout_marginStart="@dimen/chooser_edge_margin_normal_half"
+ app:layout_goneMarginStart="0dp"
+ app:layout_constraintVertical_chainStyle="packed"
android:ellipsize="end"
- android:maxLines="2"
+ android:maxLines="1"
android:textAlignment="gravity"
android:textDirection="locale"
- android:textAppearance="@android:style/TextAppearance.DeviceDefault.WindowTitle"
+ android:textStyle="bold"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
android:fontFamily="@androidprv:string/config_headlineFontFamily"/>
- </LinearLayout>
+
+ <TextView
+ android:id="@androidprv:id/content_preview_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintStart_toEndOf="@androidprv:id/content_preview_thumbnail"
+ app:layout_constraintEnd_toStartOf="@id/copy"
+ app:layout_constraintTop_toBottomOf="@androidprv:id/content_preview_title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginStart="@dimen/chooser_edge_margin_normal_half"
+ app:layout_goneMarginStart="0dp"
+ android:ellipsize="end"
+ android:fontFamily="@androidprv:string/config_headlineFontFamily"
+ android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
+ android:textAlignment="gravity"
+ android:textDirection="locale"
+ android:maxLines="@integer/text_preview_lines"
+ android:focusable="true"/>
+
+ <FrameLayout
+ android:id="@+id/copy"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ style="?android:attr/borderlessButtonStyle"
+ app:layout_constraintStart_toEndOf="@androidprv:id/content_preview_text"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginHorizontal="4dp"
+ android:contentDescription="@android:string/copy"
+ >
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:tint="?androidprv:attr/materialColorOnSurfaceVariant"
+ android:src="@androidprv:drawable/ic_menu_copy_material"
+ />
+ </FrameLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <include layout="@layout/chooser_action_row" />
+
</LinearLayout>
diff --git a/java/res/layout/chooser_headline_row.xml b/java/res/layout/chooser_headline_row.xml
new file mode 100644
index 00000000..62781847
--- /dev/null
+++ b/java/res/layout/chooser_headline_row.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingHorizontal="@dimen/chooser_edge_margin_normal"
+ android:layout_marginBottom="@dimen/chooser_view_spacing"
+>
+ <TextView
+ android:id="@+id/headline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="invisible"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/barrier"
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constrainedWidth="true"
+ style="@style/TextAppearance.ChooserDefault"
+ android:fontFamily="@androidprv:string/config_headlineFontFamily"
+ android:textSize="18sp"
+ />
+
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/barrier"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:barrierDirection="start"
+ app:constraint_referenced_ids="reselection_action,include_text_action" />
+
+ <TextView
+ android:id="@+id/reselection_action"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxWidth="@dimen/modify_share_text_toggle_max_width"
+ app:layout_constraintEnd_toEndOf="parent"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:paddingTop="3dp"
+ style="@style/TextAppearance.ChooserDefault"
+ android:drawableEnd="@drawable/chevron_right"
+ />
+
+ <!-- This is only relevant for image+text preview, but needs to be in this layout so it can
+ stay at the top if there's no reselection action. -->
+ <CheckBox
+ android:id="@+id/include_text_action"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxWidth="@dimen/modify_share_text_toggle_max_width"
+ android:layout_marginTop="16dp"
+ app:layout_goneMarginTop="0dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/reselection_action"
+ android:layout_alignWithParentIfMissing="true"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
+ android:visibility="gone" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/java/res/layout/chooser_image_preview_view_internals.xml b/java/res/layout/chooser_image_preview_view_internals.xml
deleted file mode 100644
index 2b93edf8..00000000
--- a/java/res/layout/chooser_image_preview_view_internals.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<merge
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:paddingBottom="@dimen/chooser_view_spacing"
- android:background="?android:attr/colorBackground">
-
- <com.android.intentresolver.widget.RoundedRectImageView
- android:id="@androidprv:id/content_preview_image_1_large"
- android:transitionName="screenshot_preview_image"
- android:layout_width="@dimen/chooser_preview_image_width"
- android:layout_height="@dimen/chooser_preview_image_height"
- android:layout_alignParentTop="true"
- android:adjustViewBounds="true"
- android:gravity="center"
- android:scaleType="centerCrop"/>
-
- <com.android.intentresolver.widget.RoundedRectImageView
- android:id="@androidprv:id/content_preview_image_2_large"
- android:visibility="gone"
- android:layout_width="@dimen/chooser_preview_image_width"
- android:layout_height="@dimen/chooser_preview_image_height"
- android:layout_alignParentTop="true"
- android:layout_toRightOf="@androidprv:id/content_preview_image_1_large"
- android:layout_marginLeft="10dp"
- android:adjustViewBounds="true"
- android:gravity="center"
- android:scaleType="centerCrop"/>
-
- <com.android.intentresolver.widget.RoundedRectImageView
- android:id="@androidprv:id/content_preview_image_2_small"
- android:visibility="gone"
- android:layout_width="@dimen/chooser_preview_image_width"
- android:layout_height="65dp"
- android:layout_alignParentTop="true"
- android:layout_toRightOf="@androidprv:id/content_preview_image_1_large"
- android:layout_marginLeft="10dp"
- android:adjustViewBounds="true"
- android:gravity="center"
- android:scaleType="centerCrop"/>
-
- <com.android.intentresolver.widget.RoundedRectImageView
- android:id="@androidprv:id/content_preview_image_3_small"
- android:visibility="gone"
- android:layout_width="@dimen/chooser_preview_image_width"
- android:layout_height="65dp"
- android:layout_below="@androidprv:id/content_preview_image_2_small"
- android:layout_toRightOf="@androidprv:id/content_preview_image_1_large"
- android:layout_marginLeft="10dp"
- android:layout_marginTop="10dp"
- android:adjustViewBounds="true"
- android:gravity="center"
- android:scaleType="centerCrop"/>
-
-</merge>
diff --git a/java/res/layout/chooser_list_per_profile.xml b/java/res/layout/chooser_list_per_profile.xml
index 1753e2f6..ef82090c 100644
--- a/java/res/layout/chooser_list_per_profile.xml
+++ b/java/res/layout/chooser_list_per_profile.xml
@@ -25,7 +25,7 @@
app:layoutManager="com.android.intentresolver.ChooserGridLayoutManager"
android:id="@androidprv:id/resolver_list"
android:clipToPadding="false"
- android:background="?android:attr/colorBackground"
+ android:background="?androidprv:attr/materialColorSurfaceContainer"
android:scrollbars="none"
android:elevation="1dp"
android:nestedScrollingEnabled="true" />
diff --git a/java/res/layout/chooser_row.xml b/java/res/layout/chooser_row.xml
index 29914a82..4a5e28c3 100644
--- a/java/res/layout/chooser_row.xml
+++ b/java/res/layout/chooser_row.xml
@@ -28,6 +28,7 @@
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center"
+ android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
android:visibility="gone" />
</LinearLayout>
diff --git a/java/res/layout/image_preview_image_item.xml b/java/res/layout/image_preview_image_item.xml
index c18cc279..3f534831 100644
--- a/java/res/layout/image_preview_image_item.xml
+++ b/java/res/layout/image_preview_image_item.xml
@@ -14,11 +14,38 @@
~ limitations under the License.
-->
-<com.android.intentresolver.widget.RoundedRectImageView
+<!-- Note that this is the layout for landscape phones, the default is in drawable-480dp -->
+<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/image"
- android:layout_width="@dimen/chooser_preview_image_width"
- android:layout_height="@dimen/chooser_preview_image_height"
- android:layout_alignParentTop="true"
- android:adjustViewBounds="false"
- android:scaleType="centerCrop"/>
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="46dp"
+ android:layout_height="46dp">
+
+ <com.android.intentresolver.widget.RoundedRectImageView
+ android:id="@+id/image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentTop="true"
+ android:adjustViewBounds="false"
+ android:scaleType="centerCrop"
+ app:radius="8dp" />
+
+ <FrameLayout
+ android:id="@+id/badge_frame"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toStartOf="@+id/image"
+ app:layout_constraintEnd_toEndOf="@+id/image"
+ app:layout_constraintTop_toTopOf="@+id/image"
+ app:layout_constraintBottom_toBottomOf="@+id/image"
+ android:background="@drawable/content_preview_badge_bg">
+
+ <ImageView
+ android:id="@+id/badge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scaleType="center"
+ android:tint="@android:color/white"
+ android:layout_gravity="center" />
+ </FrameLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/java/res/layout/scrollable_chooser_action_row.xml b/java/res/layout/image_preview_other_item.xml
index cb5dabf0..07f87e3a 100644
--- a/java/res/layout/scrollable_chooser_action_row.xml
+++ b/java/res/layout/image_preview_other_item.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -11,20 +11,21 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT 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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal">
+ android:layout_width="@dimen/chooser_preview_image_width"
+ android:layout_height="@dimen/chooser_preview_image_height_tall">
- <com.android.intentresolver.widget.ScrollableActionRow
- android:id="@androidprv:id/chooser_action_row"
+ <TextView
+ android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:gravity="center" />
+ android:layout_gravity="center"
+ android:drawableTop="@drawable/ic_file_copy"
+ android:drawablePadding="8dp"
+ android:textAppearance="@style/TextAppearance.ChooserDefault" />
+
</FrameLayout>
diff --git a/java/res/layout/resolve_grid_item.xml b/java/res/layout/resolve_grid_item.xml
index 00ca9945..25088773 100644
--- a/java/res/layout/resolve_grid_item.xml
+++ b/java/res/layout/resolve_grid_item.xml
@@ -23,40 +23,44 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="100dp"
- android:gravity="center"
- android:paddingTop="24dp"
- android:paddingBottom="12dp"
- android:paddingLeft="12dp"
- android:paddingRight="12dp"
+ android:gravity="top|center_horizontal"
+ android:paddingVertical="@dimen/grid_padding"
+ android:paddingHorizontal="4dp"
android:focusable="true"
android:background="?android:attr/selectableItemBackgroundBorderless">
<ImageView android:id="@android:id/icon"
android:layout_width="@dimen/chooser_icon_size"
android:layout_height="@dimen/chooser_icon_size"
+ android:layout_marginHorizontal="8dp"
android:scaleType="fitCenter" />
<!-- Size manually tuned to match specs -->
<Space android:layout_width="1dp"
android:layout_height="7dp"/>
+ <!-- NOTE: for id/text1 and id/text2 below set the width to match parent as a workaround for
+ b/269395540 i.e. prevent views bounds change during a transition animation. It does not
+ affect pinned views as we change their layout parameters programmatically (but that's even
+ more narrow possibility and it's not clear if the root cause or the bug would affect it).
+ -->
<!-- App name or Direct Share target name, DS set to 2 lines -->
<TextView android:id="@android:id/text1"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
android:textSize="12sp"
android:gravity="top|center_horizontal"
- android:lines="1"
+ android:maxLines="1"
android:ellipsize="end" />
<!-- Activity name if set, gone for Direct Share targets -->
<TextView android:id="@android:id/text2"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="12sp"
- android:textColor="?android:attr/textColorSecondary"
- android:layout_width="wrap_content"
+ android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lines="1"
android:gravity="top|center_horizontal"
diff --git a/java/res/layout/resolver_profile_tab_button.xml b/java/res/layout/resolver_profile_tab_button.xml
index 95e11cdc..1c2bc1ca 100644
--- a/java/res/layout/resolver_profile_tab_button.xml
+++ b/java/res/layout/resolver_profile_tab_button.xml
@@ -24,7 +24,7 @@
android:layout_marginVertical="6dp"
android:layout_marginHorizontal="@dimen/resolver_profile_tab_margin"
android:background="@drawable/resolver_profile_tab_bg"
- android:textColor="@androidprv:color/resolver_profile_tab_text"
+ android:textColor="@color/resolver_profile_tab_text"
android:textSize="@dimen/resolver_tab_text_size"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"
style="?android:attr/borderlessButtonStyle" />
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
new file mode 100644
index 00000000..91b9e041
--- /dev/null
+++ b/java/res/values-af/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Voltooi handeling met"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Voltooi handeling met <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Voltooi handeling"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Maak oop met"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Maak met <xliff:g id="APP">%1$s</xliff:g> oop"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Maak oop"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Maak <xliff:g id="HOST">%1$s</xliff:g>-skakels oop met"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Maak skakels oop met"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Maak skakels oop met <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Maak <xliff:g id="HOST">%1$s</xliff:g>-skakels oop met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Gee toegang"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Redigeer met"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Wysig met <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Wysig"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Deel"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Deel met <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Deel"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Stuur met"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Stuur met <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Stuur"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Kies \'n Tuis-program"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Gebruik <xliff:g id="APP">%1$s</xliff:g> as Tuis"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Vang prent vas"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Vang prent vas met"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Vang prent vas met <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Vang prent vas"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Gebruik \'n ander program"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Kies \'n handeling"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Geen programme kan hierdie handeling uitvoer nie."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Jy gebruik hierdie program buite jou werkprofiel"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Jy gebruik tans hierdie program in jou werkprofiel"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Altyd"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Net een keer"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> steun nie werkprofiel nie"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Speld <xliff:g id="LABEL">%1$s</xliff:g> vas"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Ontspeld <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Wysig"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # lêer}other{{file_name} + # lêers}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # lêer}other{+ # lêers}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Deel tans teks"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Deel tans skakel"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Deel tans prent}other{Deel tans # prente}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Deel tans video}other{Deel tans # video’s}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Deel tans # item}other{Deel tans # items}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Deel tans prent met teks"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Deel prent met skakel"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Geen mense om mee te deel is aanbeveel nie"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Programmelys"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Opneemtoestemming is nie aan hierdie program verleen nie, maar dit kan oudio deur hierdie USB-toestel opneem."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Persoonlik"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Werk"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Persoonlike aansig"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Werkaansig"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Deur jou IT-admin geblokkeer"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Hierdie inhoud kan nie met werkprogramme gedeel word nie"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Hierdie inhoud kan nie met werkprogramme oopgemaak word nie"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Hierdie inhoud kan nie met persoonlike programme gedeel word nie"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Hierdie inhoud kan nie met persoonlike programme oopgemaak word nie"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Werkprofiel is onderbreek"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Tik om aan te skakel"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Geen werkprogramme nie"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Geen persoonlike programme nie"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Maak <xliff:g id="APP">%s</xliff:g> in jou persoonlike profiel oop?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Maak <xliff:g id="APP">%s</xliff:g> in jou werkprofiel oop?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Gebruik persoonlike blaaier"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Gebruik werkblaaier"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Sluit teks uit"</string>
+ <string name="include_text" msgid="642280283268536140">"Sluit teks in"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Sluit skakel uit"</string>
+ <string name="include_link" msgid="827855767220339802">"Sluit skakel in"</string>
+</resources>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
new file mode 100644
index 00000000..81450120
--- /dev/null
+++ b/java/res/values-am/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"... በመጠቀም ድርጊቱን አጠናቅ"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g>ን በመጠቀም እርምጃ ያጠናቅቁ"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"እርምጃውን አጠናቅቅ"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"ክፈት በ"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"በ<xliff:g id="APP">%1$s</xliff:g> ይክፈቱ"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"ክፈት"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> አገናኞችን ክፈት ከዚህ ጋር"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"አገናኞችን ክፈት ከዚህ ጋር"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"አገናኞችን ከ <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ክፈት"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> አገናኞችን ከ <xliff:g id="APPLICATION">%2$s</xliff:g> ጋር ክፈት"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"መዳረሻ ስጥ"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"ያርትዑ በ"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"በ<xliff:g id="APP">%1$s</xliff:g> ያርትዑ"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"ያርትዑ"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"አጋራ"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"ለ<xliff:g id="APP">%1$s</xliff:g> ያጋሩ"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"አጋራ"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"ይላኩ በ፦"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g>ን በመጠቀም ይላኩ"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"ላክ"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"የመነሻ መተግበሪያ ይምረጡ"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g>ን እንደ መነሻ ይጠቀሙ"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"ምስል አንሳ"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"ምስል ቅረፅ በ"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"ምስል በ<xliff:g id="APP">%1$s</xliff:g> ይቅረጹ"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"ምስል አንሳ"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"የተለየ መተግበሪያ ይጠቀሙ"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"እርምጃ ይምረጡ"</string>
+ <string name="noApplications" msgid="1139487441772284671">"ምንም መተግበሪያዎች ይህን ድርጊት ማከናወን አይችሉም።"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"ከስራ መገለጫዎ ውጭ ሆነው መተግበሪያ እየተጠቀሙ ነው"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"ይህን መተግበሪያ በእርስዎ የስራ መገለጫ ላይ እየተጠቀሙበት ነው"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"ዘወትር"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"አንዴ ብቻ"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> የሥራ መገለጫን አይደግፍም"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g>ን ፒን አድርግ"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> ንቀል"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"አርትዕ"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ፋይል}one{{file_name} + # ፋይል}other{{file_name} + # ፋይሎች}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ፋይል}one{+ # ፋይል}other{+ # ፋይሎች}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"ጽሑፍን በማጋራት ላይ"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"አገናኝን በማጋራት ላይ"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{ምስልን በማጋራት ላይ}one{# ምስልን በማጋራት ላይ}other{# ምስሎችን በማጋራት ላይ}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{ቪድዮ በማጋራት ላይ}one{# ቪድዮ በማጋራት ላይ}other{# ቪድዮዎችን በማጋራት ላይ}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# ንጥልን በማጋራት ላይ}one{# ንጥልን በማጋራት ላይ}other{# ንጥሎችን በማጋራት ላይ}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"ምስልን ከጽሑፍ ጋር በማጋራት ላይ"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"ምስልን ከአገናኝ ጋር በማጋራት ላይ"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"የሚያጋሯቸው ምንም የሚመከሩ ሰዎች የሉም"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"የመተግበሪያዎች ዝርዝር"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"ይህ መተግበሪያ የመቅረጽ ፈቃድ አልተሰጠውም፣ ነገር ግን በዚህ ዩኤስቢ መሣሪያ በኩል ኦዲዮን መቅረጽ ይችላል።"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"የግል"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"ሥራ"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"የግል እይታ"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"የስራ እይታ"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"በእርስዎ የአይቲ አስተዳዳሪ ታግዷል"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"ይህ ይዘት በሥራ መተግበሪያዎች መጋራት አይችልም"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"ይህ ይዘት በሥራ መተግበሪያዎች መከፈት አይችልም"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"ይህ ይዘት በግል መተግበሪያዎች መጋራት አይችልም"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"ይህ ይዘት በግል መተግበሪያዎች መከፈት አይችልም"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"የሥራ መገለጫ ባለበት ቆሟል"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ለማብራት መታ ያድርጉ"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"ምንም የሥራ መተግበሪያዎች የሉም"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"ምንም የግል መተግበሪያዎች የሉም"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g> በግል መገለጫዎ ውስጥ ይከፈት?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g> በስራ መገለጫዎ ውስጥ ይከፈት?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"የግል አሳሽ ተጠቀም"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"የስራ አሳሽ ተጠቀም"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"ጽሁፍን አታካትት"</string>
+ <string name="include_text" msgid="642280283268536140">"ፅሁፍ ጨምር"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"አገናኝን አታካትት"</string>
+ <string name="include_link" msgid="827855767220339802">"አገናኝ አካትት"</string>
+</resources>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
new file mode 100644
index 00000000..16bff5bf
--- /dev/null
+++ b/java/res/values-ar/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"إكمال الإجراء باستخدام"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"إكمال الإجراء باستخدام \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"إكمال الإجراء"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"فتح باستخدام"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"فتح باستخدام \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"فتح"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"فتح روابط <xliff:g id="HOST">%1$s</xliff:g> باستخدام"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"فتح الروابط باستخدام"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"فتح الروابط باستخدام <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"فتح روابط <xliff:g id="HOST">%1$s</xliff:g> باستخدام <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"منح إذن الوصول"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"تعديل باستخدام"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"التعديل باستخدام \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"تعديل"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"مشاركة"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"مشاركة مع \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"مشاركة"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"إرسال باستخدام"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"إرسال باستخدام \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"إرسال"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"اختيار تطبيق شاشة رئيسية"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"استخدام \"<xliff:g id="APP">%1$s</xliff:g>\" كتطبيق الشاشة الرئيسية"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"التقاط صورة"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"التقاط صورة باستخدام"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"التقاط صورة باستخدام \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"التقاط صورة"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"استخدام تطبيق آخر"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"اختيار إجراء"</string>
+ <string name="noApplications" msgid="1139487441772284671">"ليست هناك تطبيقات يمكنها تنفيذ هذا الإجراء."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"أنت تستخدم هذا التطبيق خارج ملفك الشخصي للعمل"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"أنت تستخدم هذا التطبيق في ملفك الشخصي للعمل"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"دائمًا"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"مرة واحدة فقط"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"لا يتوافق تطبيق \"<xliff:g id="APP">%1$s</xliff:g>\" مع الملف الشخصي للعمل."</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"تثبيت <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"إزالة تثبيت <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"تعديل"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + ملف واحد}zero{{file_name} + # ملف}two{{file_name} + ملفان}few{{file_name} + # ملفات}many{{file_name} + # ملفًا}other{{file_name} + # ملف}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ ملف واحد}zero{+ # ملف}two{+ ملفان}few{+ # ملفات}many{+ # ملفًا}other{+ # ملف}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"جارٍ مشاركة النص"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"جارٍ مشاركة الرابط"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{جارٍ مشاركة صورة واحدة}zero{جارٍ مشاركة # صورة}two{جارٍ مشاركة صورتَين}few{جارٍ مشاركة # صور}many{جارٍ مشاركة # صورة}other{جارٍ مشاركة # صورة}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{جارٍ مشاركة فيديو واحد}zero{جارٍ مشاركة # فيديو}two{جارٍ مشاركة فيديوهَين}few{جارٍ مشاركة # فيديوهات}many{جارٍ مشاركة # فيديو}other{جارٍ مشاركة # فيديو}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{جارٍ مشاركة عنصر واحد}zero{جارٍ مشاركة # عنصر}two{جارٍ مشاركة عنصرَين}few{جارٍ مشاركة # عناصر}many{جارٍ مشاركة # عنصرًا}other{جارٍ مشاركة # عنصر}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"مشاركة صورة بنص"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"مشاركة صورة برابط"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"ما مِن أشخاص مقترحين للمشاركة معهم."</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"قائمة التطبيقات"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"‏لم يتم منح هذا التطبيق إذن تسجيل، ولكن يمكنه تسجيل الصوت من خلال جهاز USB هذا."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"شخصي"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"للعمل"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"عرض المحتوى الشخصي"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"عرض محتوى العمل"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"حظر مشرف تكنولوجيا المعلومات مشاركة المحتوى"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"لا يمكن مشاركة هذا المحتوى مع تطبيقات العمل."</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"لا يمكن فتح هذا المحتوى باستخدام تطبيقات العمل."</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"لا يمكن مشاركة هذا المحتوى مع التطبيقات الشخصية."</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"لا يمكن فتح هذا المحتوى باستخدام التطبيقات الشخصية."</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"الملف الشخصي للعمل متوقف مؤقتًا."</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"انقر لتفعيل الميزة"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"ما مِن تطبيقات عمل."</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"ما مِن تطبيقات شخصية."</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"هل تريد فتح <xliff:g id="APP">%s</xliff:g> في ملفك الشخصي؟"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"هل تريد فتح <xliff:g id="APP">%s</xliff:g> في ملفك الشخصي للعمل؟"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"استخدام المتصفّح الشخصي"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"استخدام متصفّح العمل"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"استثناء النص"</string>
+ <string name="include_text" msgid="642280283268536140">"تضمين النص"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"استثناء الرابط"</string>
+ <string name="include_link" msgid="827855767220339802">"تضمين الرابط"</string>
+</resources>
diff --git a/java/res/values-as/strings.xml b/java/res/values-as/strings.xml
new file mode 100644
index 00000000..cd294ec4
--- /dev/null
+++ b/java/res/values-as/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"এয়া ব্যৱহাৰ কৰি কার্য সম্পূর্ণ কৰক"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g>এ ব্যৱহাৰ কৰি কাৰ্য সম্পূৰ্ণ কৰক"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"কাৰ্য সম্পূৰ্ণ কৰক"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"ইয়াৰ জৰিয়তে খোলক"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g>ৰ জৰিয়তে খোলক"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"খোলক"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> লিংকসমূহ ইয়াৰ জৰিয়তে খোলক"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"লিংকসমূহ ইয়াৰ জৰিয়তে খোলক"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"লিংকসমূহ <xliff:g id="APPLICATION">%1$s</xliff:g>ৰ জৰিয়তে খোলক"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> লিংকসমূহ <xliff:g id="APPLICATION">%2$s</xliff:g>ৰ জৰিয়তে খোলক"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"এক্সেছ দিয়ক"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"ইয়াৰ দ্বাৰা সম্পাদনা কৰক"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g>ৰ জৰিয়তে সম্পাদনা কৰক"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"সম্পাদনা কৰক"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"শ্বেয়াৰ কৰক"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g>ৰ জৰিয়তে শ্বেয়াৰ কৰক"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"শ্বেয়াৰ কৰক"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"ইয়াৰ মাধ্য়মেৰে প্ৰেৰণ কৰক"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> ব্যৱহাৰ কৰি পঠিয়াওক"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"প্রেৰণ কৰক"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"এটা হ\'ম এপ্ বাছনি কৰক"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g>ক গৃহ স্ক্ৰীন হিচাপে ব্যৱহাৰ কৰক"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"প্ৰতিচ্ছবি তোলক"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"ইয়াৰ সৈতে প্ৰতিচ্ছবি তোলক"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g>ৰ জৰিয়তে প্ৰতিচ্ছবি তোলক"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"প্ৰতিচ্ছবি তোলক"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"এটা পৃথক এপ্ ব্যৱহাৰ কৰক"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"কোনো কাৰ্য বাছনি কৰক"</string>
+ <string name="noApplications" msgid="1139487441772284671">"কোনো এপে এই কাৰ্য কৰিব নোৱাৰে।"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"আপুনি আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলৰ বাহিৰত এই এপ্‌টো ব্যৱহাৰ কৰি আছে"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"আপুনি আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলৰ ভিতৰত এই এপ্‌টো ব্যৱহাৰ কৰি আছে"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"সদায়"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"মাত্ৰ এবাৰ"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g>এ কৰ্মস্থানৰ প্ৰ’ফাইল সমৰ্থন নকৰে"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> পিন কৰক"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g>ক আনপিন কৰক"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"সম্পাদনা কৰক"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # টা ফাইল}one{{file_name} + # টা ফাইল}other{{file_name} + # টা ফাইল}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # টা ফাইল}one{+ # টা ফাইল}other{+ # টা ফাইল}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"পাঠ শ্বেয়াৰ কৰি থকা হৈছে"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"লিংক শ্বেয়াৰ কৰি থকা হৈছে"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{প্ৰতিচ্ছবি শ্বেয়াৰ কৰি থকা হৈছে}one{# খন প্ৰতিচ্ছবি শ্বেয়াৰ কৰি থকা হৈছে}other{# খন প্ৰতিচ্ছবি শ্বেয়াৰ কৰি থকা হৈছে}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{ভিডিঅ’ শ্বেয়াৰ কৰি থকা হৈছে}one{# টা ভিডিঅ’ শ্বেয়াৰ কৰি থকা হৈছে}other{# টা ভিডিঅ’ শ্বেয়াৰ কৰি থকা হৈছে}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# টা বস্তু শ্বেয়াৰ কৰি থকা হৈছে}one{# টা বস্তু শ্বেয়াৰ কৰি থকা হৈছে}other{# টা বস্তু শ্বেয়াৰ কৰি থকা হৈছে}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"পাঠেৰে প্ৰতিচ্ছবি শ্বেয়াৰ কৰি হৈছে"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"লিংকৰে প্ৰতিচ্ছবি শ্বেয়াৰ কৰি হৈছে"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"শ্বেয়াৰ কৰিবলৈ চুপাৰিছ কৰা কোনো লোক নাই"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"এপ্‌সমূহৰ সূচী"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"এই এপ্‌টোক ৰেকর্ড কৰাৰ অনুমতি দিয়া হোৱা নাই কিন্তু ই এই ইউএছবি ডিভাইচটোৰ জৰিয়তে অডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"ব্যক্তিগত"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"কৰ্মস্থান"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"ব্যক্তিগত ভিউ"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"কৰ্মস্থানৰ ভিউ"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"আপোনাৰ আইটি প্ৰশাসকে অৱৰোধ কৰিছে"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"এই সমল কৰ্মস্থানৰ এপৰ সৈতে শ্বেয়াৰ কৰিব নোৱাৰি"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"এই সমল কৰ্মস্থানৰ এপৰ জৰিয়তে খুলিব নোৱাৰি"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"এই সমল ব্যক্তিগত এপৰ সৈতে শ্বেয়াৰ কৰিব নোৱাৰি"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"এই সমল ব্যক্তিগত এপৰ জৰিয়তে খুলিব নোৱাৰি"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"কৰ্মস্থানৰ প্ৰ\'ফাইলটো পজ কৰা আছে"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"অন কৰিবলৈ টিপক"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"কোনো কৰ্মস্থানৰ এপ্‌ নাই"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"কোনো ব্যক্তিগত এপ্‌ নাই"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"আপোনাৰ ব্যক্তিগত প্ৰ’ফাইলত <xliff:g id="APP">%s</xliff:g> খুলিবনে?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"আপোনাৰ কর্মস্থানৰ প্ৰ\'ফাইলত <xliff:g id="APP">%s</xliff:g> খুলিবনে?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"ব্যক্তিগত ব্ৰাউজাৰ ব্যৱহাৰ কৰক"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"কৰ্মস্থানৰ ব্ৰাউজাৰ ব্যৱহাৰ কৰক"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"পাঠ বহিৰ্ভূত কৰক"</string>
+ <string name="include_text" msgid="642280283268536140">"পাঠ অন্তৰ্ভুক্ত কৰক"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"লিংক বহিৰ্ভূত কৰক"</string>
+ <string name="include_link" msgid="827855767220339802">"লিংক অন্তৰ্ভুক্ত কৰক"</string>
+</resources>
diff --git a/java/res/values-az/strings.xml b/java/res/values-az/strings.xml
new file mode 100644
index 00000000..3c66f5c0
--- /dev/null
+++ b/java/res/values-az/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Əməliyyatı tamamlayın:"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> istifadə etməklə əməliyyatı tamamlayın"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Əməliyyatı tamamlayın"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Bununla açın"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> ilə açın"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Açın"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> linklərini belə açın:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Linkləri belə açın:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Linkləri <xliff:g id="APPLICATION">%1$s</xliff:g> ilə açın"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> linklərini <xliff:g id="APPLICATION">%2$s</xliff:g> ilə açın"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Giriş imkanı verin"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Bununla düzəliş edin:"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> ilə redaktə edin"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Redaktə edin"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Paylaşın"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> ilə paylaşın"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Paylaşın"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"İstifadə edərək göndərin"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> istifadə edərək göndərin"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Göndər"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Əsas tətbiqi seçin"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Ana ekran tətbiqi kimi <xliff:g id="APP">%1$s</xliff:g> istifadə edin"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Şəkil Çəkimi"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Təsviri bununla çəkin"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> ilə şəkil çəkin"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Şəkil Çəkimi"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Başqa tətbiq istifadə edin"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Əməliyyatın seçilməsi"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Heç bir tətbiq bu əməliyyatı apara bilmir."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Bu tətbiqi iş profilinizdən kənarda istifadə edirsiniz"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Bu tətbiqi iş profilinizdə istifadə edirsiniz"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Həmişə"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Sadəcə bir dəfə"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> iş profilini dəstəkləmir"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Bərkidin: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"İşarələməyin: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Redaktə edin"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # fayl}other{{file_name} + # fayl}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # fayl}other{+ # fayl}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Mətn paylaşılır"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Link paylaşılır"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Şəkil paylaşılır}other{# şəkil paylaşılır}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Video paylaşılır}other{# video paylaşılır}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# element paylaşılır}other{# element paylaşılır}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Şəkil mətn ilə paylaşılır"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Şəkil link ilə paylaşılır"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Paylaşmaq üçün tövsiyə edilən bir kimsə yoxdur"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Tətbiq siyahısı"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Tətbiqə qeydə almaq icazəsi verilməsə də, bu USB vasitəsilə səsi qeydə ala bilər."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Şəxsi"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"İş"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Şəxsi məzmuna baxış"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"İş məzmununa baxış"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"IT admininiz tərəfindən bloklanıb"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Bu kontenti iş tətbiqləri ilə paylaşmaq mümkün deyil"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Bu kontenti iş tətbiqləri ilə açmaq mümkün deyil"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Bu kontenti şəxsi tətbiqlər ilə paylaşmaq mümkün deyil"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Bu kontenti şəxsi tətbiqlər ilə açmaq mümkün deyil"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"İş profilinə fasilə verilib"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Aktiv etmək üçün toxunun"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"İş tətbiqi yoxdur"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Şəxsi tətbiq yoxdur"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Şəxsi profilinizdə <xliff:g id="APP">%s</xliff:g> tətbiqi açılsın?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"İş profilinizdə <xliff:g id="APP">%s</xliff:g> tətbiqi açılsın?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Şəxsi brauzerdən istifadə edin"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"İş brauzerindən istifadə edin"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Mətni istisna edin"</string>
+ <string name="include_text" msgid="642280283268536140">"Mətn daxil edin"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Keçidi istisna edin"</string>
+ <string name="include_link" msgid="827855767220339802">"Keçid daxil edin"</string>
+</resources>
diff --git a/java/res/values-b+sr+Latn/strings.xml b/java/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 00000000..83c55e29
--- /dev/null
+++ b/java/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Dovrši radnju preko"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Dovršite radnju pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Završi radnju"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Otvorite pomoću"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Otvorite pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Otvori"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Otvarajte <xliff:g id="HOST">%1$s</xliff:g> linkove pomoću"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Otvaraj linkove pomoću"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Otvarajte linkove pomoću aplikacije <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Otvarajte <xliff:g id="HOST">%1$s</xliff:g> linkove pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Dozvoli pristup"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Izmenite pomoću"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Izmenite pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Izmeni"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Delite"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Delite pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Deli"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Pošaljite pomoću:"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Pošaljite pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Pošalji"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Izaberite aplikaciju za početnu stranicu"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Koristite <xliff:g id="APP">%1$s</xliff:g> za početnu"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Snimite sliku"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Snimite sliku pomoću aplikacije"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Snimite sliku pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Snimite sliku"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Koristite drugu aplikaciju"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Odaberite radnju"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Nijedna aplikacija ne može da obavlja ovu radnju."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Koristite ovu aplikaciju izvan poslovnog profila"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Koristite ovu aplikaciju na poslovnom profilu"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Uvek"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Samo jednom"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ne podržava poslovni profil"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Zakačite osobu <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Otkači aplikaciju <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Izmeni"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # fajl}one{{file_name} + # fajl}few{{file_name} + # fajla}other{{file_name} + # fajlova}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{i još # fajl}one{i još # fajl}few{i još # fajla}other{i još # fajlova}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Deli se tekst"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Deli se link"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Deli se slika}one{Deli se # slika}few{Dele se # slike}other{Deli se # slika}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Deli se video}one{Deli se # video}few{Dele se # video snimka}other{Deli se # video snimaka}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Deli se # stavka}one{Deli se # stavka}few{Dele se # stavke}other{Deli se # stavki}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Deli se slika sa tekstom"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Deli se slika sa linkom"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Nema preporučenih ljudi za deljenje"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lista aplikacija"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Ova aplikacija nema dozvolu za snimanje, ali bi mogla da snima zvuk pomoću ovog USB uređaja."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Lično"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Poslovno"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Lični prikaz"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Prikaz za posao"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blokira IT administrator"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Ovaj sadržaj ne može da se deli pomoću poslovnih aplikacija"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Ovaj sadržaj ne može da se otvara pomoću poslovnih aplikacija"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Ovaj sadržaj ne može da se deli pomoću ličnih aplikacija"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Ovaj sadržaj ne može da se otvara pomoću ličnih aplikacija"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Poslovni profil je pauziran"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Dodirnite da biste uključili"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Nema poslovnih aplikacija"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Nema ličnih aplikacija"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Želite da na ličnom profilu otvorite: <xliff:g id="APP">%s</xliff:g>?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Želite da na poslovnom profilu otvorite: <xliff:g id="APP">%s</xliff:g>?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Koristi lični pregledač"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Koristi poslovni pregledač"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Isključi tekst"</string>
+ <string name="include_text" msgid="642280283268536140">"Uvrsti tekst"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Isključi link"</string>
+ <string name="include_link" msgid="827855767220339802">"Uvrsti link"</string>
+</resources>
diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml
new file mode 100644
index 00000000..a24b4a36
--- /dev/null
+++ b/java/res/values-be/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Завяршыць дзеянне з дапамогай"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Выканаць дзеянне з дапамогай праграмы \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Завяршыць дзеянне"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Адкрыць з дапамогай"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Адкрыць у праграме \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Адкрыць"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Адкрываць спасылкі <xliff:g id="HOST">%1$s</xliff:g> з дапамогай"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Адкрываць спасылкі з дапамогай"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Адкрываць спасылкі з дапамогай праграмы \"<xliff:g id="APPLICATION">%1$s</xliff:g>\""</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Адкрываць спасылкі <xliff:g id="HOST">%1$s</xliff:g>з дапамогай праграмы \"<xliff:g id="APPLICATION">%2$s</xliff:g>\""</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Даць доступ"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Рэдагаваць з дапамогай"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Рэдагаваць з дапамогай праграмы \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Рэдагаваць"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Абагуліць"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Абагуліць праз праграму \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Абагуліць"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Адправіць з дапамогай"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Адправіць з дапамогай праграмы \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Адправiць"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Выберыце праграму Галоўнай старонкі"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Выкарыстоўваць праграму \"<xliff:g id="APP">%1$s</xliff:g>\" для галоўнага экрана"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Зрабіць здымак"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Зрабіць здымак з дапамогай"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Зрабіць здымак з дапамогай праграмы \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Зрабіць здымак"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Выкарыстоўваць іншую праграму"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Выберыце дзеянне"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Няма прыкладанняў, якія могуць выконваць гэты працэс."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Вы выкарыстоўваеце гэту праграму па-за межамі свайго працоўнага профілю"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Вы выкарыстоўваеце гэту праграму ў сваім працоўным профілі"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Заўсёды"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Толькі адзін раз"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> не падтрымлівае працоўны профіль"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Замацаваць праграму \"<xliff:g id="LABEL">%1$s</xliff:g>\""</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Адмацаваць праграму \"<xliff:g id="LABEL">%1$s</xliff:g>\""</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Рэдагаваць"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # файл}one{{file_name} + # файл}few{{file_name} + # файлы}many{{file_name} + # файлаў}other{{file_name} + # файла}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # файл}one{+ # файл}few{+ # файлы}many{+ # файлаў}other{+ # файла}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Абагульванне тэксту"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Абагульванне спасылкі"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Абагульванне відарыса}one{Абагульванне # відарыса}few{Абагульванне # відарысаў}many{Абагульванне # відарысаў}other{Абагульванне # відарыса}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Абагульванне відэа}one{Абагульванне # відэа}few{Абагульванне # відэа}many{Абагульванне # відэа}other{Абагульванне # відэа}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Абагульванне # аб\'екта}one{Абагульванне # аб\'екта}few{Абагульванне # аб\'ектаў}many{Абагульванне # аб\'ектаў}other{Абагульванне # аб\'екта}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Абагульванне відарыса з тэкстам"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Абагульванне відарыса са спасылкай"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Няма кантактаў, з якімі рэкамендуецца абагульваць змесціва"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Спіс праграм"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"У гэтай праграмы няма дазволу на запіс, аднак яна зможа запісваць аўдыя праз гэту USB-прыладу."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Асабісты"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Працоўны"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Прагляд асабістага змесціва"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Прагляд працоўнага змесціва"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Заблакіравана вашым ІТ-адміністратарам"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Не ўдалося абагуліць гэта змесціва з працоўнымі праграмамі"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Не ўдалося адкрыць гэта змесціва з дапамогай працоўных праграм"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Не ўдалося абагуліць гэта змесціва з асабістымі праграмамі"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Не ўдалося адкрыць гэта змесціва з дапамогай асабістых праграм"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Працоўны профіль прыпынены"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Націсніце, каб уключыць"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Няма працоўных праграм"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Няма асабістых праграм"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Адкрыць праграму \"<xliff:g id="APP">%s</xliff:g>\" з выкарыстаннем асабістага профілю?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Адкрыць праграму \"<xliff:g id="APP">%s</xliff:g>\" з выкарыстаннем працоўнага профілю?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Скарыстаць асабісты браўзер"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Скарыстаць працоўны браўзер"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Выдаліць тэкст"</string>
+ <string name="include_text" msgid="642280283268536140">"Дадаць тэкст"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Выдаліць спасылку"</string>
+ <string name="include_link" msgid="827855767220339802">"Дадаць спасылку"</string>
+</resources>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
new file mode 100644
index 00000000..44892051
--- /dev/null
+++ b/java/res/values-bg/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Изпълняване на действието чрез"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Изпълняване на действието чрез <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Изпълняване на действието"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Отваряне чрез"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Отваряне чрез <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Отваряне"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Отваряне на връзките от <xliff:g id="HOST">%1$s</xliff:g> посредством"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Отваряне на връзките посредством"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Отваряне на връзките посредством <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Отваряне на връзките от <xliff:g id="HOST">%1$s</xliff:g> посредством <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Даване на достъп"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Редактиране чрез"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Редактиране чрез <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Редактиране"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Споделяне"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Споделяне чрез <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Споделяне"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Изпращане посредством"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Изпращане посредством <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Изпращане"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Избиране на начално приложение"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Използване на <xliff:g id="APP">%1$s</xliff:g> като начално приложение"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Заснемане на изображение"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Заснемане на изображение с/ъс"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Заснемане на изображение чрез <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Заснемане на изображение"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Използване на друго приложение"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Изберете действие"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Това действие не може да се изпълни от нито едно приложение."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Използвате това приложение извън служебния си потребителски профил"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Използвате това приложение в служебния си потребителски профил"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Винаги"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Само веднъж"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> не поддържа служебни потребителски профили"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Фиксиране на <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Премахване на фиксирането на <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Редактиране"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # файл}other{{file_name} + # файла}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # файл}other{+ # файла}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Текстът се споделя"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Връзката се споделя"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Изображението се споделя}other{# изображения се споделят}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Видеоклипът се споделя}other{# видеоклипа се споделят}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# елемент се споделя}other{# елемента се споделят}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Изобр. се споделя с текст"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Изобр. се споделя с връзка"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Няма препоръки за хора, с които да споделяте"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Списък с приложения"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Приложението няма разрешение за записване, но може да записва звук чрез това USB устройство."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Лични"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Служебни"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Личен изглед"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Служебен изглед"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Блокирано от системния ви администратор"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Това съдържание не може да се споделя със служебни приложения"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Това съдържание не може да се отваря със служебни приложения"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Това съдържание не може да се споделя с лични приложения"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Това съдържание не може да се отваря с лични приложения"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Служебният потребителски профил е поставен на пауза"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Докоснете за включване"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Няма подходящи служебни приложения"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Няма подходящи лични приложения"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Искате ли да отворите <xliff:g id="APP">%s</xliff:g> в личния си потребителски профил?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Искате ли да отворите <xliff:g id="APP">%s</xliff:g> в служебния си потребителски профил?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Използване на личния браузър"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Използване на служебния браузър"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Изключване на текста"</string>
+ <string name="include_text" msgid="642280283268536140">"Включване на текста"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Изключване на връзката"</string>
+ <string name="include_link" msgid="827855767220339802">"Включване на връзката"</string>
+</resources>
diff --git a/java/res/values-bn/strings.xml b/java/res/values-bn/strings.xml
new file mode 100644
index 00000000..22438fbf
--- /dev/null
+++ b/java/res/values-bn/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"এটি ব্যবহার করে ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> ব্যবহার করে অ্যাকশন সম্পূর্ণ করুন"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"এর মাধ্যমে খুলুন"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> দিয়ে খুলুন"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"খুলুন"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"এই ব্রাউজারে <xliff:g id="HOST">%1$s</xliff:g> লিঙ্কটি খুলুন"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"এই ব্রাউজারে লিঙ্কটি খুলুন"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g>-এ লিঙ্ক খুলুন"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="APPLICATION">%2$s</xliff:g>-এ <xliff:g id="HOST">%1$s</xliff:g> লিঙ্কটি খুলুন"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"অ্যাক্সেস দিন"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"এর মাধ্যমে সম্পাদনা করুন"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> দিয়ে এডিট করুন"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"সম্পাদনা করুন"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"শেয়ার করুন"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g>-এর সাথে শেয়ার করুন"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"শেয়ার করুন"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"এটি ব্যবহার করে পাঠান"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> ব্যবহার করে পাঠান"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"পাঠান"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"একটি হোম অ্যাপ্লিকেশন বেছে নিন"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"হোম হিসেবে <xliff:g id="APP">%1$s</xliff:g> ব্যবহার করুন"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"ছবি তুলুন"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"এই দিয়ে ছবি তুলুন"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> দিয়ে ছবি তুলুন"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"ছবি তুলুন"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"আলাদা কোনো অ্যাপ্লিকেশান ব্যবহার করুন"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"একটি অ্যাকশন বেছে নিন"</string>
+ <string name="noApplications" msgid="1139487441772284671">"কোনো অ্যাপ্লিকেশানই এই ক্রিয়া সঞ্চালন করতে পারবে না৷"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"আপনি এই অ্যাপ্লিকেশানটি আপনার কর্মস্থলের প্রোফাইলের বাইরে ব্যবহার করছেন"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"আপনি এই অ্যাপ্লিকেশানটি আপনার কর্মস্থলের প্রোফাইলে ব্যবহার করছেন"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"সবসময়"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"শুধু একবার"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"অফিস প্রোফাইলে <xliff:g id="APP">%1$s</xliff:g> কাজ করে না"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> অ্যাপ পিন করুন"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> অ্যাপ আনপিন করুন"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"এডিট করুন"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} ও আরও #টি ফাইল}one{{file_name} ও আরও #টি ফাইল}other{{file_name} ও আরও #টি ফাইল}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{আরও #টি ফাইল}one{আরও #টি ফাইল}other{আরও #টি ফাইল}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"টেক্সট শেয়ার করা হচ্ছে"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"লিঙ্ক শেয়ার করা হচ্ছে"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{ছবি শেয়ার করা হচ্ছে}one{#টি ছবি শেয়ার করা হচ্ছে}other{#টি ছবি শেয়ার করা হচ্ছে}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{ভিডিও শেয়ার করা হচ্ছে}one{#টি ভিডিও শেয়ার করা হচ্ছে}other{#টি ভিডিও শেয়ার করা হচ্ছে}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{#টি আইটেম শেয়ার করা হচ্ছে}one{#টি আইটেম শেয়ার করা হচ্ছে}other{#টি আইটেম শেয়ার করা হচ্ছে}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"ছবি টেক্সটের মাধ্যমে শেয়ার করা হচ্ছে"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"ছবি লিঙ্কের মাধ্যমে শেয়ার করা হচ্ছে"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"শেয়ার করার জন্য সাজেস্ট করার মতো কেউ নেই"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"অ্যাপের তালিকা"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"এই অ্যাপকে রেকর্ড করার অনুমতি দেওয়া হয়নি কিন্তু USB ডিভাইসের মাধ্যমে সেটি অডিও রেকর্ড করতে পারে।"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"ব্যক্তিগত"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"অফিস"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"ব্যক্তিগত ভিউ"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"অফিসের ভিউ"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"আপনার আইটি অ্যাডমিন ব্লক করেছেন"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"অফিসের অ্যাপে এই কন্টেন্ট শেয়ার করা যাবে না"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"অফিসের অ্যাপে এই খোলা যাবে না"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"ব্যক্তিগত অ্যাপে এই কন্টেন্ট শেয়ার করা যাবে না"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"ব্যক্তিগত অ্যাপে এই কন্টেন্ট খোলা যাবে না"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"অফিস প্রোফাইল বন্ধ করা আছে"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"চালু করতে ট্যাপ করুন"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"এর জন্য কোনও অফিস অ্যাপ নেই"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"ব্যক্তিগত অ্যাপে দেখা যাবে না"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"আপনার ব্যক্তিগত প্রোফাইল থেকে <xliff:g id="APP">%s</xliff:g> খুলবেন?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"আপনার অফিস প্রোফাইল থেকে <xliff:g id="APP">%s</xliff:g> খুলবেন?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"ব্যক্তিগত ব্রাউজার ব্যবহার করুন"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"অফিস ব্রাউজার ব্যবহার করুন"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"টেক্সট বাদ দিন"</string>
+ <string name="include_text" msgid="642280283268536140">"টেক্সট যোগ করুন"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"লিঙ্ক বাদ দিন"</string>
+ <string name="include_link" msgid="827855767220339802">"লিঙ্ক যোগ করুন"</string>
+</resources>
diff --git a/java/res/values-bs/strings.xml b/java/res/values-bs/strings.xml
new file mode 100644
index 00000000..f4b54c7b
--- /dev/null
+++ b/java/res/values-bs/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Završite radnju pomoću aplikacije"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Završavanje radnje pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Izvršiti akciju"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Otvori koristeći"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Otvaranje pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Otvori"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Otvaranje <xliff:g id="HOST">%1$s</xliff:g> linkova pomoću preglednika/aplikacije"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Otvaranje linkova pomoću preglednika"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Otvaranje linkova pomoću preglednika <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Otvaranje <xliff:g id="HOST">%1$s</xliff:g> linkova pomoću preglednika <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Dozvoli pristup"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Uredi koristeći"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Uređivanje pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Uredi"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Dijeli"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Dijeljenje putem aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Dijeli"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Pošalji koristeći"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Slanje pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Pošalji"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Odaberi glavnu aplikaciju"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Korištenje aplikacije <xliff:g id="APP">%1$s</xliff:g> kao početne"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Snimanje slike"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Snimanje slike koristeći"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Snimanje slike pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Snimanje slike"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Koristi drugu aplikaciju"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Odaberite radnju"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Nijedna aplikacija ne može izvršiti ovu akciju."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Aplikaciju koristite van poslovnog profila"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Aplikaciju koristite u poslovnom profilu"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Uvijek"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Samo ovaj put"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ne podržava radni profil"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Zakači aplikaciju <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Otkači aplikaciju <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Uredi"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} i # fajl}one{{file_name} i # fajl}few{{file_name} i # fajla}other{{file_name} i # fajlova}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{i još # fajl}one{i još # fajl}few{i još # fajla}other{i još # fajlova}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Dijeljenje teksta"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Dijeljenje linka"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Dijeljenje slike}one{Dijeljenje # slike}few{Dijeljenje # slike}other{Dijeljenje # slika}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Dijeljenje videozapisa}one{Dijeljenje # videozapisa}few{Dijeljenje # videozapisa}other{Dijeljenje # videozapisa}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Dijeljenje # stavke}one{Dijeljenje # stavke}few{Dijeljenje # stavke}other{Dijeljenje # stavki}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Dijeljenje slike s tekstom"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Dijeljenje slike s linkom"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Nema preporučenih osoba s kojima biste dijelili"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lista aplikacija"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Ovoj aplikaciji nije dato odobrenje za snimanje, ali može snimati zvuk putem ovog USB uređaja."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Lično"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Posao"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Prikaz ličnog sadržaja"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Prikaz poslovnog sadržaja"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blokirao je vaš IT administrator"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Ovaj sadržaj nije moguće dijeliti pomoću poslovnih aplikacija"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Ovaj sadržaj nije moguće otvoriti pomoću poslovnih aplikacija"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Ovaj sadržaj nije moguće dijeliti pomoću ličnih aplikacija"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Ovaj sadržaj nije moguće otvoriti pomoću ličnih aplikacija"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Radni profil je pauziran"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Dodirnite da uključite"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Nema poslovnih aplikacija"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Nema ličnih aplikacija"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Otvoriti aplikaciju <xliff:g id="APP">%s</xliff:g> na ličnom profilu?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Otvoriti aplikaciju <xliff:g id="APP">%s</xliff:g> na radnom profilu?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Koristi lični preglednik"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Koristi poslovni preglednik"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Izuzmi tekst"</string>
+ <string name="include_text" msgid="642280283268536140">"Uključi tekst"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Izuzmi link"</string>
+ <string name="include_link" msgid="827855767220339802">"Uključi link"</string>
+</resources>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
new file mode 100644
index 00000000..97aeeddc
--- /dev/null
+++ b/java/res/values-ca/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Completa l\'acció mitjançant"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Completa l\'acció mitjançant <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Completa l\'acció"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Obre amb"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Obre amb <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Obre"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Obre els enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Obre els enllaços amb"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Obre els enllaços amb <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Obre els enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Dona accés"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Edita amb"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Edita a <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Edita"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Comparteix"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Comparteix amb <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Comparteix"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Envia mitjançant"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Envia mitjançant <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Envia"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Seleccionar una aplicació Inici"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Utilitza <xliff:g id="APP">%1$s</xliff:g> com a aplicació d\'inici"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Captura la imatge"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Captura la imatge amb"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Captura la imatge amb <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Captura la imatge"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Fes servir una altra aplicació"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Selecciona una acció"</string>
+ <string name="noApplications" msgid="1139487441772284671">"No hi ha cap aplicació que pugui fer aquesta acció."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Estàs utilitzant aquesta aplicació fora del perfil de treball."</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Estàs utilitzant l\'aplicació al perfil de treball."</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Sempre"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Només una vegada"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> no admet perfils de treball"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fixa <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"No fixis <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Edita"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} i # fitxer}many{{file_name} i # fitxers}other{{file_name} i # fitxers}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # fitxer}many{+ # de fitxers}other{+ # fitxers}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"S\'està compartint text"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"S\'està compartint l\'enllaç"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{S\'està compartint una imatge}many{S\'estan compartint # d\'imatges}other{S\'estan compartint # imatges}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{S\'està compartint un vídeo}many{S\'estan compartint # de vídeos}other{S\'estan compartint # vídeos}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{S\'està compartint # element}many{S\'estan compartint # d\'elements}other{S\'estan compartint # elements}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Compartint imatge amb text"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Compartint imatge i enllaç"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"No hi ha cap suggeriment de persones amb qui compartir"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Llista d\'aplicacions"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Aquesta aplicació no té permís de gravació, però pot capturar àudio a través d\'aquest dispositiu USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Feina"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Visualització personal"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Visualització de treball"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Bloquejat per l\'administrador de TI"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"No es pot compartir aquest contingut amb aplicacions de treball"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"No es pot obrir aquest contingut amb aplicacions de treball"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"No es pot compartir aquest contingut amb aplicacions personals"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"No es pot obrir aquest contingut amb aplicacions personals"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"El perfil de treball està en pausa"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Toca per activar"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Cap aplicació de treball"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Cap aplicació personal"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Vols obrir <xliff:g id="APP">%s</xliff:g> al teu perfil personal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Vols obrir <xliff:g id="APP">%s</xliff:g> al teu perfil de treball?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Utilitza el navegador personal"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Utilitza el navegador de treball"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Exclou text"</string>
+ <string name="include_text" msgid="642280283268536140">"Inclou text"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Exclou l\'enllaç"</string>
+ <string name="include_link" msgid="827855767220339802">"Inclou l\'enllaç"</string>
+</resources>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
new file mode 100644
index 00000000..e15b1b00
--- /dev/null
+++ b/java/res/values-cs/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Dokončit akci pomocí aplikace"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Dokončit akci pomocí aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Dokončit akci"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Otevřít v aplikaci"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Otevřít v aplikaci <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Otevřít"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Odkazy <xliff:g id="HOST">%1$s</xliff:g> otevírat pomocí aplikace"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Odkazy otevírat pomocí aplikace"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Odkazy otevírat pomocí aplikace <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Odkazy <xliff:g id="HOST">%1$s</xliff:g> otevírat pomocí aplikace <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Udělit přístup"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Upravit v aplikaci"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Upravit pomocí editoru <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Upravit"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Sdílet"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Sdílet s aplikací <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Sdílet"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Odeslat pomocí aplikace"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Odeslat pomocí aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Odeslat"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Výběr aplikace na plochu"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Použít aplikaci <xliff:g id="APP">%1$s</xliff:g> jako plochu"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Vyfotit"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Vyfotit pomocí aplikace"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Vyfotit pomocí aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Vyfotit"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Použít jinou aplikaci"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Vyberte akci"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Tuto činnost nemohou provádět žádné aplikace."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Tuto aplikaci používáte mimo svůj pracovní profil."</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Tuto aplikaci používáte v pracovním profilu"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Vždy"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Pouze jednou"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"Aplikace <xliff:g id="APP">%1$s</xliff:g> nepodporuje pracovní profil"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Připnout <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Odepnout: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Upravit"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # soubor}few{{file_name} + # soubory}many{{file_name} + # souboru}other{{file_name} + # souborů}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # soubor}few{+ # soubory}many{+ # souboru}other{+ # souborů}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Sdílení textu"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Sdílení odkazu"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Sdílení obrázku}few{Sdílení # obrázků}many{Sdílení # obrázku}other{Sdílení # obrázků}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Sdílení videa}few{Sdílení # videí}many{Sdílení # videa}other{Sdílení # videí}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Sdílení # položky}few{Sdílení # položek}many{Sdílení # položky}other{Sdílení # položek}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Sdílení obrázku s textem"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Sdílení obrázku s odkazem"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Žádní doporučení lidé, s nimiž můžete sdílet"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Seznam aplikací"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Tato aplikace nemá oprávnění k nahrávání, ale může zaznamenávat zvuk prostřednictvím tohoto zařízení USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Osobní"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Pracovní"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Osobní zobrazení"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Pracovní zobrazení"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blokováno administrátorem IT"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Tento obsah nelze sdílet pomocí pracovních aplikací"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Tento obsah nelze otevřít pomocí pracovních aplikací"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Tento obsah nelze sdílet pomocí osobních aplikací"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Tento obsah nelze otevřít pomocí osobních aplikací"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Pracovní profil je pozastaven"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Klepnutím ho zapnete"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Žádné pracovní aplikace"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Žádné osobní aplikace"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Otevřít aplikaci <xliff:g id="APP">%s</xliff:g> v osobním profilu?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Otevřít aplikaci <xliff:g id="APP">%s</xliff:g> v pracovním profilu?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Použít osobní prohlížeč"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Použít pracovní prohlížeč"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Vyloučit text"</string>
+ <string name="include_text" msgid="642280283268536140">"Zahrnout text"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Vyloučit odkaz"</string>
+ <string name="include_link" msgid="827855767220339802">"Zahrnout odkaz"</string>
+</resources>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
new file mode 100644
index 00000000..ef66baeb
--- /dev/null
+++ b/java/res/values-da/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Brug"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Udfør handlingen ved hjælp af <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Afslut handling"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Åbn med"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Åbn med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Åbn"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Åbn <xliff:g id="HOST">%1$s</xliff:g>-links med"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Åbn links med"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Åbn links med <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Åbn <xliff:g id="HOST">%1$s</xliff:g>-links med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Giv adgang"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Rediger med"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Rediger med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Rediger"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Del"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Del med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Del"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Send via"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Send via <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Send"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Vælg en startapp"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Brug <xliff:g id="APP">%1$s</xliff:g> som Hjem"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Tag billede"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Tag billede med"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Tag billede med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Tag billede"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Brug en anden app"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Vælg en handling"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Der er ingen apps, der kan foretage denne handling."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Du bruger denne app uden for din arbejdsprofil"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Du bruger denne app i din arbejdsprofil"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Altid"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Kun én gang"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> understøtter ikke arbejdsprofilen"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fastgør <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Frigør <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Rediger"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # fil}one{{file_name} + # fil}other{{file_name} + # filer}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # fil}one{+ # fil}other{+ # filer}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Deler tekst"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Deler link"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Deler billede}one{Deler # billede}other{Deler # billeder}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Deler video}one{Deler # video}other{Deler # videoer}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Deler # element}one{Deler # element}other{Deler # elementer}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Deler billede med tekst"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Deler billede med et link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Der er ingen anbefalede personer at dele med"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Liste over apps"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Denne app har ikke fået tilladelse til at optage, men optager muligvis lyd via denne USB-enhed."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personlig"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Arbejde"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Visningen Personligt"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Visningen Arbejde"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blokeret af din it-administrator"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Dette indhold kan ikke deles med arbejdsapps"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Dette indhold kan ikke åbnes med arbejdsapps"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Dette indhold kan ikke deles med personlige apps"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Dette indhold kan ikke åbnes med personlige apps"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Arbejdsprofilen er sat på pause"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Tryk for at aktivere"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Der er ingen arbejdsapps"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Der er ingen personlige apps"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Vil du åbne <xliff:g id="APP">%s</xliff:g> på din personlige profil?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Vil du åbne <xliff:g id="APP">%s</xliff:g> på din arbejdsprofil?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Brug personlig browser"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Brug arbejdsbrowser"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Ekskluder tekst"</string>
+ <string name="include_text" msgid="642280283268536140">"Inkluder tekst"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Ekskluder link"</string>
+ <string name="include_link" msgid="827855767220339802">"Inkluder link"</string>
+</resources>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
new file mode 100644
index 00000000..a78310d5
--- /dev/null
+++ b/java/res/values-de/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Aktion durchführen mit"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Aktion ausführen mit <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Abschließen"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Öffnen mit"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Mit <xliff:g id="APP">%1$s</xliff:g> öffnen"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Öffnen"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Links von <xliff:g id="HOST">%1$s</xliff:g> öffnen mit"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Links öffnen mit"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Links mit <xliff:g id="APPLICATION">%1$s</xliff:g> öffnen"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Links von <xliff:g id="HOST">%1$s</xliff:g> mit <xliff:g id="APPLICATION">%2$s</xliff:g> öffnen"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Zugriff erlauben"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Bearbeiten mit"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Bearbeiten mit <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Bearbeiten"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Teilen"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Mit <xliff:g id="APP">%1$s</xliff:g> teilen"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Teilen"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Senden via"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Mit <xliff:g id="APP">%1$s</xliff:g> senden"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Senden"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Start-App auswählen"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> als Startbildschirm-App verwenden"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Bild aufnehmen"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Bild aufnehmen mit"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Bild aufnehmen mit <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Bild aufnehmen"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Andere App verwenden"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Aktion auswählen"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Diese Aktion kann von keiner App ausgeführt werden."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Du verwendest diese App außerhalb deines Arbeitsprofils"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Du verwendest diese App in deinem Arbeitsprofil."</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Immer"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Nur diesmal"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> unterstützt das Arbeitsprofil nicht"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> anpinnen"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> loslösen"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Bearbeiten"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # Datei}other{{file_name} + # Dateien}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # Datei}other{+ # Dateien}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Text wird geteilt"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Link wird geteilt"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Bild wird geteilt}other{# Bilder werden geteilt}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Video wird geteilt}other{# Videos werden geteilt}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# Element wird geteilt}other{# Elemente werden geteilt}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Bild mit Text geteilt"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Bild mit Link geteilt"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Keine empfohlenen Empfänger"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Liste der Apps"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Diese App hat noch keine Berechtigung zum Aufnehmen erhalten, könnte aber Audioaufnahmen über dieses USB-Gerät machen."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Privat"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Geschäftlich"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Private Ansicht"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Geschäftliche Ansicht"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Von deinem IT-Administrator blockiert"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Diese Art von Inhalt kann nicht über geschäftliche Apps geteilt werden"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Diese Art von Inhalt kann nicht mit geschäftlichen Apps geöffnet werden"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Diese Art von Inhalt kann nicht über private Apps geteilt werden"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Diese Art von Inhalt kann nicht mit privaten Apps geöffnet werden"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Arbeitsprofil pausiert"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Zum Aktivieren tippen"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Keine geschäftlichen Apps"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Keine privaten Apps"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g> in deinem privaten Profil öffnen?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g> in deinem Arbeitsprofil öffnen?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Privaten Browser verwenden"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Arbeitsbrowser verwenden"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Text ausschließen"</string>
+ <string name="include_text" msgid="642280283268536140">"Text einschließen"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Link ausschließen"</string>
+ <string name="include_link" msgid="827855767220339802">"Link einschließen"</string>
+</resources>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
new file mode 100644
index 00000000..31e273ab
--- /dev/null
+++ b/java/res/values-el/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Ολοκλήρωση ενέργειας με τη χρήση"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Ολοκλήρωση ενέργειας χρησιμοποιώντας την εφαρμογή <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Ολοκλήρωση ενέργειας"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Άνοιγμα με"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Άνοιγμα με την εφαρμογή <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Άνοιγμα"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Άνοιγμα συνδέσμων <xliff:g id="HOST">%1$s</xliff:g> με"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Άνοιγμα συνδέσμων με"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Άνοιγμα συνδέσμων με την εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Άνοιγμα συνδέσμων <xliff:g id="HOST">%1$s</xliff:g> με την εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Παροχή πρόσβασης"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Επεξεργασία με"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Επεξεργασία με <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Επεξεργασία"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Κοινοποίηση"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Κοινοποίηση στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Κοινοποίηση"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Αποστολή μέσω"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Αποστολή με την εφαρμογή <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Αποστολή"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Επιλέξτε μια εφαρμογή Αρχικής σελίδας"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Χρήση της εφαρμογής <xliff:g id="APP">%1$s</xliff:g> ως αρχικής"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Λήψη εικόνας"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Λήψη εικόνας με"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Λήψη εικόνας με την εφαρμογή <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Λήψη εικόνας"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Χρήση άλλης εφαρμογής"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Επιλέξτε μια ενέργεια"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Δεν υπάρχουν εφαρμογές, οι οποίες μπορούν να εκτελέσουν αυτήν την ενέργεια."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Χρησιμοποιείτε αυτήν την εφαρμογή εκτός του προφίλ εργασίας σας"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Χρησιμοποιείτε αυτήν την εφαρμογή στο προφίλ εργασίας"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Πάντα"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Μόνο μία φορά"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> δεν υποστηρίζει προφίλ εργασίας"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Καρφίτσωμα <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Ξεκαρφίτσωμα <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Επεξεργασία"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # αρχείο}other{{file_name} + # αρχεία}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # αρχείο}other{+ # αρχεία}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Κοινοποίηση μηνύματος"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Κοινοποίηση συνδέσμου"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Κοινοποίηση εικόνας}other{Κοινοποίηση # εικόνων}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Κοινοποίηση βίντεο}other{Κοινοποίηση # βίντεο}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Κοινοποίηση # στοιχείου}other{Κοινοποίηση # στοιχείων}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Κοινοπ. εικόνας με κείμ."</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Κοινοπ. εικόνας με σύνδ."</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Δεν υπάρχουν προτεινόμενα άτομα για κοινοποίηση"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Λίστα εφαρμογών"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Δεν έχει εκχωρηθεί άδεια εγγραφής σε αυτήν την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Προσωπικό"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Εργασία"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Προσωπική προβολή"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Προβολή εργασίας"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Αποκλείστηκε από τον διαχειριστή IT"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Δεν είναι δυνατή η κοινοποίηση αυτού του περιεχομένου με εφαρμογές εργασιών"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Δεν είναι δυνατό το άνοιγμα αυτού του περιεχομένου με εφαρμογές εργασιών"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Δεν είναι δυνατή η κοινοποίηση αυτού του περιεχομένου με προσωπικές εφαρμογές"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Δεν είναι δυνατό το άνοιγμα αυτού του περιεχομένου με προσωπικές εφαρμογές"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Το προφίλ εργασίας σας έχει τεθεί σε παύση."</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Πατήστε για ενεργοποίηση"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Δεν υπάρχουν εφαρμογές εργασιών"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Δεν υπάρχουν προσωπικές εφαρμογές"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Θέλετε να ανοίξετε την εφαρμογή <xliff:g id="APP">%s</xliff:g> στο προσωπικό σας προφίλ;"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Θέλετε να ανοίξετε την εφαρμογή <xliff:g id="APP">%s</xliff:g> στο προφίλ σας εργασίας;"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Χρήση προσωπικού προγράμματος περιήγησης"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Χρήση προγράμματος περιήγησης εργασίας"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Εξαίρεση κειμένου"</string>
+ <string name="include_text" msgid="642280283268536140">"Συμπερίληψη κειμένου"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Εξαίρεση συνδέσμου"</string>
+ <string name="include_link" msgid="827855767220339802">"Συμπερίληψη συνδέσμου"</string>
+</resources>
diff --git a/java/res/values-en-rAU/strings.xml b/java/res/values-en-rAU/strings.xml
new file mode 100644
index 00000000..29707f24
--- /dev/null
+++ b/java/res/values-en-rAU/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Complete action using"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Complete action using <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Complete action"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Open with"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Open with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Open"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Open links with"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Give access"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Edit with"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Edit with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Edit"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Share"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Share with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Share"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Send using"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Send using <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Send"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Select a Home app"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Use <xliff:g id="APP">%1$s</xliff:g> as Home"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Capture image"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Capture image with"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Capture image with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Capture image"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Use a different app"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Choose an action"</string>
+ <string name="noApplications" msgid="1139487441772284671">"No apps can perform this action."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"You\'re using this app outside of your work profile"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"You\'re using this app in your work profile"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Always"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Just once"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> doesn\'t support work profile"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Pin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Unpin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Edit"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # file}other{{file_name} + # files}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # file}other{+ # files}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Sharing text"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Sharing link"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Sharing image}other{Sharing # images}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Sharing video}other{Sharing # videos}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Sharing # item}other{Sharing # items}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Sharing image with text"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Sharing image with link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"No recommended people to share with"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Apps list"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"This app has not been granted record permission but could capture audio through this USB device."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Work"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Personal view"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Work view"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blocked by your IT admin"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"This content can’t be shared with work apps"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"This content can’t be opened with work apps"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"This content can’t be shared with personal apps"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"This content can’t be opened with personal apps"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Work profile is paused"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Tap to turn on"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"No work apps"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"No personal apps"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Open <xliff:g id="APP">%s</xliff:g> in your personal profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Open <xliff:g id="APP">%s</xliff:g> in your work profile?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Use personal browser"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Use work browser"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Exclude text"</string>
+ <string name="include_text" msgid="642280283268536140">"Include text"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Exclude link"</string>
+ <string name="include_link" msgid="827855767220339802">"Include link"</string>
+</resources>
diff --git a/java/res/values-en-rCA/strings.xml b/java/res/values-en-rCA/strings.xml
new file mode 100644
index 00000000..29707f24
--- /dev/null
+++ b/java/res/values-en-rCA/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Complete action using"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Complete action using <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Complete action"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Open with"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Open with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Open"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Open links with"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Give access"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Edit with"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Edit with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Edit"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Share"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Share with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Share"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Send using"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Send using <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Send"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Select a Home app"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Use <xliff:g id="APP">%1$s</xliff:g> as Home"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Capture image"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Capture image with"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Capture image with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Capture image"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Use a different app"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Choose an action"</string>
+ <string name="noApplications" msgid="1139487441772284671">"No apps can perform this action."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"You\'re using this app outside of your work profile"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"You\'re using this app in your work profile"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Always"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Just once"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> doesn\'t support work profile"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Pin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Unpin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Edit"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # file}other{{file_name} + # files}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # file}other{+ # files}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Sharing text"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Sharing link"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Sharing image}other{Sharing # images}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Sharing video}other{Sharing # videos}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Sharing # item}other{Sharing # items}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Sharing image with text"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Sharing image with link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"No recommended people to share with"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Apps list"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"This app has not been granted record permission but could capture audio through this USB device."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Work"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Personal view"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Work view"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blocked by your IT admin"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"This content can’t be shared with work apps"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"This content can’t be opened with work apps"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"This content can’t be shared with personal apps"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"This content can’t be opened with personal apps"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Work profile is paused"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Tap to turn on"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"No work apps"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"No personal apps"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Open <xliff:g id="APP">%s</xliff:g> in your personal profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Open <xliff:g id="APP">%s</xliff:g> in your work profile?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Use personal browser"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Use work browser"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Exclude text"</string>
+ <string name="include_text" msgid="642280283268536140">"Include text"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Exclude link"</string>
+ <string name="include_link" msgid="827855767220339802">"Include link"</string>
+</resources>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
new file mode 100644
index 00000000..29707f24
--- /dev/null
+++ b/java/res/values-en-rGB/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Complete action using"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Complete action using <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Complete action"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Open with"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Open with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Open"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Open links with"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Give access"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Edit with"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Edit with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Edit"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Share"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Share with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Share"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Send using"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Send using <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Send"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Select a Home app"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Use <xliff:g id="APP">%1$s</xliff:g> as Home"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Capture image"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Capture image with"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Capture image with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Capture image"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Use a different app"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Choose an action"</string>
+ <string name="noApplications" msgid="1139487441772284671">"No apps can perform this action."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"You\'re using this app outside of your work profile"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"You\'re using this app in your work profile"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Always"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Just once"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> doesn\'t support work profile"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Pin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Unpin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Edit"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # file}other{{file_name} + # files}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # file}other{+ # files}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Sharing text"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Sharing link"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Sharing image}other{Sharing # images}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Sharing video}other{Sharing # videos}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Sharing # item}other{Sharing # items}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Sharing image with text"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Sharing image with link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"No recommended people to share with"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Apps list"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"This app has not been granted record permission but could capture audio through this USB device."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Work"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Personal view"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Work view"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blocked by your IT admin"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"This content can’t be shared with work apps"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"This content can’t be opened with work apps"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"This content can’t be shared with personal apps"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"This content can’t be opened with personal apps"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Work profile is paused"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Tap to turn on"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"No work apps"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"No personal apps"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Open <xliff:g id="APP">%s</xliff:g> in your personal profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Open <xliff:g id="APP">%s</xliff:g> in your work profile?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Use personal browser"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Use work browser"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Exclude text"</string>
+ <string name="include_text" msgid="642280283268536140">"Include text"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Exclude link"</string>
+ <string name="include_link" msgid="827855767220339802">"Include link"</string>
+</resources>
diff --git a/java/res/values-en-rIN/strings.xml b/java/res/values-en-rIN/strings.xml
new file mode 100644
index 00000000..29707f24
--- /dev/null
+++ b/java/res/values-en-rIN/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Complete action using"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Complete action using <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Complete action"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Open with"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Open with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Open"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Open links with"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Give access"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Edit with"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Edit with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Edit"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Share"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Share with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Share"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Send using"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Send using <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Send"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Select a Home app"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Use <xliff:g id="APP">%1$s</xliff:g> as Home"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Capture image"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Capture image with"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Capture image with <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Capture image"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Use a different app"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Choose an action"</string>
+ <string name="noApplications" msgid="1139487441772284671">"No apps can perform this action."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"You\'re using this app outside of your work profile"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"You\'re using this app in your work profile"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Always"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Just once"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> doesn\'t support work profile"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Pin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Unpin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Edit"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # file}other{{file_name} + # files}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # file}other{+ # files}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Sharing text"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Sharing link"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Sharing image}other{Sharing # images}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Sharing video}other{Sharing # videos}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Sharing # item}other{Sharing # items}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Sharing image with text"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Sharing image with link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"No recommended people to share with"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Apps list"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"This app has not been granted record permission but could capture audio through this USB device."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Work"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Personal view"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Work view"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blocked by your IT admin"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"This content can’t be shared with work apps"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"This content can’t be opened with work apps"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"This content can’t be shared with personal apps"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"This content can’t be opened with personal apps"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Work profile is paused"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Tap to turn on"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"No work apps"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"No personal apps"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Open <xliff:g id="APP">%s</xliff:g> in your personal profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Open <xliff:g id="APP">%s</xliff:g> in your work profile?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Use personal browser"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Use work browser"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Exclude text"</string>
+ <string name="include_text" msgid="642280283268536140">"Include text"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Exclude link"</string>
+ <string name="include_link" msgid="827855767220339802">"Include link"</string>
+</resources>
diff --git a/java/res/values-en-rXC/strings.xml b/java/res/values-en-rXC/strings.xml
new file mode 100644
index 00000000..5811516b
--- /dev/null
+++ b/java/res/values-en-rXC/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‏‎‏‏‏‎‎‏‏‎‎Complete action using‎‏‎‎‏‎"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎Complete action using ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‎‎‎‏‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎Complete action‎‏‎‎‏‎"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎Open with‎‏‎‎‏‎"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‎Open with ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‎Open‎‏‎‎‏‎"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‎‎‏‎‎Open ‎‏‎‎‏‏‎<xliff:g id="HOST">%1$s</xliff:g>‎‏‎‎‏‏‏‎ links with‎‏‎‎‏‎"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎Open links with‎‏‎‎‏‎"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‎Open links with ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‎‎‏‎‏‏‎‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎Open ‎‏‎‎‏‏‎<xliff:g id="HOST">%1$s</xliff:g>‎‏‎‎‏‏‏‎ links with ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‏‏‎Give access‎‏‎‎‏‎"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‏‎‎‏‎‏‏‎‎Edit with‎‏‎‎‏‎"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎Edit with ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‎‏‎‏‏‎‎‎Edit‎‏‎‎‏‎"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‎Share‎‏‎‎‏‎"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‏‏‎Share with ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‏‎Share‎‏‎‎‏‎"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎Send using‎‏‎‎‏‎"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎Send using ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎Send‎‏‎‎‏‎"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‎Select a Home app‎‏‎‎‏‎"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‎‏‎‏‏‎Use ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ as Home‎‏‎‎‏‎"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎Capture image‎‏‎‎‏‎"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎Capture image with‎‏‎‎‏‎"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‎‎Capture image with ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎Capture image‎‏‎‎‏‎"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎Use a different app‎‏‎‎‏‎"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎‏‎‎‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‎‎Choose an action‎‏‎‎‏‎"</string>
+ <string name="noApplications" msgid="1139487441772284671">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎No apps can perform this action.‎‏‎‎‏‎"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‏‎‏‏‎You\'re using this app outside of your work profile‎‏‎‎‏‎"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎You\'re using this app in your work profile‎‏‎‎‏‎"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‎‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‎‏‎Always‎‏‎‎‏‎"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎Just once‎‏‎‎‏‎"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‏‎‏‎‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ doesn\'t support work profile‎‏‎‎‏‎"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‏‏‏‏‎‎Pin ‎‏‎‎‏‏‎<xliff:g id="LABEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎Unpin ‎‏‎‎‏‏‎<xliff:g id="LABEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‎‎Edit‎‏‎‎‏‎"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎{file_name}‎‏‎‎‏‏‏‎ + # file‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎{file_name}‎‏‎‎‏‏‏‎ + # files‎‏‎‎‏‎}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‎+ # file‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‎+ # files‎‏‎‎‏‎}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎Sharing text‎‏‎‎‏‎"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‎‎‏‎‎‎Sharing link‎‏‎‎‏‎"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‏‎‎‎‏‎‏‎‏‏‎‎Sharing image‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‏‎‎‎‏‎‏‎‏‏‎‎Sharing # images‎‏‎‎‏‎}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‏‏‎‏‎‎Sharing video‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‏‏‎‏‎‎Sharing # videos‎‏‎‎‏‎}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‏‎Sharing # item‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‏‎Sharing # items‎‏‎‎‏‎}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎Sharing image with text‎‏‎‎‏‎"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‎‎‎‏‎‏‏‎Sharing image with link‎‏‎‎‏‎"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‎‏‎‏‎‎‎No recommended people to share with‎‏‎‎‏‎"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‎Apps list‎‏‎‎‏‎"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎This app has not been granted record permission but could capture audio through this USB device.‎‏‎‎‏‎"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‎Personal‎‏‎‎‏‎"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‎‎‏‏‏‎‎‎Work‎‏‎‎‏‎"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‏‎‎Personal view‎‏‎‎‏‎"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‎‎‎‎Work view‎‏‎‎‏‎"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎Blocked by your IT admin‎‏‎‎‏‎"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎‏‎‎‏‏‎This content can’t be shared with work apps‎‏‎‎‏‎"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎‏‎‎This content can’t be opened with work apps‎‏‎‎‏‎"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎This content can’t be shared with personal apps‎‏‎‎‏‎"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‎‎‏‎‎This content can’t be opened with personal apps‎‏‎‎‏‎"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‎‏‎Work profile is paused‎‏‎‎‏‎"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‎‏‏‏‏‎‏‎‏‎Tap to turn on‎‏‎‎‏‎"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‏‎No work apps‎‏‎‎‏‎"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‎‏‏‏‏‎No personal apps‎‏‎‎‏‎"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎Open ‎‏‎‎‏‏‎<xliff:g id="APP">%s</xliff:g>‎‏‎‎‏‏‏‎ in your personal profile?‎‏‎‎‏‎"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‎‏‎Open ‎‏‎‎‏‏‎<xliff:g id="APP">%s</xliff:g>‎‏‎‎‏‏‏‎ in your work profile?‎‏‎‎‏‎"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‎Use personal browser‎‏‎‎‏‎"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‎Use work browser‎‏‎‎‏‎"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‏‏‎‎‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‎‏‎‎Exclude text‎‏‎‎‏‎"</string>
+ <string name="include_text" msgid="642280283268536140">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‏‏‎‎‎Include text‎‏‎‎‏‎"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎Exclude link‎‏‎‎‏‎"</string>
+ <string name="include_link" msgid="827855767220339802">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‎‏‏‎‏‏‎‏‎‏‎‎‎‏‎‎‎‏‎‏‏‎‏‎‎Include link‎‏‎‎‏‎"</string>
+</resources>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
new file mode 100644
index 00000000..5393889e
--- /dev/null
+++ b/java/res/values-es-rUS/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Completar la acción mediante"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Completar la acción con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Completar acción"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Abrir con"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Abrir con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Abrir"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Abrir vínculos con"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Abrir vínculos con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Otorgar acceso"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Editar con"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Editar con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Editar"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Compartir"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Compartir con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Compartir"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Enviar con"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Enviar con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Enviar"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Seleccionar una aplicación de la pantalla principal"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Usar <xliff:g id="APP">%1$s</xliff:g> como pantalla principal"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Capturar imagen"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Capturar imagen con"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Capturar imagen con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Capturar imagen"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Utilizar una aplicación diferente"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Seleccionar una acción"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Ninguna aplicación puede realizar esta acción."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Estás utilizando esta aplicación fuera del perfil de trabajo."</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Estás utilizando esta aplicación en tu perfil de trabajo."</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Siempre"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Solo una vez"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> no admite el perfil de trabajo"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Dejar de fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Editar"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} y # archivo más}many{{file_name} y # archivos más}other{{file_name} y # archivos más}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # archivo}many{+ # de archivos}other{+ # archivos}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Compartiendo texto"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Compartiendo vínculo"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Compartiendo imagen}many{Compartiendo # de imág.}other{Compartiendo # imágenes}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Compartiendo video}many{Compartiendo # de videos}other{Compartiendo # videos}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Compartiendo # elemento}many{Compartiendo # de elem.}other{Compartiendo # elementos}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Compartiendo con texto"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Compartiendo con vínculo"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"No hay personas recomendadas con quienes compartir"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lista de apps"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Aunque no se le otorgó permiso de grabación a esta app, puede capturar audio con este dispositivo USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Trabajo"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Vista personal"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Vista de trabajo"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Bloqueado por tu administrador de TI"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"No se pueden usar apps de trabajo para compartir este contenido"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"No se puede abrir este contenido con apps de trabajo"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"No se pueden usar apps personales para compartir este contenido"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"No se puede abrir este contenido con apps personales"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"El perfil de trabajo está en pausa"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Presionar para activar"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"El contenido no es compatible con apps de trabajo"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"El contenido no es compatible con apps personales"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"¿Quieres abrir <xliff:g id="APP">%s</xliff:g> en tu perfil personal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"¿Quieres abrir <xliff:g id="APP">%s</xliff:g> en tu perfil de trabajo?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Usar un navegador personal"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Usar un navegador de trabajo"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Excluir texto"</string>
+ <string name="include_text" msgid="642280283268536140">"Incluir texto"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Excluir vínculo"</string>
+ <string name="include_link" msgid="827855767220339802">"Incluir vínculo"</string>
+</resources>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
new file mode 100644
index 00000000..5be4c35a
--- /dev/null
+++ b/java/res/values-es/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Completar acción utilizando"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Completar acción con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Completar acción"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Abrir con"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Abrir con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Abrir"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Abrir enlaces con"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Abrir enlaces con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Dar acceso"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Editar con"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Editar con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Cambiar"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Compartir"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Compartir con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Compartir"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Enviar con"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Enviar con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Enviar"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Selecciona una aplicación de inicio"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Usar <xliff:g id="APP">%1$s</xliff:g> como aplicación de inicio"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Capturar imagen"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Capturar imagen con"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Capturar imagen con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Capturar imagen"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Usar otra aplicación"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Selecciona una acción"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Ninguna aplicación puede realizar esta acción."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Estás usando esta aplicación fuera del perfil de trabajo"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Estás usando esta aplicación en tu perfil de trabajo"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Siempre"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Solo una vez"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> no admite perfiles de trabajo"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"No fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Editar"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} y # archivo más}many{{file_name} y # archivos más}other{{file_name} y # archivos más}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # archivo}many{+ # archivos}other{+ # archivos}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Compartiendo texto"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Compartiendo enlace"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Compartiendo imagen}many{Compartiendo # imágenes}other{Compartiendo # imágenes}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Compartiendo vídeo}many{Compartiendo # vídeos}other{Compartiendo # vídeos}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Compartiendo # elemento}many{Compartiendo # elementos}other{Compartiendo # elementos}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Compartiendo imagen con texto"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Compartiendo imagen con enlace"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"No hay sugerencias de personas con las que compartir"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lista de aplicaciones"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Esta aplicación no tiene permiso para grabar, pero podría capturar audio con este dispositivo USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Trabajo"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Ver contenido personal"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Ver contenido de trabajo"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Bloqueado por tu administrador de TI"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Este contenido no se puede compartir con aplicaciones de trabajo"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Este contenido no se puede abrir con aplicaciones de trabajo"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Este contenido no se puede compartir con aplicaciones personales"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Este contenido no se puede abrir con aplicaciones personales"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"El perfil de trabajo está en pausa"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Toca para activar"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Ninguna aplicación de trabajo"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Ninguna aplicación personal"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"¿Abrir <xliff:g id="APP">%s</xliff:g> en tu perfil personal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"¿Abrir <xliff:g id="APP">%s</xliff:g> en tu perfil de trabajo?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Usar navegador personal"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Usar navegador de trabajo"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Excluir texto"</string>
+ <string name="include_text" msgid="642280283268536140">"Incluir texto"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Excluir enlace"</string>
+ <string name="include_link" msgid="827855767220339802">"Incluir enlace"</string>
+</resources>
diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml
new file mode 100644
index 00000000..60ba3db6
--- /dev/null
+++ b/java/res/values-et/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Lõpetage toiming rakendusega"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Lõpeta toiming, kasutades rakendust <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Vii toiming lõpule"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Avamine:"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Ava rakendusega <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Ava"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Ava teenuse <xliff:g id="HOST">%1$s</xliff:g> lingid rakendusega"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Ava lingid rakendusega"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Linkide avamine rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Ava teenuse <xliff:g id="HOST">%1$s</xliff:g> lingid rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Anna juudepääs"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Redigeeri rakendusega:"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Muuda rakendusega <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Muuda"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Jagamine"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Jaga rakendusega <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Jaga"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Saada rakendusega"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Saada rakendusega <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Saada"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Avakuva rakenduse valimine"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Kasuta rakendust <xliff:g id="APP">%1$s</xliff:g> avakuvana"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Jäädvusta kujutis"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Jäädvusta pilt rakendusega"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Jäädvusta pilt rakendusega <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Jäädvusta kujutis"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Teise rakenduse kasutamine"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Toimingu valimine"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Ükski rakendus ei saa seda toimingut teostada."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Kasutate rakendust väljaspool tööprofiili"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Kasutate seda rakendust oma tööprofiilil"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Alati"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Ainult üks kord"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ei toeta tööprofiili"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Kinnita <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Vabasta <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Muuda"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # fail}other{{file_name} + # faili}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # fail}other{+ # faili}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Teksti jagamine"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Lingi jagamine"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Pildi jagamine}other{# pildi jagamine}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Video jagamine}other{# video jagamine}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# üksuse jagamine}other{# üksuse jagamine}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Pildi jagamine tekstiga"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Pildi jagamine lingiga"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Ei ole ühtki soovitatud inimest, kellega jagada"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Rakenduste loend"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Sellele rakendusele pole antud salvestamise luba, kuid see saab heli jäädvustada selle USB-seadme kaudu."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Isiklik"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Töö"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Isiklik vaade"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Töövaade"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blokeeris teie IT-administraator"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Seda sisu ei saa töörakendustega jagada"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Seda sisu ei saa töörakendustega avada"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Seda sisu ei saa isiklike rakendustega jagada"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Seda sisu ei saa isiklike rakendustega avada"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Tööprofiil on peatatud"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Puudutage sisselülitamiseks"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Töörakendusi pole"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Isiklikke rakendusi pole"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Kas avada <xliff:g id="APP">%s</xliff:g> teie isiklikul profiilil?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Kas avada <xliff:g id="APP">%s</xliff:g> teie tööprofiilil?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Kasuta isiklikku brauserit"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Kasuta tööbrauserit"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Välista tekst"</string>
+ <string name="include_text" msgid="642280283268536140">"Kaasa tekst"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Välista link"</string>
+ <string name="include_link" msgid="827855767220339802">"Kaasa link"</string>
+</resources>
diff --git a/java/res/values-eu/strings.xml b/java/res/values-eu/strings.xml
new file mode 100644
index 00000000..1a613e7f
--- /dev/null
+++ b/java/res/values-eu/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Gauzatu ekintza hau erabilita:"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Gauzatu ekintza <xliff:g id="APP">%1$s</xliff:g> erabilita"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Osatu ekintza"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Ireki honekin"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Ireki <xliff:g id="APP">%1$s</xliff:g> aplikazioaren bidez"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Ireki"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Ireki <xliff:g id="HOST">%1$s</xliff:g> ostalariko estekak honekin:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Ireki estekak honekin:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Ireki estekak <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioarekin"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Ireki <xliff:g id="HOST">%1$s</xliff:g> ostalariko estekak <xliff:g id="APPLICATION">%2$s</xliff:g> aplikazioarekin"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Eman baimena"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Editatu honekin:"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Editatu <xliff:g id="APP">%1$s</xliff:g> aplikazioarekin"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Editatu"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Partekatu"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Partekatu <xliff:g id="APP">%1$s</xliff:g> aplikazioarekin"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Partekatu"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Bidali honen bidez:"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Bidali <xliff:g id="APP">%1$s</xliff:g> erabilita"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Bidali"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Hautatu hasierako aplikazioa"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Erabili <xliff:g id="APP">%1$s</xliff:g> hasierako pantaila gisa"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Atera argazkia"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Atera argazkia aplikazio honekin:"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Atera argazkia <xliff:g id="APP">%1$s</xliff:g> aplikazioarekin"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Atera argazkia"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Erabili beste aplikazio bat"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Aukeratu ekintza bat"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Ez dago ekintza hori egin dezakeen aplikaziorik."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Laneko profiletik kanpo ari zara aplikazioa erabiltzen"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Laneko profilean ari zara aplikazioa erabiltzen"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Beti"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Behin soilik"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> aplikazioak ez du onartzen laneko profila"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Ainguratu <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Kendu aingura <xliff:g id="LABEL">%1$s</xliff:g> aplikazioari"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Editatu"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} eta beste # fitxategi}other{{file_name} eta beste # fitxategi}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{eta beste # fitxategi}other{eta beste # fitxategi}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Testua partekatzen"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Esteka partekatzen"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Irudia partekatzen}other{# irudi partekatzen}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Bideoa partekatzen}other{# bideo partekatzen}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# elementu partekatzen}other{# elementu partekatzen}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Irudi testuduna partekatzen"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Irudi estekaduna partekatzen"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Ez dago edukia partekatzeko pertsona gomendaturik"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Aplikazioen zerrenda"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Aplikazioak ez du grabatzeko baimenik, baina baliteke audioa grabatzea USB bidezko gailu horren bidez."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Pertsonala"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Lanekoa"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Ikuspegi pertsonala"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Laneko ikuspegia"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"IKT saileko administratzaileak blokeatu egin du"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Eduki hau ezin da laneko aplikazioekin partekatu"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Eduki hau ezin da laneko aplikazioekin ireki"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Eduki hau ezin da aplikazio pertsonalekin partekatu"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Eduki hau ezin da aplikazio pertsonalekin ireki"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Laneko profila pausatuta dago"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Sakatu aktibatzeko"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Ez dago laneko aplikaziorik"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Ez dago aplikazio pertsonalik"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Profil pertsonalean ireki nahi duzu <xliff:g id="APP">%s</xliff:g>?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Laneko profilean ireki nahi duzu <xliff:g id="APP">%s</xliff:g>?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Erabili arakatzaile pertsonala"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Erabili laneko arakatzailea"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Utzi kanpoan testua"</string>
+ <string name="include_text" msgid="642280283268536140">"Sartu testua"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Utzi kanpoan esteka"</string>
+ <string name="include_link" msgid="827855767220339802">"Sartu esteka"</string>
+</resources>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
new file mode 100644
index 00000000..bb4a1a69
--- /dev/null
+++ b/java/res/values-fa/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"تکمیل کنش بااستفاده از"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"تکمیل کنش بااستفاده از <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"تکمیل عملکرد"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"باز کردن با"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"باز کردن با <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"باز کردن"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"باز کردن پیوندهای <xliff:g id="HOST">%1$s</xliff:g> با"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"باز کردن پیوندها با"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"باز کردن پیوندها با <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"باز کردن پیوندهای <xliff:g id="HOST">%1$s</xliff:g> با <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"ارائه دسترسی"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"ویرایش با"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"ویرایش با <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"ویرایش"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"هم‌رسانی"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"هم‌رسانی با <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"اشتراک‌گذاری"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"ارسال با استفاده از"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"ارسال بااستفاده از <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"ارسال"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"انتخاب یک برنامه صفحه اصلی"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"استفاده از <xliff:g id="APP">%1$s</xliff:g> به‌عنوان «خانه»"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"تصویربرداری"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"تصویربرداری با"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"گرفتن عکس با <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"تصویربرداری"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"استتفاده از یک برنامه دیگر"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"انتخاب کنش"</string>
+ <string name="noApplications" msgid="1139487441772284671">"‏هیچ برنامه‌ای نمی‌‎تواند این کار را انجام دهد."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"شما از این برنامه در خارج از نمایه کاری‌تان استفاده می‌کنید"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"از این برنامه در نمایه کاری‌تان استفاده می‌کنید"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"همیشه"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"فقط این بار"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> از نمایه کاری پشتیبانی نمی‌کند"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"سنجاق کردن <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"برداشتن سنجاق <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"ویرایش"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # فایل}one{{file_name} + # فایل}other{{file_name} + # فایل}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{بیش‌از # فایل}one{بیش‌از # فایل}other{بیش‌از # فایل}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"درحال هم‌رسانی نوشتار"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"درحال هم‌رسانی پیوند"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{درحال هم‌رسانی تصویر}one{درحال هم‌رسانی ‍# تصویر}other{درحال هم‌رسانی ‍# تصویر}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{درحال هم‌رسانی ویدیو}one{درحال هم‌رسانی # ویدیو}other{درحال هم‌رسانی # ویدیو}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{درحال هم‌رسانی # مورد}one{درحال هم‌رسانی # مورد}other{درحال هم‌رسانی # مورد}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"هم‌رسانی تصویر با نوشتار"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"هم‌رسانی تصویر با پیوند"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"هیچ فردی توصیه نشده است که با او هم‌رسانی کنید"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"فهرست برنامه‌ها"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"‏مجوز ضبط به این برنامه داده نشده است اما می‌تواند صدا را ازطریق این دستگاه USB ضبط کند."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"شخصی"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"کاری"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"نمای شخصی"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"نمای کاری"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"سرپرست فناوری اطلاعات آن را مسدود کرده است"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"نمی‌توان این محتوا را با برنامه‌های کاری هم‌رسانی کرد"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"نمی‌توان این محتوا را با برنامه‌های کاری باز کرد"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"نمی‌توان این محتوا را با برنامه‌های شخصی هم‌رسانی کرد"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"نمی‌توان این محتوا را با برنامه‌های شخصی باز کرد"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"نمایه کاری موقتاً متوقف شده است"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"برای روشن کردن، ضربه بزنید"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"برنامه کاری‌ای وجود ندارد"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"برنامه شخصی‌ای وجود ندارد"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g> در نمایه شخصی باز شود؟"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g> در نمایه کاری باز شود؟"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"استفاده از مرورگر شخصی"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"استفاده از مرورگر کاری"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"مستثنی کردن نوشتار"</string>
+ <string name="include_text" msgid="642280283268536140">"لحاظ کردن نوشتار"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"مستثنی کردن پیوند"</string>
+ <string name="include_link" msgid="827855767220339802">"لحاظ کردن پیوند"</string>
+</resources>
diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml
new file mode 100644
index 00000000..3c60b384
--- /dev/null
+++ b/java/res/values-fi/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Tee toiminto käyttäen:"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Suorita toiminto tällä: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Suorita toiminto"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Avaa sovelluksessa"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Avaa tällä: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Avaa"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g>-linkit avataan:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Linkit avataan:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> avaa linkit"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="APPLICATION">%2$s</xliff:g> avaa linkit (<xliff:g id="HOST">%1$s</xliff:g>)"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Anna pääsyoikeus"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Muokkaa sovelluksessa"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Muokkaa tällä: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Muokkaa"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Jaa"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Jaa: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Jaa"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Lähetä sovelluksella"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Lähetä tällä: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Lähetä"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Valitse aloitusruutusovellus"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Käytä sovellusta (<xliff:g id="APP">%1$s</xliff:g>) aloitusnäyttönä"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Tallenna kuva"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Tallenna kuva sovelluksella"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Tallenna kuva tällä: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Tallenna kuva"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Käytä toista sovellusta"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Valitse toiminto"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Yksikään sovellus ei voi suorittaa tätä toimintoa."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Käytät sovellusta muulla kuin työprofiililla"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Käytät sovellusta työprofiililla"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Aina"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Vain kerran"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ei tue työprofiilia"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Kiinnitä <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Irrota <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Muokkaa"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # tiedosto}other{{file_name} + # tiedostoa}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{yli # tiedosto}other{yli # tiedostoa}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Jaetaan tekstiä"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Jaetaan linkkiä"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Jaetaan kuvaa}other{Jaetaan # kuvaa}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Jaetaan videota}other{Jaetaan # videota}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Jaetaan # kohdetta}other{Jaetaan # kohdetta}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Kuvaa ja tekstiä jaetaan"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Kuvaa ja linkkiä jaetaan"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Ei suosituksia kenelle jakaa"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Sovellusluettelo"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Sovellus ei ole saanut tallennuslupaa mutta voi tallentaa ääntä tämän USB-laitteen avulla."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Henkilökohtainen"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Työ"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Henkilökohtainen näkymä"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Työnäkymä"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"IT-järjestelmänvalvojasi estämä"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Tätä sisältöä ei voi jakaa työsovelluksilla"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Tätä sisältöä ei voi avata työsovelluksilla"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Tätä sisältöä ei voi jakaa henkilökohtaisilla sovelluksilla"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Tätä sisältöä ei voi avata henkilökohtaisilla sovelluksilla"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Työprofiilin käyttö on keskeytetty"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Laita päälle napauttamalla"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Ei työsovelluksia"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Ei henkilökohtaisia sovelluksia"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Avataanko <xliff:g id="APP">%s</xliff:g> henkilökohtaisessa profiilissa?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Avataanko <xliff:g id="APP">%s</xliff:g> työprofiilissa?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Käytä henkilökohtaista selainta"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Käytä työselainta"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Jätä teksti pois"</string>
+ <string name="include_text" msgid="642280283268536140">"Liitä teksti mukaan"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Jätä linkki pois"</string>
+ <string name="include_link" msgid="827855767220339802">"Liitä linkki mukaan"</string>
+</resources>
diff --git a/java/res/values-fr-rCA/strings.xml b/java/res/values-fr-rCA/strings.xml
new file mode 100644
index 00000000..47bea8ac
--- /dev/null
+++ b/java/res/values-fr-rCA/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Continuer avec"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Effectuer l\'action avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Terminer l\'action"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Ouvrir avec"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Ouvrir avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Ouvrir"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Ouvrir les liens avec"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Ouvrir les liens avec <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Accorder l\'accès"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Modifier avec"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Modifier avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Modifier"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Partager"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Partager avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Partager"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Envoyer avec"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Envoyer avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Envoyer"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Sélectionner une application pour l\'écran d\'accueil"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Utiliser <xliff:g id="APP">%1$s</xliff:g> comme application sur la page d\'accueil"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Enregistrer l\'image"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Enregistrer l\'image avec"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Enregistrer l\'image avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Enregistrer l\'image"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Utiliser une application différente"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Sélectionner une action"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Aucune application ne peut effectuer cette action."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Vous utilisez cette application en dehors de votre profil professionnel"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Vous utilisez cette application dans votre profil professionnel"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Toujours"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Une seule fois"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ne prend pas en charge le profil professionnel"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Épingler <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Annuler l\'épinglage de <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Modifier"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # fichier}one{{file_name} + # fichier}many{{file_name} + # fichiers}other{{file_name} + # fichiers}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # fichier}one{+ # fichier}many{+ # de fichiers}other{+ # fichiers}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Partage du message texte…"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Partage du lien en cours…"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Partage de l\'image…}one{Partage de # image…}many{Partage de # d\'images…}other{Partage de # images…}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Partage de la vidéo…}one{Partage de # vidéo…}many{Partage de # de vidéos…}other{Partage de # vidéos…}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Partage de # élément…}one{Partage de # élément…}many{Partage de # d\'éléments}other{Partage de # éléments…}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Partage d\'image avec texte…"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Partage d\'image avec lien…"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Aucune recommandation de personnes avec lesquelles effectuer un partage"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Liste des applications"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Cette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait capturer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personnel"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Professionnel"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Affichage personnel"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Affichage professionnel"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Bloqué par votre administrateur informatique"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Impossible de partager ce contenu avec des applications professionnelles"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Impossible d\'ouvrir ce contenu avec des applications professionnelles"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Impossible de partager ce contenu avec des applications personnelles"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Impossible d\'ouvrir ce contenu avec des applications personnelles"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Le profil professionnel est interrompu"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Touchez pour activer"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Aucune application professionnelle"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Aucune application personnelle"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Ouvrir <xliff:g id="APP">%s</xliff:g> dans votre profil personnel?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Ouvrir <xliff:g id="APP">%s</xliff:g> dans votre profil professionnel?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Utiliser le navigateur du profil personnel"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Utiliser le navigateur du profil professionnel"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Exclure le texte"</string>
+ <string name="include_text" msgid="642280283268536140">"Inclure le texte"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Exclure le lien"</string>
+ <string name="include_link" msgid="827855767220339802">"Inclure le lien"</string>
+</resources>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
new file mode 100644
index 00000000..fbdb3a14
--- /dev/null
+++ b/java/res/values-fr/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Continuer avec"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Effectuer l\'action avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Terminer l\'action"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Ouvrir avec"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Ouvrir avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Ouvrir"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Ouvrir les liens avec"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Ouvrir les liens avec <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Autoriser l\'accès"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Modifier avec"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Modifier avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Modifier"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Partager"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Partager avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Partager"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Envoyer avec"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Envoyer avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Envoyer"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Sélectionner une application de l\'écran d\'accueil"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Utiliser <xliff:g id="APP">%1$s</xliff:g> pour l\'accueil"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Capturer une image"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Capturer une image avec"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Capturer une image avec <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Capturer une image"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Utiliser une autre application"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Sélectionner une action"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Aucune application ne peut effectuer cette action."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Vous utilisez cette application en dehors de votre profil professionnel."</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Vous utilisez cette application dans votre profil professionnel."</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Toujours"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Une seule fois"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> n\'est pas compatible avec le profil professionnel"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Épingler <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Retirer <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Modifier"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # fichier}one{{file_name} + # fichier}many{{file_name} + # fichiers}other{{file_name} + # fichiers}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # fichier}one{+ # fichier}many{+ # fichiers}other{+ # fichiers}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Partage du texte…"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Partage du lien…"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Partage de l\'image…}one{Partage de # image…}many{Partage de # d\'images…}other{Partage de # images…}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Partage de la vidéo…}one{Partage de # vidéo…}many{Partage de # de vidéos…}other{Partage de # vidéos…}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Partage de # élément…}one{Partage de # élément…}many{Partage de # d\'éléments…}other{Partage de # éléments…}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Partage de l\'image (texte)"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Partage de l\'image (lien)"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Aucune recommandation de personnes avec lesquelles effectuer un partage"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Liste des applications"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Cette application n\'a pas reçu l\'autorisation d\'enregistrer des contenus audio, mais peut le faire via ce périphérique USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personnel"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Professionnel"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Vue personnelle"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Vue professionnelle"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Bloqué par votre administrateur informatique"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Impossible de partager ce contenu avec des applis professionnelles"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Impossible d\'ouvrir ce contenu avec des applis professionnelles"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Impossible de partager ce contenu avec des applis personnelles"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Impossible d\'ouvrir ce contenu avec des applis personnelles"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Profil professionnel en pause"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Appuyez pour l\'activer"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Aucune appli professionnelle"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Aucune appli personnelle"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Ouvrir <xliff:g id="APP">%s</xliff:g> dans votre profil personnel ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Ouvrir <xliff:g id="APP">%s</xliff:g> dans votre profil professionnel ?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Utiliser le navigateur personnel"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Utiliser le navigateur professionnel"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Exclure le texte"</string>
+ <string name="include_text" msgid="642280283268536140">"Inclure le texte"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Exclure le lien"</string>
+ <string name="include_link" msgid="827855767220339802">"Inclure le lien"</string>
+</resources>
diff --git a/java/res/values-gl/strings.xml b/java/res/values-gl/strings.xml
new file mode 100644
index 00000000..f50f61b8
--- /dev/null
+++ b/java/res/values-gl/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Completar a acción usando"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Completar a acción usando <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Completar acción"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Abrir con"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Abrir con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Abrir"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Abrir ligazóns con"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Abrir ligazóns con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Permitir acceso"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Editar con"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Editar con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Editar"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Compartir"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Compartir o contido con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Compartir"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Enviar a través de"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Enviar con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Enviar"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Selecciona unha aplicación de Inicio"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Usar <xliff:g id="APP">%1$s</xliff:g> como aplicación de pantalla de inicio"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Capturar imaxe"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Capturar imaxe con"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Capturar a imaxe con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Capturar imaxe"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Utilizar unha aplicación diferente"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Escoller unha acción"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Ningunha aplicación pode realizar esta acción."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Estás usando esta aplicación fóra do teu perfil de traballo"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Estás usando esta aplicación no teu perfil de traballo"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Sempre"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Só unha vez"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> non é compatible co perfil de traballo"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fixar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Deixar de fixar a <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Editar"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ficheiro}other{{file_name} + # ficheiros}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+# ficheiro}other{+# ficheiros}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Compartindo texto"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Compartindo ligazón"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Compartindo imaxe}other{Compartindo # imaxes}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Compartindo vídeo}other{Compartindo # vídeos}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Compartindo # elemento}other{Compartindo # elementos}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Compartindo imaxe (texto)"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Compartindo imaxe (lig.)"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Non hai recomendacións de persoas coas que compartir contido"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lista de aplicacións"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Esta aplicación non está autorizada a realizar gravacións, pero podería capturar audio a través deste dispositivo USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Persoal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Traballo"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Vista persoal"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Vista de traballo"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"O teu administrador de TI bloqueou a instalación"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Este contido non pode compartirse con aplicacións do traballo"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Este contido non pode abrirse con aplicacións do traballo"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Este contido non pode compartirse con aplicacións persoais"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Este contido non pode abrirse con aplicacións persoais"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"O perfil de traballo está en pausa"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Tocar para activar o perfil"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Non hai ningunha aplicación do traballo compatible"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Non hai ningunha aplicación persoal compatible"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Queres abrir <xliff:g id="APP">%s</xliff:g> no teu perfil persoal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Queres abrir <xliff:g id="APP">%s</xliff:g> no teu perfil de traballo?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Utilizar navegador persoal"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Utilizar navegador de traballo"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Excluír texto"</string>
+ <string name="include_text" msgid="642280283268536140">"Incluír texto"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Excluír ligazón"</string>
+ <string name="include_link" msgid="827855767220339802">"Incluír ligazón"</string>
+</resources>
diff --git a/java/res/values-gu/strings.xml b/java/res/values-gu/strings.xml
new file mode 100644
index 00000000..b9d846e2
--- /dev/null
+++ b/java/res/values-gu/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"આના ઉપયોગથી ક્રિયા પૂર્ણ કરો"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g>ના ઉપયોગથી ક્રિયા પૂર્ણ કરો"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"ક્રિયા પૂર્ણ કરો"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"આની સાથે ખોલો"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> વડે ખોલો"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"ખોલો"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"આના વડે <xliff:g id="HOST">%1$s</xliff:g> લિંક ખોલો"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"આના વડે લિંક ખોલો"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> વડે લિંક ખોલો"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="APPLICATION">%2$s</xliff:g> વડે <xliff:g id="HOST">%1$s</xliff:g> લિંક ખોલો"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"ઍક્સેસ આપો"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"આનાથી સંપાદિત કરો"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> વડે ફેરફાર કરો"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"ફેરફાર કરો"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"શેર કરો"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> વડે શેર કરો"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"શેર કરો"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"આનો ઉપયોગ કરીને મોકલો"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g>નો ઉપયોગ કરીને મોકલો"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"મોકલો"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"હોમ ઍપ્લિકેશન પસંદ કરો"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Home ઍપ તરીકે <xliff:g id="APP">%1$s</xliff:g>નો ઉપયોગ કરો"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"છબી કૅપ્ચર કરો"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"આની સાથે છબી કૅપ્ચર કરો"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> વડે છબી કૅપ્ચર કરો"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"છબી કૅપ્ચર કરો"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"અલગ એપ્લિકેશનનો ઉપયોગ કરો"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"ક્રિયા પસંદ કરો"</string>
+ <string name="noApplications" msgid="1139487441772284671">"કોઈ ઍપ્લિકેશન આ ક્રિયા કરી શકતી નથી."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"તમે તમારી કાર્ય પ્રોફાઇલની બહાર આ એપ્લિકેશનનો ઉપયોગ કરી રહ્યાં છો"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"તમે તમારી કાર્ય પ્રોફાઇલમાં આ એપ્લિકેશનનો ઉપયોગ કરી રહ્યાં છો"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"હંમેશાં"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"ફક્ત એક વાર"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g>, ઑફિસની પ્રોફાઇલને સપોર્ટ કરતી નથી"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g>ને પિન કરો"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g>ને અનપિન કરો"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"ફેરફાર કરો"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ફાઇલ}one{{file_name} + # ફાઇલ}other{{file_name} + # ફાઇલો}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ફાઇલ}one{+ # ફાઇલ}other{+ # ફાઇલ}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"ટેક્સ્ટ શેર કરીએ છીએ"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"લિંક શેર કરી રહ્યાં છીએ"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{છબી શેર કરી રહ્યાં છીએ}one{# છબી શેર કરી રહ્યાં છીએ}other{# છબી શેર કરી રહ્યાં છીએ}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{વીડિયો શેર કરીએ છીએ}one{# વીડિયો શેર કરીએ છીએ}other{# વીડિયો શેર કરીએ છીએ}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# આઇટમ શેર કરી રહ્યાં છીએ}one{# આઇટમ શેર કરી રહ્યાં છીએ}other{# આઇટમ શેર કરી રહ્યાં છીએ}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"ટેક્સ્ટ સાથે છબી શેર થશે"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"લિંક સાથે છબી શેર થાય છે"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"શેર કરવા માટે સુઝાવ આપવામાં આવેલા કોઈ લોકો નથી"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"ઍપની સૂચિ"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"આ ઍપને રેકૉર્ડ કરવાની પરવાનગી આપવામાં આવી નથી પરંતુ તે આ USB ડિવાઇસ મારફતે ઑડિયો કૅપ્ચર કરી શકે છે."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"વ્યક્તિગત"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"ઑફિસ"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"વ્યક્તિગત વ્યૂ"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"ઑફિસ વ્યૂ"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"તમારા IT વ્યવસ્થાપકે બ્લૉક કર્યું છે"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"આ કન્ટેન્ટ ઑફિસ માટેની ઍપ સાથે શેર કરી શકાતું નથી"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"આ કન્ટેન્ટ ઑફિસ માટેની ઍપ વડે ખોલી શકાતું નથી"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"આ કન્ટેન્ટ વ્યક્તિગત ઍપ સાથે શેર કરી શકાતું નથી"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"આ કન્ટેન્ટ વ્યક્તિગત ઍપ વડે ખોલી શકાતું નથી"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"ઑફિસની પ્રોફાઇલ થોભાવી છે"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ચાલુ કરવા માટે ટૅપ કરો"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"કોઈ ઑફિસ માટેની ઍપ સપોર્ટ કરતી નથી"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"કોઈ વ્યક્તિગત ઍપ સપોર્ટ કરતી નથી"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"તમારી વ્યક્તિગત પ્રોફાઇલમાં <xliff:g id="APP">%s</xliff:g> ખોલીએ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"તમારી ઑફિસની પ્રોફાઇલમાં <xliff:g id="APP">%s</xliff:g> ખોલીએ?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"વ્યક્તિગત બ્રાઉઝરનો ઉપયોગ કરો"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"ઑફિસના બ્રાઉઝરના ઉપયોગ કરો"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"ટેક્સ્ટને બાકાત કરો"</string>
+ <string name="include_text" msgid="642280283268536140">"ટેક્સ્ટ શામેલ કરો"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"લિંકને બાકાત કરો"</string>
+ <string name="include_link" msgid="827855767220339802">"લિંક શામેલ કરો"</string>
+</resources>
diff --git a/java/res/values-h480dp/dimens.xml b/java/res/values-h480dp/dimens.xml
index 9cdc8899..b5c86c77 100644
--- a/java/res/values-h480dp/dimens.xml
+++ b/java/res/values-h480dp/dimens.xml
@@ -20,4 +20,9 @@
<dimen name="resolver_empty_state_container_padding_bottom">48dp</dimen>
<dimen name="resolver_title_padding_bottom">@dimen/resolver_edge_margin</dimen>
<dimen name="resolver_button_bar_spacing">8dp</dimen>
-</resources> \ No newline at end of file
+
+ <dimen name="chooser_preview_width">-1px</dimen>
+ <dimen name="chooser_preview_image_height_tall">192dp</dimen>
+ <dimen name="grid_padding">10dp</dimen>
+ <dimen name="width_text_image_preview_size">56dp</dimen>
+</resources>
diff --git a/java/res/values-h480dp/bools.xml b/java/res/values-h480dp/integers.xml
index 7896d9bf..c1693057 100644
--- a/java/res/values-h480dp/bools.xml
+++ b/java/res/values-h480dp/integers.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2020 The Android Open Source Project
+ ~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,6 +14,6 @@
~ limitations under the License.
-->
-<resources>
- <bool name="resolver_landscape_phone">false</bool>
-</resources> \ No newline at end of file
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <integer name="text_preview_lines">3</integer>
+</resources>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
new file mode 100644
index 00000000..538b11dd
--- /dev/null
+++ b/java/res/values-hi/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"इसका इस्तेमाल करके कार्रवाई को पूरा करें"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> का इस्तेमाल करके कार्रवाई को पूरा करें"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"कार्रवाई पूरी करें"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"इसमें खोलें"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> से खोलें"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"खोलें"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"इसे इस्तेमाल करके <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलें"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"इसे इस्तेमाल करके लिंक खोलें"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> इस्तेमाल करके लिंक खोलें"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="APPLICATION">%2$s</xliff:g> इस्तेमाल करके <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलें"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"ऐक्सेस दें"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"इसके ज़रिये बदलाव करें"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> से बदलाव करें"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"बदलाव करें"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"शेयर करें"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> से शेयर करें"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"शेयर करें"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"इसका उपयोग करके भेजें"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> का इस्तेमाल करके भेजें"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"भेजें"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"होम ऐप चुनें"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> को होम ऐप्लिकेशन के तौर पर इस्तेमाल करें"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"चित्र कैप्चर करें"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"चित्र को इसके साथ कैप्चर करें"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> से इमेज कैप्चर करें"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"चित्र कैप्चर करें"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"किसी दूसरे ऐप्लिकेशन का इस्तेमाल करें"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"कोई कार्रवाई चुनें"</string>
+ <string name="noApplications" msgid="1139487441772284671">"कोई भी ऐप्लिकेशन यह कार्रवाई नहीं कर सकता."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"आप इस ऐप्स का उपयोग अपनी वर्क प्रोफ़ाइल से बाहर कर रहे हैं"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"आप इस ऐप्स का उपयोग अपनी वर्क प्रोफ़ाइल में कर रहे हैं"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"हमेशा"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"सिर्फ़ एक बार"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"वर्क प्रोफ़ाइल से <xliff:g id="APP">%1$s</xliff:g> का इस्तेमाल नहीं किया जा सकता"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> को पिन करें"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> को अनपिन करें"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"बदलाव करें"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # फ़ाइल}one{{file_name} + # फ़ाइल}other{{file_name} + # फ़ाइलें}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # फ़ाइल}one{+ # फ़ाइल}other{+ # फ़ाइलें}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"टेक्स्ट शेयर किया जा रहा है"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"लिंक शेयर किया जा रहा है"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{इमेज शेयर की जा रही है}one{# इमेज शेयर की जा रही है}other{# इमेज शेयर की जा रही हैं}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{वीडियो शेयर किया जा रहा है}one{# वीडियो शेयर किया जा रहा है}other{# वीडियो शेयर किए जा रहे हैं}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# आइटम शेयर किया जा रहा है}one{# आइटम शेयर किया जा रहा है}other{# आइटम शेयर किए जा रहे हैं}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"टेक्स्ट के साथ इमेज शेयर की जा रही है"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"लिंक के साथ इमेज शेयर की जा रही है"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"शेयर करने के लिए, किसी व्यक्ति का सुझाव नहीं दिया गया है"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"ऐप्लिकेशन की सूची"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"इस ऐप्लिकेशन को रिकॉर्ड करने की अनुमति नहीं दी गई है. हालांकि, ऐप्लिकेशन इस यूएसबी डिवाइस से ऐसा कर सकता है."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"निजी प्रोफ़ाइल"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"वर्क प्रोफ़ाइल"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"निजी व्यू"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"वर्क व्यू"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"आपके आईटी एडमिन ने इस कॉन्टेंट को शेयर करने की सुविधा ब्लॉक कर रखी है"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"इस कॉन्टेंट को ऑफ़िस के काम से जुड़े ऐप्लिकेशन का इस्तेमाल करके, शेयर नहीं किया जा सकता"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"इस कॉन्टेंट को ऑफ़िस के काम से जुड़े ऐप्लिकेशन पर खोला नहीं जा सकता"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"इस कॉन्टेंट को निजी ऐप्लिकेशन का इस्तेमाल करके, शेयर नहीं किया जा सकता"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"इस कॉन्टेंट को निजी ऐप्लिकेशन पर खोला नहीं जा सकता"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"वर्क प्रोफ़ाइल रोक दी गई है"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"वर्क प्रोफ़ाइल चालू करने के लिए टैप करें"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"यह कॉन्टेंट, ऑफ़िस के काम से जुड़े आपके किसी भी ऐप्लिकेशन पर खोला नहीं जा सकता"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"यह कॉन्टेंट आपके किसी भी निजी ऐप्लिकेशन पर खोला नहीं जा सकता"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"क्या <xliff:g id="APP">%s</xliff:g> को निजी प्रोफ़ाइल में खोलना है?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"क्या <xliff:g id="APP">%s</xliff:g> को वर्क प्रोफ़ाइल में खोलना है?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"निजी ब्राउज़र का इस्तेमाल करें"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"ऑफ़िस के काम से जुड़े ब्राउज़र का इस्तेमाल करें"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"टेक्स्ट हटाएं"</string>
+ <string name="include_text" msgid="642280283268536140">"टेक्स्ट जोड़ें"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"लिंक हटाएं"</string>
+ <string name="include_link" msgid="827855767220339802">"लिंक जोड़ें"</string>
+</resources>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
new file mode 100644
index 00000000..ef08630e
--- /dev/null
+++ b/java/res/values-hr/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Radnju dovrši pomoću stavke"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Radnju dovrši pomoću aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Dovrši radnju"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Otvaranje pomoću aplikacije"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Otvori s aplikacijom <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Otvori"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Otvaranje veza sa stranice <xliff:g id="HOST">%1$s</xliff:g> u aplikaciji"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Otvaranje veza u aplikaciji"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Otvaranje veza u aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Otvaranje veza s <xliff:g id="HOST">%1$s</xliff:g> u aplikaciji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Omogući pristup"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Uređivanje pomoću aplikacije"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Uredi pomoću alata <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Uredi"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Dijeljenje"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Dijeli s aplikacijom<xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Dijeli"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Pošalji aplikacijom"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Pošalji putem aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Pošalji"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Odaberite početnu aplikaciju"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Upotrijebi aplikaciju <xliff:g id="APP">%1$s</xliff:g> kao aplikaciju početnog zaslona"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Snimi sliku"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Snimi sliku aplikacijom"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Snimi sliku aplikacijom <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Snimi sliku"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Upotrijebite neku drugu aplikaciju"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Odaberi radnju"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Tu radnju ne može izvesti nijedna aplikacija."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Ovu aplikaciju upotrebljavate izvan svog radnog profila"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Upotrebljavate tu aplikaciju u radnom profilu"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Uvijek"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Samo jednom"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> ne podržava poslovni profil"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Prikvači aplikaciju <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Otkvači sudionika <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Uredi"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} i # datoteka}one{{file_name} i # datoteka}few{{file_name} i # datoteke}other{{file_name} i # datoteka}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # datoteka}one{+ # datoteka}few{+ # datoteke}other{+ # datoteka}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Dijeli se tekst"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Dijeli se veza"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Dijeli se slika}one{Dijeli se # slika}few{Dijele se # slike}other{Dijeli se # slika}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Dijeli se videozapis}one{Dijeli se # videozapis}few{Dijele se # videozapisa}other{Dijeli se # videozapisa}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Dijeli se # stavka}one{Dijeli se # stavka}few{Dijele se # stavke}other{Dijeli se # stavki}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Dijeli se slika s tekstom"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Dijeli se slika s vezom"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Nema preporučenih osoba za dijeljenje"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Popis aplikacija"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Ta aplikacija nema dopuštenje za snimanje, no mogla bi primati zvuk putem ovog USB uređaja."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Osobno"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Posao"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Osobni prikaz"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Poslovni prikaz"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blokirao vaš IT administrator"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Taj se sadržaj ne može dijeliti pomoću poslovnih aplikacija"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Taj se sadržaj ne može otvoriti pomoću poslovnih aplikacija"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Taj se sadržaj ne može dijeliti pomoću osobnih aplikacija"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Taj se sadržaj ne može otvoriti pomoću osobnih aplikacija"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Poslovni profil je pauziran"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Dodirnite da biste uključili"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Poslovne aplikacije nisu dostupne"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Osobne aplikacije nisu dostupne"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Želite li otvoriti aplikaciju <xliff:g id="APP">%s</xliff:g> na osobnom profilu?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Želite li otvoriti aplikaciju <xliff:g id="APP">%s</xliff:g> na poslovnom profilu?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Koristi osobni preglednik"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Koristi poslovni preglednik"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Isključi tekst"</string>
+ <string name="include_text" msgid="642280283268536140">"Uključi tekst"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Isključi vezu"</string>
+ <string name="include_link" msgid="827855767220339802">"Uključi vezu"</string>
+</resources>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
new file mode 100644
index 00000000..15b79c6d
--- /dev/null
+++ b/java/res/values-hu/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Művelet végrehajtása a következővel:"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Művelet végrehajtása a következővel: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Művelet végrehajtása"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Megnyitás a következővel:"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Megnyitás a következővel: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Megnyitás"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g>-linkek megnyitása a következővel:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Linkek megnyitása a következővel:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Linkek megnyitása a következővel: <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g>-linkek megnyitása a következővel: <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Engedély megadása"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Szerkesztés a következővel:"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Szerkesztés a következővel: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Szerkesztés"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Megosztás"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Megosztás a következővel: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Megosztás"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Küldés a következővel:"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Küldés a következővel: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Küldés"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Válasszon kezdőalkalmazást"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"A(z) <xliff:g id="APP">%1$s</xliff:g> használata kezdőalkalmazásként"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Kép készítése"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Kép készítése a következővel:"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Kép készítése a következővel: <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Kép készítése"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Használjon másik alkalmazást"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Válasszon műveletet"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Egy alkalmazás sem tudja végrehajtani ezt a műveletet."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Ezt az alkalmazást munkaprofilján kívül használja"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Munkaprofiljában már használja az alkalmazást"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Mindig"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Csak egyszer"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"A(z) <xliff:g id="APP">%1$s</xliff:g> nem támogatja a munkaprofilt"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> kitűzése"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> rögzítésének feloldása"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Szerkesztés"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # fájl}other{{file_name} + # fájl}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # fájl}other{+ # fájl}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Szöveg megosztása"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Link megosztása"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Kép megosztása}other{# kép megosztása}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Videó megosztása}other{# videó megosztása}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# elem megosztása}other{# elem megosztása}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Kép megosztása szöveggel…"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Kép megosztása linkkel…"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Nincsenek ajánlott személyek a megosztáshoz"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Alkalmazások listája"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Ez az alkalmazás nem rendelkezik rögzítési engedéllyel, de ezzel az USB-eszközzel képes a hangfelvételre."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Személyes"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Munka"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Személyes nézet"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Munkanézet"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Rendszergazda által letiltva"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Ez a tartalom nem osztható meg munkahelyi alkalmazásokkal"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Ez a tartalom nem nyitható meg munkahelyi alkalmazásokkal"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Ez a tartalom nem osztható meg személyes alkalmazásokkal"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Ez a tartalom nem nyitható meg személyes alkalmazásokkal"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"A munkaprofil használata szünetel"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Koppintson a bekapcsoláshoz"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Nincs munkahelyi alkalmazás"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Nincs személyes alkalmazás"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Megnyitja a(z) <xliff:g id="APP">%s</xliff:g> alkalmazást a személyes profil használatával?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Megnyitja a(z) <xliff:g id="APP">%s</xliff:g> alkalmazást a munkaprofil használatával?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Személyes böngésző használata"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Munkahelyi böngésző használata"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Szöveg eltávolítása"</string>
+ <string name="include_text" msgid="642280283268536140">"Szöveggel együtt"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Link eltávolítása"</string>
+ <string name="include_link" msgid="827855767220339802">"Linkkel együtt"</string>
+</resources>
diff --git a/java/res/values-hy/strings.xml b/java/res/values-hy/strings.xml
new file mode 100644
index 00000000..64f1b7f6
--- /dev/null
+++ b/java/res/values-hy/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Ավարտել գործողությունը` օգտագործելով"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Ավարտել գործողությունը <xliff:g id="APP">%1$s</xliff:g> հավելվածի միջոցով"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Ավարտել գործողությունը"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Բացել հետևյալ ծրագրով՝"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Բացել <xliff:g id="APP">%1$s</xliff:g> հավելվածի միջոցով"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Բացել"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> տեսակի հղումները բացել…"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Հղումները բացել այս հավելվածով…"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Հղումները բացել <xliff:g id="APPLICATION">%1$s</xliff:g> դիտարկիչում"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> տեսակի հղումները բացել <xliff:g id="APPLICATION">%2$s</xliff:g> դիտարկիչում"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Թույլատրել"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Խմբագրել հետևյալ ծրագրով՝"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Խմբագրել <xliff:g id="APP">%1$s</xliff:g> հավելվածի միջոցով"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Փոփոխել"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Կիսվել"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Կիսվել <xliff:g id="APP">%1$s</xliff:g> հավելվածի միջոցով"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Կիսվել"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Ուղարկել այս հավելվածով"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Ուղարկել <xliff:g id="APP">%1$s</xliff:g> հավելվածի միջոցով"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Ուղարկել"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Ընտրեք Հիմնական հավելվածը"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Օգտագործել <xliff:g id="APP">%1$s</xliff:g> հավելվածը որպես հիմնական էկրան"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Լուսանկարել"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Լուսանկարել այս հավելվածի օգնությամբ"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Լուսանկարել <xliff:g id="APP">%1$s</xliff:g> հավելվածի միջոցով"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Լուսանկարել"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Ուրիշ հավելված"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Ընտրեք գործողություն"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Ոչ մի հավելված չի կարող կատարել այս գործողությունը:"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Դուք օգտագործում եք այս հավելվածը ձեր աշխատանքային պրոֆիլից դուրս"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Դուք օգտագործում եք այս հավելվածը ձեր աշխատանքային պրոֆիլում"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Միշտ"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Միայն այս անգամ"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> հավելվածն աշխատանքային պրոֆիլներ չի աջակցում"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Ամրացնել <xliff:g id="LABEL">%1$s</xliff:g> հավելվածը"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Ապամրացնել <xliff:g id="LABEL">%1$s</xliff:g> հավելվածը"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Փոփոխել"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} ու ևս # ֆայլ}one{{file_name} ու ևս # ֆայլ}other{{file_name} ու ևս # ֆայլ}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ֆայլ}one{# ֆայլ}other{# ֆայլ}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Տեքստի ուղարկում"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Հղման ուղարկում"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Պատկերի ուղարկում}one{# պատկերի ուղարկում}other{# պատկերի ուղարկում}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Տեսանյութի ուղարկում}one{# տեսանյութի ուղարկում}other{# տեսանյութի ուղարկում}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# տարրի ուղարկում}one{# տարրի ուղարկում}other{# տարրի ուղարկում}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Պատկերի+տեքստի ուղարկում"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Պատկերի և հղման ուղարկում"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Չկան օգտատերեր, որոնց հետ կարող եք կիսվել"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Հավելվածների ցանկ"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Հավելվածը ձայնագրելու թույլտվություն չունի, սակայն կկարողանա գրանցել ձայնն այս USB սարքի միջոցով։"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Անձնական"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Աշխատանքային"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Անձնական"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Աշխատանքային"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Արգելափակվել է ձեր ՏՏ ադմինիստրատորի կողմից"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Այս բովանդակությունը հնարավոր չէ ուղարկել աշխատանքային հավելվածներով"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Այս բովանդակությունը հնարավոր չէ բացել աշխատանքային հավելվածներով"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Այս բովանդակությունը հնարավոր չէ ուղարկել անձնական հավելվածներով"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Այս բովանդակությունը հնարավոր չէ բացել անձնական հավելվածներով"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Աշխատանքային պրոֆիլի ծառայությունը դադարեցված է"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Հպեք միացնելու համար"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Աշխատանքային հավելվածներ չկան"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Անձնական հավելվածներ չկան"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Բացե՞լ <xliff:g id="APP">%s</xliff:g> հավելվածը ձեր անձնական պրոֆիլում"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Բացե՞լ <xliff:g id="APP">%s</xliff:g> հավելվածը ձեր աշխատանքային պրոֆիլում"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Օգտագործել անձնական դիտարկիչը"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Օգտագործել աշխատանքային դիտարկիչը"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Բացառել տեքստը"</string>
+ <string name="include_text" msgid="642280283268536140">"Ներառել տեքստը"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Բացառել հղումը"</string>
+ <string name="include_link" msgid="827855767220339802">"Ներառել հղումը"</string>
+</resources>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
new file mode 100644
index 00000000..5c5ba638
--- /dev/null
+++ b/java/res/values-in/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Selesaikan tindakan menggunakan"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Selesaikan tindakan menggunakan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Selesaikan tindakan"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Buka dengan"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Buka dengan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Buka"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Buka link <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Buka link dengan"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Buka link dengan <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Buka link <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Berikan akses"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Edit dengan"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Edit dengan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Edit"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Bagikan"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Berbagi menggunakan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Bagikan"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Kirim menggunakan"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Kirim menggunakan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Kirim"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Pilih aplikasi Beranda"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Gunakan <xliff:g id="APP">%1$s</xliff:g> sebagai aplikasi Layar utama"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Jepret gambar"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Jepret gambar dengan"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Ambil gambar dengan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Jepret gambar"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Gunakan aplikasi yang berbeda"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Pilih tindakan"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Tidak ada apl yang dapat melakukan tindakan ini."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Anda menggunakan aplikasi ini di luar profil kerja"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Anda menggunakan aplikasi ini di profil kerja"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Selalu"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Sekali ini saja"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> tidak mendukung profil kerja"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Sematkan <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Lepas sematan <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Edit"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # file}other{{file_name} + # file}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # file}other{+ # file}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Membagikan teks"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Membagikan link"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Membagikan gambar}other{Membagikan # gambar}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Membagikan video}other{Membagikan # video}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Membagikan # item}other{Membagikan # item}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Membagikan gambar dengan teks"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Membagikan gambar dengan link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Tidak ada rekomendasi kontak untuk berbagi"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Daftar aplikasi"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Aplikasi ini tidak diberi izin merekam, tetapi dapat merekam audio melalui perangkat USB ini."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Pribadi"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Kerja"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Tampilan pribadi"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Tampilan kerja"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Diblokir oleh admin IT Anda"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Konten ini tidak dapat dibagikan dengan aplikasi kerja"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Konten ini tidak dapat dibuka dengan aplikasi kerja"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Konten ini tidak dapat dibagikan dengan aplikasi pribadi"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Konten ini tidak dapat dibuka dengan aplikasi pribadi"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Profil kerja dijeda"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Ketuk untuk mengaktifkan"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Tidak ada aplikasi kerja"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Tidak ada aplikasi pribadi"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Buka <xliff:g id="APP">%s</xliff:g> di profil pribadi?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Buka <xliff:g id="APP">%s</xliff:g> di profil kerja?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Gunakan browser pribadi"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Gunakan browser kerja"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Kecualikan teks"</string>
+ <string name="include_text" msgid="642280283268536140">"Sertakan teks"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Kecualikan link"</string>
+ <string name="include_link" msgid="827855767220339802">"Sertakan link"</string>
+</resources>
diff --git a/java/res/values-is/strings.xml b/java/res/values-is/strings.xml
new file mode 100644
index 00000000..04a99b79
--- /dev/null
+++ b/java/res/values-is/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Ljúka aðgerð með"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Ljúka aðgerð með <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Ljúka aðgerð"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Opna með"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Opna með <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Opna"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Opna <xliff:g id="HOST">%1$s</xliff:g> tengla með"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Opna tengla með"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Opna tengla með <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Opna <xliff:g id="HOST">%1$s</xliff:g> tengla með <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Veita aðgang"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Breyta með"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Breyta með <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Breyta"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Deila"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Deila með <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Deila"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Senda með því að nota"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Senda með <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Senda"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Veldu heimaforrit"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Nota <xliff:g id="APP">%1$s</xliff:g> sem heimaforrit"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Taka mynd"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Taka mynd með"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Taka mynd með <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Taka mynd"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Nota annað forrit"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Veldu aðgerð"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Engin forrit geta framkvæmt þessa aðgerð."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Þú ert að nota þetta forrit utan vinnusniðsins"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Þú ert að nota þetta forrit á vinnusniðinu þínu"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Alltaf"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Bara einu sinni"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> styður ekki vinnusnið"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Festa <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Losa <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Breyta"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # skrá}one{{file_name} + # skrá}other{{file_name} + # skrár}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # skrá}one{+ # skrá}other{+ # skrár}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Deilir texta"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Deilir tengli"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Deilir mynd}one{Deilir # mynd}other{Deilir # myndum}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Deilir myndskeiði}one{Deilir # myndskeiði}other{Deilir # myndskeiðum}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Deilir # atriði}one{Deilir # atriði}other{Deilir # atriðum}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Deilir mynd með texta"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Deilir mynd með tengli"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Engar tillögur um fólk til að deila með"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Forritalisti"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Þetta forrit hefur ekki fengið heimild fyrir upptöku en gæti tekið upp hljóð í gegnum þetta USB-tæki."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Persónulegt"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Vinna"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Persónulegt yfirlit"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Vinnuyfirlit"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Útilokað af kerfisstjóra"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Ekki er hægt að deila þessu efni með vinnuforritum"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Ekki er hægt að opna þetta efni með vinnuforritum"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Ekki er hægt að deila þessu efni með forritum til einkanota"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Ekki er hægt að opna þetta efni með forritum til einkanota"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Hlé gert á vinnusniði"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Ýttu til að kveikja"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Engin vinnuforrit"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Engin forrit til einkanota"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Opna <xliff:g id="APP">%s</xliff:g> í þínu eigin sniði?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Opna <xliff:g id="APP">%s</xliff:g> í vinnusniðinu þínu?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Nota einkavafra"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Nota vinnuvafra"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Útiloka texta"</string>
+ <string name="include_text" msgid="642280283268536140">"Hafa texta með"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Útiloka tengil"</string>
+ <string name="include_link" msgid="827855767220339802">"Hafa tengil með"</string>
+</resources>
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
new file mode 100644
index 00000000..dc23c628
--- /dev/null
+++ b/java/res/values-it/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Completa l\'azione con"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Completa l\'azione con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Completa azione"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Apri con"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Apri con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Apri"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Apri i link <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Apri i link con"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Apri i link con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Apri i link <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Fornisci accesso"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Modifica con"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Modifica con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Modifica"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Condividi"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Condividi tramite <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Condividi"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Invia tramite"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Invia tramite <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Invia"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Seleziona un\'app Home"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Usa <xliff:g id="APP">%1$s</xliff:g> come Home"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Acquisisci immagine"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Acquisisci immagine con"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Acquisisci immagine con <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Acquisisci immagine"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Utilizza un\'app diversa"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Scegli un\'azione"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Nessuna applicazione è in grado di eseguire questa azione."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Stai utilizzando l\'app al di fuori del tuo profilo di lavoro"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Stai utilizzando l\'app nel tuo profilo di lavoro"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Sempre"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Solo una volta"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> non supporta il profilo di lavoro"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fissa <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Sblocca <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Modifica"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # file}many{{file_name} + # file}other{{file_name} + # file}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # file}many{+ # file}other{+ # file}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Condivisione del testo…"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Condivisione del link…"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Condivisione immagine…}many{Condivis. di # immagini…}other{Condivis. di # immagini…}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Condivisione del video…}many{Condivisione di # video…}other{Condivisione di # video…}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Condivis. di # elemento…}many{Condivis. di # elementi…}other{Condivis. di # elementi…}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Condivis. img con testo…"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Condivis. img con link…"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Nessuna persona consigliata per la condivisione"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Elenco di app"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"A questa app non è stata concessa l\'autorizzazione di registrazione, ma l\'app potrebbe acquisire l\'audio tramite questo dispositivo USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personale"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Lavoro"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Visualizzazione personale"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Visualizzazione di lavoro"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Bloccati dall\'amministratore IT"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Questi contenuti non possono essere condivisi con app di lavoro"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Questi contenuti non possono essere aperti con app di lavoro"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Questi contenuti non possono essere condivisi con app personali"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Questi contenuti non possono essere aperti con app personali"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Profilo di lavoro in pausa"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Tocca per attivare"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Nessuna app di lavoro"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Nessuna app personale"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Aprire <xliff:g id="APP">%s</xliff:g> nel tuo profilo personale?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Aprire <xliff:g id="APP">%s</xliff:g> nel tuo profilo di lavoro?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Usa il browser personale"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Usa il browser di lavoro"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Escludi testo"</string>
+ <string name="include_text" msgid="642280283268536140">"Includi testo"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Escludi link"</string>
+ <string name="include_link" msgid="827855767220339802">"Includi link"</string>
+</resources>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
new file mode 100644
index 00000000..62ff1d89
--- /dev/null
+++ b/java/res/values-iw/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"השלמת הפעולה עם"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"השלמת הפעולה באמצעות <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"להשלמת הפעולה"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"פתיחה באמצעות"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"פתיחה באמצעות <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"פתיחה"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"פתיחת קישורים של <xliff:g id="HOST">%1$s</xliff:g> באמצעות"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"פתיחת קישורים באמצעות"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"פתיחת קישורים באמצעות <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"פתיחת קישורים של <xliff:g id="HOST">%1$s</xliff:g> באמצעות <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"הענקת גישה"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"עריכה באמצעות"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"עריכה באמצעות <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"עריכה"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"שיתוף"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"שיתוף עם <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"שיתוף"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"שליחה באמצעות"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"שליחה באמצעות <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"שליחה"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"בחירת אפליקציה שתשמש כדף הבית"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"שימוש באפליקציה <xliff:g id="APP">%1$s</xliff:g> בתור \'בית\'"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"צילום תמונה"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"צילום תמונה באמצעות"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"צילום תמונה באמצעות <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"צילום תמונה"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"שימוש באפליקציה אחרת"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"בחירת פעולה"</string>
+ <string name="noApplications" msgid="1139487441772284671">"אין אפליקציות שיכולות לבצע את הפעולה הזו."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"בחרת להשתמש באפליקציה הזאת מחוץ לפרופיל העבודה שלך"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"נעשה שימוש באפליקציה הזו בפרופיל העבודה שלך"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"תמיד"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"רק פעם אחת"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"האפליקציה <xliff:g id="APP">%1$s</xliff:g> לא תומכת בפרופיל עבודה"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"הצמדה של <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"ביטול ההצמדה של <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"עריכה"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} ועוד קובץ אחד}one{{file_name} ועוד # קבצים}two{{file_name} ועוד # קבצים}other{{file_name} ועוד # קבצים}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ קובץ אחד}one{+ # קבצים}two{+ # קבצים}other{+ # קבצים}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"שיתוף הטקסט מתבצע"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"שיתוף הקישור מתבצע"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{מתבצע שיתוף של תמונה}one{מתבצע שיתוף של # תמונות}two{מתבצע שיתוף של # תמונות}other{מתבצע שיתוף של # תמונות}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{מתבצע שיתוף של סרטון}one{מתבצע שיתוף של # סרטונים}two{מתבצע שיתוף של # סרטונים}other{מתבצע שיתוף של # סרטונים}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{מתבצע שיתוף של פריט אחד (#)}one{מתבצע שיתוף של # פריטים}two{מתבצע שיתוף של # פריטים}other{מתבצע שיתוף של # פריטים}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"שיתוף תמונה עם טקסט"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"שיתוף תמונה עם קישור"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"אין אנשים שניתן לשתף איתם"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"רשימת האפליקציות"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"‏לאפליקציה זו לא ניתנה הרשאת הקלטה, אבל אפשר להקליט אודיו באמצעות התקן ה-USB הזה."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"אישי"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"עבודה"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"תצוגה אישית"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"תצוגת עבודה"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"‏נחסם על ידי מנהל ה-IT"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"אי אפשר לשתף את התוכן הזה עם אפליקציות לעבודה"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"אי אפשר לפתוח את התוכן הזה באמצעות אפליקציות לעבודה"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"אי אפשר לשתף את התוכן הזה עם אפליקציות לשימוש אישי"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"אי אפשר לפתוח את התוכן הזה באמצעות אפליקציות לשימוש אישי"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"פרופיל העבודה מושהה"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"יש להקיש כדי להפעיל את פרופיל העבודה"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"אין אפליקציות לעבודה"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"אין אפליקציות לשימוש אישי"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"לפתוח את <xliff:g id="APP">%s</xliff:g> בפרופיל האישי?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"לפתוח את <xliff:g id="APP">%s</xliff:g> בפרופיל העבודה?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"בדפדפן האישי"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"בדפדפן של העבודה"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"החרגת הטקסט"</string>
+ <string name="include_text" msgid="642280283268536140">"הכללת הטקסט"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"החרגת הקישור"</string>
+ <string name="include_link" msgid="827855767220339802">"הכללת הקישור"</string>
+</resources>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
new file mode 100644
index 00000000..0e0751d8
--- /dev/null
+++ b/java/res/values-ja/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"アプリケーションを選択"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> を使用してアクションを完了"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"アクションを実行"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"アプリで開く"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> で開く"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"開く"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> のリンクを開くブラウザ / アプリの選択"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"リンクを開くブラウザの選択"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> でリンクを開く"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="APPLICATION">%2$s</xliff:g> で <xliff:g id="HOST">%1$s</xliff:g> のリンクを開く"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"アクセスを許可"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"編集に使用"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> で編集"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"編集"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"共有"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> と共有"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"共有"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"送信に使用するアプリ"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> で送信"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"送信"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"ホームアプリを選択"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> をホームとして使用"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"画像をキャプチャ"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"画像のキャプチャに使用するアプリ"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> で画像をキャプチャ"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"画像をキャプチャ"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"別のアプリを使用"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"操作の選択"</string>
+ <string name="noApplications" msgid="1139487441772284671">"この操作を実行できるアプリはありません。"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"仕事用プロファイルの外部でこのアプリを使用しています"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"仕事用プロファイルでこのアプリを使用しています"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"常時"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"1 回のみ"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> は仕事用プロファイルをサポートしていません"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> を固定"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> の固定を解除"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"編集"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name}、他 # ファイル}other{{file_name}、他 # ファイル}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{他 # 件のファイル}other{他 # 件のファイル}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"テキストを共有しています"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"リンクを共有しています"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{画像を共有中}other{# 枚の画像を共有中}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{動画を共有中}other{# 個の動画を共有中}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# 個のアイテムを共有中}other{# 個のアイテムを共有中}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"テキスト付き画像を共有中"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"リンク付き画像を共有中"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"おすすめの共有相手はいません"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"アプリのリスト"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"このアプリに録音権限は付与されていませんが、この USB デバイスから音声を収集できるようになります。"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"個人用"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"仕事用"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"個人用ビュー"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"仕事用ビュー"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"IT 管理者によりブロックされました"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"このコンテンツを仕事用アプリと共有することはできません"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"このコンテンツを仕事用アプリで開くことはできません"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"このコンテンツを個人用アプリと共有することはできません"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"このコンテンツを個人用アプリで開くことはできません"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"仕事用プロファイルが一時停止しています"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"タップして ON にする"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"仕事用アプリはありません"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"個人用アプリはありません"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"個人用プロファイルで <xliff:g id="APP">%s</xliff:g> を開きますか?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"仕事用プロファイルで <xliff:g id="APP">%s</xliff:g> を開きますか?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"個人用ブラウザを使用"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"仕事用ブラウザを使用"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"テキストを除外"</string>
+ <string name="include_text" msgid="642280283268536140">"テキストを含める"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"リンクを除外"</string>
+ <string name="include_link" msgid="827855767220339802">"リンクを含める"</string>
+</resources>
diff --git a/java/res/values-ka/strings.xml b/java/res/values-ka/strings.xml
new file mode 100644
index 00000000..5c6e0462
--- /dev/null
+++ b/java/res/values-ka/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"რა გამოვიყენოთ?"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"მოქმედების შესრულება <xliff:g id="APP">%1$s</xliff:g> აპის დახმარებით"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"მოქმედების დასრულება"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"გახსნა აპით"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> აპით გახსნა"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"გახსნა"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> ბმულების გახსნა შემდეგით:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"ბმულების გახსნა შემდეგით:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"ბმულების გახსნა <xliff:g id="APPLICATION">%1$s</xliff:g>-ით"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> ბმულების <xliff:g id="APPLICATION">%2$s</xliff:g>-ით გახსნა"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"წვდომის მიცემა"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"რედაქტირება აპით:"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> აპით რედაქტირება"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"რედაქტირება"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"გაზიარება"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> აპით გაზიარება"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"გაზიარება"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"გაგზავნა:"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> აპით გაგზავნა"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"გაგზავნა"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"აირჩიეთ Home აპი"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g>-ის მთავარ აპად გამოყენება"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"სურათის აღბეჭდვა"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"სურათის აღბეჭდვა აპით"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"სურათის აღბეჭდვა <xliff:g id="APP">%1$s</xliff:g> აპით"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"სურათის აღბეჭდვა"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"სხვა აპის გამოყენება"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"აირჩიეთ მოქმედება"</string>
+ <string name="noApplications" msgid="1139487441772284671">"ვერც ერთი აპი ვერ შეასრულებს ამ ქმედებას."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"იყენებთ ამ აპს თქვენს სამუშაო პროფილს მიღმა"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"ამ აპს თქვენს სამუშაო პროფილში იყენებთ"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"ყოველთვის"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"მხოლოდ ერთხელ"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g>-ს არ აქვს სამსახურის პროფილის მხარდაჭერა"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g>-ის ჩამაგრება"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g>-ის ჩამაგრების მოხსნა"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"რედაქტირება"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ფაილი}other{{file_name} + # ფაილი}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ფაილი}other{+ # ფაილი}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"ზიარდება ტექსტი"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"ზიარდება ბმული"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{ზიარდება სურათი}other{ზიარდება # სურათი}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{ზიარდება ვიდეო}other{ზიარდება # ვიდეო}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{ზიარდება # ერთეული}other{ზიარდება # ერთეული}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"სურათი ზიარდება ტექსტით"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"სურათი ზიარდება ბმულით"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"ვერ იძებნება რეკომენდებული ადამიანები, რომლებთანაც გაზიარება შეიძლება"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"აპების სია"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"ამ აპს არ აქვს მინიჭებული ჩაწერის ნებართვა, მაგრამ შეუძლია ჩაიწეროს აუდიო ამ USB მოწყობილობის მეშვეობით."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"პირადი"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"სამსახური"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"პირადი ხედი"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"სამსახურის ხედი"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"დაბლოკილია თქვენი IT-ადმინისტრატორის მიერ"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"ამ კონტენტის სამსახურის აპებისთვის გაზიარება შეუძლებელია"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"ამ კონტენტის სამსახურის აპებით გახსნა შეუძლებელია"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"ამ კონტენტის პირადი აპებისთვის გაზიარება შეუძლებელია"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"ამ კონტენტის პირადი აპებით გახსნა შეუძლებელია"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"სამსახურის პროფილი დაპაუზებულია"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"შეეხეთ ჩასართავად"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"სამსახურის აპები არ არის"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"პირადი აპები არ არის"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"გსურთ <xliff:g id="APP">%s</xliff:g>-ის გახსნა თქვენს პირად პროფილში?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"გსურთ <xliff:g id="APP">%s</xliff:g>-ის გახსნა თქვენს სამსახურის პროფილში?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"პირადი ბრაუზერის გამოყენება"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"სამსახურის ბრაუზერის გამოყენება"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"ტექსტის ამოღება"</string>
+ <string name="include_text" msgid="642280283268536140">"ტექსტის ჩასმა"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"ბმულის ამოღება"</string>
+ <string name="include_link" msgid="827855767220339802">"ბმულის დართვა"</string>
+</resources>
diff --git a/java/res/values-kk/strings.xml b/java/res/values-kk/strings.xml
new file mode 100644
index 00000000..94ff2581
--- /dev/null
+++ b/java/res/values-kk/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Әрекетті аяқтау"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> көмегімен әрекетті орындау"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Әрекетті аяқтау"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Басқаша ашу"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> арқылы ашу"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Ашу"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> сілтемелерін келесімен ашу:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Сілтемелерді келесімен ашу:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Сілтемелерді <xliff:g id="APPLICATION">%1$s</xliff:g> браузерімен ашу"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> сілтемелерін <xliff:g id="APPLICATION">%2$s</xliff:g> браузерімен ашу"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Рұқсат беру"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Келесімен өңдеу"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> арқылы өзгерту"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Өңдеу"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Бөлісу"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> арқылы бөлісу"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Бөлісу"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Келесі арқылы жіберу"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> көмегімен жіберу"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Жіберу"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"«Негізгі» қолданбасын таңдау"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> қолданбасын Үй қолданбасы ретінде пайдалану"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Кескін түсіру"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Кескінді түсіру қолданбасы"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> арқылы суретке түсіру"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Кескін түсіру"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Басқа қолданбаны пайдалану"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Әрекет таңдау"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Бұл әрекетті ешбір қолданба орындай алмайды."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Осы қолданбаны жұмыс профиліңізден тыс пайдаланып жатырсыз"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Осы қолданбаны жұмыс профиліңізде пайдаланып жатырсыз"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Әрқашан"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Бір рет қана"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> жұмыс профиліне қолдау көрсетпейді."</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> бекіту"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> босату"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Өзгерту"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # файл}other{{file_name} + # файл}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # файл}other{+ # файл}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Мәтін бөлісіліп жатыр"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Сілтеме бөлісіліп жатыр"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Сурет бөлісіліп жатыр}other{# сурет бөлісіліп жатыр}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Бейне бөлісіліп жатыр}other{# бейне бөлісіліп жатыр}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# элемент бөлісіліп жатыр}other{# элемент бөлісіліп жатыр}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Сурет мәтінімен бөлісіліп жатыр"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Сурет сілтемесімен бөлісіліп жатыр"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Бөлісу үшін ұсынылатын адамдар жоқ."</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Қолданбалар тізімі"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Қолданбаға жазу рұқсаты берілмеді, бірақ ол осы USB құрылғысы арқылы дыбыс жаза алады."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Жеке"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Жұмыс"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Жеке көру"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Жұмыс деректерін көру"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Әкімшіңіз бөгеген"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Бұл контентті жұмыс қолданбаларымен бөлісу мүмкін емес."</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Бұл контентті жұмыс қолданбаларымен ашу мүмкін емес."</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Бұл контентті жеке қолданбалармен бөлісу мүмкін емес."</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Бұл контентті жеке қолданбалармен ашу мүмкін емес."</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Жұмыс профилі кідіртілді."</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Қосу үшін түртіңіз"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Жұмыс қолданбалары жоқ."</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Жеке қолданбалар жоқ."</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g> қолданбасын жеке профиліңізде ашу керек пе?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g> қолданбасын жұмыс профиліңізде ашу керек пе?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Жеке браузерді пайдалану"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Жұмыс браузерін пайдалану"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Мәтінді шығару"</string>
+ <string name="include_text" msgid="642280283268536140">"Мәтін қосу"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Сілтемені шығару"</string>
+ <string name="include_link" msgid="827855767220339802">"Сілтеме қосу"</string>
+</resources>
diff --git a/java/res/values-km/strings.xml b/java/res/values-km/strings.xml
new file mode 100644
index 00000000..9d069d8a
--- /dev/null
+++ b/java/res/values-km/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"បញ្ចប់​សកម្មភាព​ដោយ​ប្រើ"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"បញ្ចប់​សកម្មភាព​ដោយ​ប្រើ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"បញ្ចប់សកម្មភាព"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"បើក​ជា​មួយ"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"បើក​ដោយ​ប្រើ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"បើក"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"បើក​តំណ <xliff:g id="HOST">%1$s</xliff:g> ដោយប្រើ"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"បើកតំណដោយប្រើ"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"បើក​តំណដោយប្រើ <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"បើក​តំណ <xliff:g id="HOST">%1$s</xliff:g> ដោយប្រើ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"ផ្តល់សិទ្ធិចូលប្រើ"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"កែសម្រួល​ជាមួយ"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"កែដោយប្រើ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"កែ"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"ចែករំលែក"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"ចែក​រំលែក​ជា​មួយ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"ចែករំលែក"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"ផ្ញើដោយប្រើ"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"ផ្ញើដោយប្រើ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"ផ្ញើ"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"ជ្រើសរើស​កម្មវិធីអេក្រង់​ដើម"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"ប្រើ <xliff:g id="APP">%1$s</xliff:g> ជាកម្មវិធីដើម"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"ថតរូប"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"ថតរូបជាមួយ"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"ថតរូបដោយប្រើ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"ថតរូប"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"ប្រើ​កម្មវិធី​ផ្សេង"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"ជ្រើសរើស​សកម្មភាព​​"</string>
+ <string name="noApplications" msgid="1139487441772284671">"មិន​មាន​​កម្មវិធី​ដែលអាចធ្វើ​សកម្មភាពនេះ​បាន​ទេ។"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"អ្នក​កំពុង​ប្រើ​កម្មវិធី​នេះ​នៅ​ខាងក្រៅ​ប្រវត្តិរូប​​ការងារ​របស់​អ្នក"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"អ្នក​កំពុង​ប្រើ​កម្មវិធី​នេះ​ក្នុង​ប្រវត្តិរូប​ការងារ​របស់​អ្នក"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"ជា​និច្ច"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"តែ​ម្ដង"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> មិនស្គាល់​កម្រងព័ត៌មាន​ការងារ​ទេ"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"ខ្ទាស់ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"ដកខ្ទាស់ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"កែ"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + ឯកសារ #}other{{file_name} + ឯកសារ #}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ឯកសារ}other{+ # ឯកសារ}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"កំពុងចែករំលែក​សារជាអក្សរ"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"កំពុងចែករំលែកតំណ"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{កំពុងចែក​រំលែករូបភាព}other{កំពុងចែក​រំលែករូបភាព #}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{កំពុងចែករំលែកវីដេអូ}other{កំពុងចែករំលែកវីដេអូ #}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{កំពុងចែករំលែកធាតុ #}other{កំពុងចែករំលែកធាតុ #}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"ចែករំលែករូបភាពជាមួយអក្សរ"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"ចែករំលែករូបភាពជាមួយតំណ"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"មិនមាន​មនុស្សដែល​បានណែនាំ​សម្រាប់​ចែករំលែក​ជាមួយទេ"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"បញ្ជីកម្មវិធី"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"កម្មវិធីនេះ​មិនទាន់បាន​ទទួលសិទ្ធិ​ថតសំឡេង​នៅឡើយទេ ប៉ុន្តែអាច​ថតសំឡេង​តាមរយៈ​ឧបករណ៍ USB នេះបាន។"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"ផ្ទាល់ខ្លួន"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"ការងារ"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"ទិដ្ឋភាពផ្ទាល់ខ្លួន"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"ទិដ្ឋភាព​ការងារ"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"បានទប់ស្កាត់ដោយ​អ្នកគ្រប់គ្រង​ផ្នែកព័ត៌មានវិទ្យា​របស់អ្នក"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"ខ្លឹមសារនេះ​មិនអាចចែករំលែក​តាមរយៈ​កម្មវិធី​ការងារ​បានទេ"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"ខ្លឹមសារនេះ​មិនអាចបើក​តាមរយៈ​កម្មវិធី​ការងារ​បានទេ"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"ខ្លឹមសារនេះ​មិនអាចចែករំលែក​តាមរយៈ​កម្មវិធី​ផ្ទាល់ខ្លួន​បានទេ"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"ខ្លឹមសារនេះ​មិនអាចបើក​តាមរយៈ​កម្មវិធី​ផ្ទាល់ខ្លួន​បានទេ"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"កម្រងព័ត៌មានការងារត្រូវបាន​ផ្អាក"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ចុច​ដើម្បី​បើក"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"គ្មាន​កម្មវិធី​ការងារ​ទេ"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"គ្មាន​កម្មវិធី​ផ្ទាល់ខ្លួន​ទេ"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"បើក <xliff:g id="APP">%s</xliff:g> នៅក្នុងកម្រង​ព័ត៌មាន​ផ្ទាល់​ខ្លួនរបស់អ្នកឬ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"បើក <xliff:g id="APP">%s</xliff:g> នៅក្នុងកម្រងព័ត៌មានការងាររបស់អ្នកឬ?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"ប្រើ​កម្មវិធីរុករក​តាមអ៊ីនធឺណិត​ផ្ទាល់ខ្លួន"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"ប្រើ​កម្មវិធីរុករក​តាមអ៊ីនធឺណិត​សម្រាប់​ការងារ"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"មិនរួមបញ្ចូលអក្សរ"</string>
+ <string name="include_text" msgid="642280283268536140">"រួមបញ្ចូលអក្សរ"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"មិនរួមបញ្ចូលតំណ"</string>
+ <string name="include_link" msgid="827855767220339802">"រួមបញ្ចូល​តំណ"</string>
+</resources>
diff --git a/java/res/values-kn/strings.xml b/java/res/values-kn/strings.xml
new file mode 100644
index 00000000..2e6c0fa8
--- /dev/null
+++ b/java/res/values-kn/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> ಬಳಸಿಕೊಂಡು ಕ್ರಿಯೆ ಪೂರ್ಣಗೊಳಿಸಿ"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"ಇದರ ಮೂಲಕ ತೆರೆಯಿರಿ"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> ಜೊತೆ ತೆರೆಯಿರಿ"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"ತೆರೆಯಿರಿ"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"ಇವುಗಳ ಮೂಲಕ <xliff:g id="HOST">%1$s</xliff:g> ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"ಇವುಗಳ ಮೂಲಕ ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> ಮೂಲಕ ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="APPLICATION">%2$s</xliff:g> ಮೂಲಕ <xliff:g id="HOST">%1$s</xliff:g> ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"ಆ್ಯಕ್ಸೆಸ್ ನೀಡಿ"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"ಇವರ ಜೊತೆಗೆ ಎಡಿಟ್ ಮಾಡಿ"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> ಮೂಲಕ ಎಡಿಟ್ ಮಾಡಿ"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"ಎಡಿಟ್"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> ಜೊತೆ ಹಂಚಿಕೊಳ್ಳಿ"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಕಳುಹಿಸಿ"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> ಬಳಸಿ ಕಳುಹಿಸಿ"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"ಕಳುಹಿಸು"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"ಮುಖಪುಟ‌ ಅಪ್ಲಿಕೇಶನ್‌ ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> ಅನ್ನು ಹೋಮ್ ಆಗಿ ಬಳಸಿ"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"ಇದರ ಜೊತೆಗೆ ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> ಮೂಲಕ ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"ಬೇರೊಂದು ಆ್ಯಪ್ ಬಳಸಿ"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"ಕ್ರಿಯೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="noApplications" msgid="1139487441772284671">"ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಈ ಕ್ರಿಯೆಗಾಗಿ ಬದ್ಧತೆ ತೋರಿಸುವುದಿಲ್ಲ."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ನ ಹೊರಗೆ ನೀವು ಈ ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಬಳಸುತ್ತಿರುವಿರಿ"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ನಲ್ಲಿ ನೀವು ಈ ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಬಳಸುತ್ತಿರುವಿರಿ"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"ಯಾವಾಗಲೂ"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"ಒಮ್ಮೆ ಮಾತ್ರ"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> ಪಿನ್ ಮಾಡಿ"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> ಅನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಿ"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"ಎಡಿಟ್"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ಫೈಲ್}one{{file_name} + # ಫೈಲ್‌ಗಳು}other{{file_name} + # ಫೈಲ್‌ಗಳು}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ಫೈಲ್‌}one{+ # ಫೈಲ್‌ಗಳು}other{+ # ಫೈಲ್‌ಗಳು}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"ಪಠ್ಯ ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"ಲಿಂಕ್ ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{ಚಿತ್ರವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ}one{# ಚಿತ್ರಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ}other{# ಚಿತ್ರಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{ವೀಡಿಯೊವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ}one{# ವೀಡಿಯೊಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ}other{# ವೀಡಿಯೊಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# ಐಟಂ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ}one{# ಐಟಂಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ}other{# ಐಟಂಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"ಪಠ್ಯದೊಂದಿಗೆ ಚಿತ್ರವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"ಲಿಂಕ್‌ನೊಂದಿಗೆ ಚಿತ್ರವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"ಹಂಚಿಕೊಳ್ಳಲು ಶಿಫಾರಸು ಮಾಡಲಾದವರು ಯಾರೂ ಇಲ್ಲ"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"ಆ್ಯಪ್‌ಗಳ ಪಟ್ಟಿ"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"ಈ ಆ್ಯಪ್‌ಗೆ ರೆಕಾರ್ಡ್ ಅನುಮತಿಯನ್ನು ನೀಡಲಾಗಿಲ್ಲ, ಆದರೆ ಈ USB ಸಾಧನದ ಮೂಲಕ ಆಡಿಯೊವನ್ನು ಸೆರೆಹಿಡಿಯಬಲ್ಲದು."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"ವೈಯಕ್ತಿಕ"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"ಕೆಲಸ"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"ವೈಯಕ್ತಿಕ ವೀಕ್ಷಣೆ"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"ಕೆಲಸದ ವೀಕ್ಷಣೆ"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರಿಂದ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್‌ಗಳ ಈ ವಿಷಯವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುವುದಿಲ್ಲ"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್‌ಗಳ ಈ ವಿಷಯವನ್ನು ತೆರೆಯಲಾಗುವುದಿಲ್ಲ"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"ವೈಯಕ್ತಿಕ ಆ್ಯಪ್‌ಗಳ ಮೂಲಕ ಈ ವಿಷಯವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುವುದಿಲ್ಲ"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"ವೈಯಕ್ತಿಕ ಆ್ಯಪ್‌ಗಳ ಮೂಲಕ ಈ ವಿಷಯವನ್ನು ತೆರೆಯಲಾಗುವುದಿಲ್ಲ"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ಆನ್‌‌‌ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"ಯಾವುದೇ ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್‌ಗಳಿಲ್ಲ"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"ಯಾವುದೇ ವೈಯಕ್ತಿಕ ಆ್ಯಪ್‌ಗಳಿಲ್ಲ"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಪ್ರೊಫೈಲ್‌ನಲ್ಲಿ <xliff:g id="APP">%s</xliff:g> ಅನ್ನು ತೆರೆಯಬೇಕೆ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್‌ನಲ್ಲಿ <xliff:g id="APP">%s</xliff:g> ಅನ್ನು ತೆರೆಯಬೇಕೆ?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"ವೈಯಕ್ತಿಕ ಬ್ರೌಸರ್ ಬಳಸಿ"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"ಉದ್ಯೋಗ ಬ್ರೌಸರ್ ಬಳಸಿ"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"ಪಠ್ಯವನ್ನು ಹೊರತುಪಡಿಸಿ"</string>
+ <string name="include_text" msgid="642280283268536140">"ಪಠ್ಯವನ್ನು ಸೇರಿಸಿ"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"ಲಿಂಕ್ ಹೊರತುಪಡಿಸಿ"</string>
+ <string name="include_link" msgid="827855767220339802">"ಲಿಂಕ್ ಸೇರಿಸಿ"</string>
+</resources>
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
new file mode 100644
index 00000000..4df2adff
--- /dev/null
+++ b/java/res/values-ko/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"작업을 수행할 때 사용하는 애플리케이션"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> 앱을 사용해 작업 완료"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"작업 완료"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"연결 프로그램"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> 앱으로 열기"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"열기"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> 링크를 열 때 사용할 앱"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"링크를 열 때 사용할 앱"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱으로 링크 열기"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="APPLICATION">%2$s</xliff:g> 앱으로 <xliff:g id="HOST">%1$s</xliff:g> 링크 열기"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"권한 부여"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"편집 프로그램:"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> 앱으로 수정"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"수정"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"공유"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> 앱과 공유"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"공유"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"전송 시 사용할 앱"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> 앱을 사용해 전송"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"전송"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"홈 앱 선택"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> 앱을 홈으로 사용"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"이미지 캡처"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"이미지 캡처에 사용할 앱:"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> 앱으로 이미지 캡처"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"이미지 캡처"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"다른 앱 사용"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"작업 선택"</string>
+ <string name="noApplications" msgid="1139487441772284671">"작업을 수행할 수 있는 앱이 없습니다."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"직장 프로필 외부에서 이 앱을 사용 중입니다."</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"직장 프로필에서 이 앱을 사용 중입니다."</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"항상"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"한 번만"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g>에서 직장 프로필을 지원하지 않음"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> 고정"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> 고정 해제"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"수정"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + 파일 #개}other{{file_name} + 파일 #개}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{외 파일 #개}other{외 파일 #개}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"텍스트 공유 중"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"링크 공유 중"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{이미지 공유 중}other{이미지 #개 공유 중}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{동영상 1개 공유 중}other{동영상 #개 공유 중}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{항목 1개 공유 중}other{항목 #개 공유 중}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"텍스트로 이미지 공유 중"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"링크로 이미지 공유 중"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"공유할 추천 사용자가 없음"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"앱 목록"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"이 앱에는 녹음 권한이 부여되지 않았지만, 이 USB 기기를 통해 오디오를 녹음할 수 있습니다."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"개인"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"직장"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"개인 뷰"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"직장 뷰"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"IT 관리자에 의해 차단됨"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"이 콘텐츠는 직장 앱을 통해 공유할 수 없습니다."</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"이 콘텐츠는 직장 앱으로 열 수 없습니다."</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"이 콘텐츠는 개인 앱을 통해 공유할 수 없습니다."</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"이 콘텐츠는 개인 앱으로 열 수 없습니다."</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"직장 프로필이 일시중지됨"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"탭하여 사용 설정"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"직장 앱 없음"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"개인 앱 없음"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"개인 프로필에서 <xliff:g id="APP">%s</xliff:g> 앱을 여시겠습니까?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"직장 프로필에서 <xliff:g id="APP">%s</xliff:g> 앱을 여시겠습니까?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"개인 브라우저 사용"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"직장 브라우저 사용"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"텍스트 제외"</string>
+ <string name="include_text" msgid="642280283268536140">"텍스트 포함"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"링크 제외"</string>
+ <string name="include_link" msgid="827855767220339802">"링크 포함"</string>
+</resources>
diff --git a/java/res/values-ky/strings.xml b/java/res/values-ky/strings.xml
new file mode 100644
index 00000000..c438a92f
--- /dev/null
+++ b/java/res/values-ky/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Кайсынысын колдоносуз?"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Аракетти <xliff:g id="APP">%1$s</xliff:g> колдонмосу менен аткарыңыз"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Аракетти аягына чыгаруу"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Төмөнкү менен ачуу"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> менен ачыңыз"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Ачуу"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> шилтемелерин төмөнкү колдонмодо ачуу:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Шилтемелерди төмөнкү колдонмодо ачуу:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Шилтемелерди <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосунда ачуу"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> шилтемелерин <xliff:g id="APPLICATION">%2$s</xliff:g> колдонмосунда ачуу"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Уруксат берүү"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Төмөнкү менен түзөтүү"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> менен түзөтүңүз"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Түзөтүү"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Бөлүшүү"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> аркылуу бөлүшүңүз"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Бөлүшүү"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Колдонмо тандаңыз"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> менен жөнөтүңүз"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Жөнөтүү"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Башкы бет колдонмосун тандаңыз"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> колдонмосун Үй катары колдонуңуз"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Сүрөткө тартуу"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Сүрөткө төмөнкү параметрлер менен тартуу"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Сүрөткө <xliff:g id="APP">%1$s</xliff:g> менен тартыңыз"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Сүрөткө тартуу"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Башка колдонмону пайдалануу"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Аракет тандаңыз"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Бул аракетти аткара турган колдонмо жок."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Бул колдонмо жумуш профилиңиздин сыртында колдонулуп жатат"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Бул колдонмону жумуш профилиңизде пайдаланып жатасыз"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Ар дайым"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Бир жолу гана"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> жумуш профилин колдоого албайт"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Кадап коюу: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> бошотуу"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Түзөтүү"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # файл}other{{file_name} + # файл}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # файл}other{+ # файл}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Текст бөлүшүлүүдө"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Шилтеме бөлүшүлүүдө"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Сүрөт бөлүшүлүүдө}other{# сүрөт бөлүшүлүүдө}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Видео бөлүшүлүүдө}other{# видео бөлүшүлүүдө}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# нерсе бөлүшүлүүдө}other{# нерсе бөлүшүлүүдө}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Сүрөттү текст менен жөнөтүү"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Сүрөттү шилтеме менен жөнөтүү"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Бөлүшкөнгө эч ким сунушталган жок"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Колдонмолордун тизмеси"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Бул колдонмого жаздырууга уруксат берилген эмес, бирок ушул USB түзмөгү аркылуу үндөрдү жаза алат."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Жеке"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Жумуш"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Жеке көрүнүш"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Жумуш көрүнүшү"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"IT администраторуңуз бөгөттөп койгон"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Бул мазмунду жумуш колдонмолору менен бөлүшүү мүмкүн эмес"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Бул мазмунду жумуш колдонмолору менен ачуу мүмкүн эмес"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Бул мазмунду жеке колдонмолор менен бөлүшүү мүмкүн эмес"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Бул мазмунду жеке колдонмолор менен ачуу мүмкүн эмес"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Жумуш профили тындырылган"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Күйгүзүү үчүн таптап коюңуз"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Жумуш колдонмолору жок"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Жеке колдонмолор жок"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g> колдонмосу жеке профилде ачылсынбы?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g> колдонмосу жумуш профилинде ачылсынбы?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Жеке серепчини колдонуу"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Жумуш серепчисин колдонуу"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Текстти чыгарып салуу"</string>
+ <string name="include_text" msgid="642280283268536140">"Текст кошуу"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Шилтемени чыгарып салуу"</string>
+ <string name="include_link" msgid="827855767220339802">"Шилтеме кошуу"</string>
+</resources>
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
deleted file mode 100644
index 7e3fb9cb..00000000
--- a/java/res/values-land/dimens.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources>
- <dimen name="chooser_preview_width">412dp</dimen>
-</resources>
diff --git a/java/res/values-lo/strings.xml b/java/res/values-lo/strings.xml
new file mode 100644
index 00000000..debe9c23
--- /dev/null
+++ b/java/res/values-lo/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"ດຳເນີນການໂດຍໃຊ້"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"ສຳເລັດຄຳສັ່ງໂດຍໃຊ້ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"ສຳເລັດຄຳສັ່ງ"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"ເປີດໂດຍໃຊ້"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"ເປີດດ້ວຍ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"ເປີດ"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"ເປີດລິ້ງ <xliff:g id="HOST">%1$s</xliff:g> ໂດຍໃຊ້"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"ເປີດລິ້ງໂດຍໃຊ້"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"ເປີດລິ້ງໂດຍໃຊ້ <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"ເປີດລິ້ງ <xliff:g id="HOST">%1$s</xliff:g> ໂດຍໃຊ້ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"ໃຫ້ສິດເຂົ້າເຖິງ"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"​ແກ້​ໄຂ​ໃນ"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"ແກ້ໄຂດ້ວຍ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"ແກ້ໄຂ"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"ແບ່ງປັນ"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"ແບ່ງປັນດ້ວຍ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"ແບ່ງປັນ"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"ສົ່ງໂດຍໃຊ້"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"ສົ່ງໂດຍໃຊ້ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"ສົ່ງ"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"​ເລືອກ​ແອັບຯ​ໂຮມ"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"ໃຊ້ <xliff:g id="APP">%1$s</xliff:g> ເປັນ Home"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"ບັນທຶກຮູບພາບ"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"ບັນທຶກຮູບພາບດ້ວຍ"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"ບັນທຶກຮູບພາບດ້ວຍ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"ບັນທຶກຮູບພາບ"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"ນຳໃຊ້ແອັບຯອື່ນ"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"ເລືອກຄຳສັ່ງ"</string>
+ <string name="noApplications" msgid="1139487441772284671">"ບໍ່ມີແອັບຯໃດສາມາດເຮັດວຽກນີ້ໄດ້."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"​ທ່ານ​ກຳ​ລັງ​ໃຊ້​ແອັບຯ​ນີ້ນອກ​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກ​ຂອງ​ທ່ານ"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"​ທ່ານ​ກຳ​ລັງ​ໃຊ້​ແອັບຯ​ນີ້​ໃນ​ໂປຣ​ໄຟລ໌​​ບ່ອນ​ເຮັດ​ວຽກ​ຂອງ​ທ່ານ"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"ທຸກຄັ້ງ"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"ຄັ້ງດຽວ"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ບໍ່ຮອງຮັບໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"ປັກໝຸດ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"ຖອດປັກມຸດ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"ແກ້ໄຂ"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ໄຟລ໌}other{{file_name} + # ໄຟລ໌}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{ອີກ # ໄຟລ໌}other{ອີກ # ໄຟລ໌}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"ກຳລັງແບ່ງປັນຂໍ້ຄວາມ"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"ກຳລັງແບ່ງປັນລິ້ງ"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{ກຳລັງແບ່ງປັນຮູບ}other{ກຳລັງແບ່ງປັນ # ຮູບ}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{ກຳລັງແບ່ງປັນວິດີໂອ}other{ກຳລັງແບ່ງປັນ # ວິດີໂອ}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{ກຳລັງແບ່ງປັນ # ລາຍການ}other{ກຳລັງແບ່ງປັນ # ລາຍການ}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"ກຳລັງແບ່ງປັນຮູບດ້ວຍຂໍ້ຄວາມ"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"ກຳລັງແບ່ງປັນຮູບດ້ວຍລິ້ງ"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"ບໍ່ມີຄົນທີ່ແນະນຳໃຫ້ແບ່ງປັນນຳ"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"ລາຍຊື່ແອັບ"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"ແອັບນີ້ບໍ່ໄດ້ຮັບສິດອະນຸຍາດໃນການບັນທຶກ ແຕ່ສາມາດບັນທຶກສຽງໄດ້ຜ່ານອຸປະກອນ USB ນີ້."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"ສ່ວນຕົວ"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"ວຽກ"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"ມຸມມອງສ່ວນຕົວ"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"ມຸມມອງວຽກ"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"ຖືກບລັອກໄວ້ໂດຍຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານ"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"ເນື້ອຫານີ້ບໍ່ສາມາດຖືກແບ່ງປັນກັບແອັບບ່ອນເຮັດວຽກໄດ້"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"ເນື້ອຫານີ້ບໍ່ສາມາດຖືກເປີດໄດ້ດ້ວຍແອັບບ່ອນເຮັດວຽກ"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"ເນື້ອຫານີ້ບໍ່ສາມາດຖືກແບ່ງປັນກັບແອັບສ່ວນຕົວໄດ້"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"ເນື້ອຫານີ້ບໍ່ສາມາດຖືກເປີດໄດ້ດ້ວຍແອັບສ່ວນຕົວ"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"ຢຸດໂປຣໄຟລ໌ວຽກໄວ້ຊົ່ວຄາວແລ້ວ"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ແຕະເພື່ອເປີດໃຊ້"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"ບໍ່ມີແອັບບ່ອນເຮັດວຽກ"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"ບໍ່ມີແອັບສ່ວນຕົວ"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"ເປີດ <xliff:g id="APP">%s</xliff:g> ໃນໂປຣໄຟລ໌ສ່ວນຕົວຂອງທ່ານບໍ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"ເປີດ <xliff:g id="APP">%s</xliff:g> ໃນ​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກຂອງທ່ານບໍ?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"ໃຊ້ໂປຣແກຣມທ່ອງເວັບສ່ວນຕົວ"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"ໃຊ້ໂປຣແກຣມທ່ອງເວັບບ່ອນເຮັດວຽກ"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"ບໍ່ຮວມຂໍ້ຄວາມ"</string>
+ <string name="include_text" msgid="642280283268536140">"ຮວມຂໍ້ຄວາມ"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"ບໍ່ຮວມລິ້ງ"</string>
+ <string name="include_link" msgid="827855767220339802">"ຮວມລິ້ງ"</string>
+</resources>
diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml
new file mode 100644
index 00000000..77ae0a47
--- /dev/null
+++ b/java/res/values-lt/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Užbaigti veiksmą naudojant"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Užbaigti veiksmą naudojant „<xliff:g id="APP">%1$s</xliff:g>“"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Užbaigti veiksmą"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Atidaryti naudojant"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Atidaryti naudojant „<xliff:g id="APP">%1$s</xliff:g>“"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Atidaryti"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Atidaryti nuorodas naudojant"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Atidaryti nuorodas naudojant „<xliff:g id="APPLICATION">%1$s</xliff:g>“"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant „<xliff:g id="APPLICATION">%2$s</xliff:g>“"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Leisti pasiekti"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Redaguoti naudojant"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Redaguoti naudojant „<xliff:g id="APP">%1$s</xliff:g>“"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Redaguoti"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Bendrinti"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Bendrinti naudojant programą „<xliff:g id="APP">%1$s</xliff:g>“"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Bendrinti"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Siųsti naudojant"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Siųsti naudojant „<xliff:g id="APP">%1$s</xliff:g>“"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Siųsti"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Pasirinkti pagrindinę programą"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Naudoti „<xliff:g id="APP">%1$s</xliff:g>“ kaip pagrindinę programą"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Užfiksuoti vaizdą"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Užfiksuoti vaizdą naudojant"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Užfiksuoti vaizdą naudojant „<xliff:g id="APP">%1$s</xliff:g>“"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Užfiksuoti vaizdą"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Naudoti kitą programą"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Pasirinkite veiksmą"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Jokios programos negali atlikti šio veiksmo."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Šią programą naudojate ne darbo profilyje"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Šią programą naudojate darbo profilyje"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Visada"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Tik kartą"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"„<xliff:g id="APP">%1$s</xliff:g>“ nepalaiko darbo profilio"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Prisegti <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Atsegti <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Redaguoti"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{„{file_name}“ ir dar # failas}one{„{file_name}“ ir dar # failas}few{„{file_name}“ ir dar # failai}many{„{file_name}“ ir dar # failo}other{„{file_name}“ ir dar # failų}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{Dar # failas}one{Dar # failas}few{Dar # failai}many{Dar # failo}other{Dar # failų}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Bendrinamas tekstas"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Bendrinama nuoroda"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Bendrinamas vaizdas}one{Bendrinamas # vaizdas}few{Bendrinami # vaizdai}many{Bendrinama # vaizdo}other{Bendrinama # vaizdų}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Bendrinamas vaizdo įrašas}one{Bendrinamas # vaizdo įrašas}few{Bendrinami # vaizdo įrašai}many{Bendrinama # vaizdo įrašo}other{Bendrinama # vaizdo įrašų}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Bendrinamas # elementas}one{Bendrinamas # elementas}few{Bendrinami # elementai}many{Bendrinama # elemento}other{Bendrinama # elementų}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Bendrinamas vaizdas su tekstu"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Bendrinamas vaizdas su nuoroda"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Nėra rekomenduojamų žmonių, su kuriais būtų galima bendrinti"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Programų sąrašas"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Šiai programai nebuvo suteiktas leidimas įrašyti, bet ji gali užfiksuoti garsą per šį USB įrenginį."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Asmeninis"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Darbo"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Asmeninė peržiūra"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Darbo peržiūra"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Užblokavo jūsų IT administratorius"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Šio turinio negalima bendrinti su darbo programomis"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Šio turinio negalima atidaryti naudojant darbo programas"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Šio turinio negalima bendrinti su asmeninėmis programomis"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Šio turinio negalima atidaryti naudojant asmenines programas"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Darbo profilis pristabdytas"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Paliesti, norint įjungti"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Nėra darbo programų"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Nėra asmeninių programų"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Atidaryti „<xliff:g id="APP">%s</xliff:g>“ asmeniniame profilyje?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Atidaryti „<xliff:g id="APP">%s</xliff:g>“ darbo profilyje?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Naudoti asmeninę naršyklę"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Naudoti darbo naršyklę"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Išskirti tekstą"</string>
+ <string name="include_text" msgid="642280283268536140">"Įtraukti tekstą"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Išskirti nuorodą"</string>
+ <string name="include_link" msgid="827855767220339802">"Įtraukti nuorodą"</string>
+</resources>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
new file mode 100644
index 00000000..6fb7fee3
--- /dev/null
+++ b/java/res/values-lv/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Izvēlieties lietotni"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Darbības pabeigšana, izmantojot lietotni <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Pabeigt darbību"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Atvērt, izmantojot"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Atvēršana lietotnē <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Atvērt"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> saišu atvēršana, izmantojot:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Saišu atvēršana, izmantojot:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Saišu atvēršana, izmantojot pārlūku <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> saišu atvēršana, izmantojot pārlūku <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Atļaut piekļuvi"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Rediģēt, izmantojot"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Rediģēšana lietotnē <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Rediģēt"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Kopīgot"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Kopīgošana, izmantojot lietotni <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Kopīgot"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Sūtīšana, izmantojot..."</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Sūtīšana, izmantojot lietotni <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Sūtīt"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Sākuma lietotnes atlase"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> kā sākuma lietotnes izmantošana"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Uzņemt attēlu"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Attēla uzņemšana, izmantojot lietotni"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Attēla uzņemšana, izmantojot lietotni <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Uzņemt attēlu"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Izmantot citu lietotni"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Darbības izvēle"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Šo darbību nevar veikt neviena lietotne."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Šo lietotni izmantojat ārpus sava darba profila"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Jūs izmantojat šo lietotni no sava darba profila."</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Vienmēr"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Tikai vienreiz"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> neatbalsta darba profilu"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Piespraust lietotni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Atspraust lietotni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Rediģēt"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} un vēl # fails}zero{{file_name} un vēl # failu}one{{file_name} un vēl # fails}other{{file_name} un vēl # faili}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{un vēl # fails}zero{un vēl # faili}one{un vēl # fails}other{un vēl # faili}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Tiek kopīgots teksts"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Tiek kopīgota saite"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Tiek kopīgots attēls}zero{Tiek kopīgoti # attēli}one{Tiek kopīgots # attēls}other{Tiek kopīgoti # attēli}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Tiek kopīgots video}zero{Tiek kopīgoti # video}one{Tiek kopīgots # video}other{Tiek kopīgoti # video}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Tiek kopīgots # vienums}zero{Tiek kopīgoti # vienumi}one{Tiek kopīgots # vienums}other{Tiek kopīgoti # vienumi}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Tiek kopīgots attēls ar tekstu"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Tiek kopīgots attēls ar saiti"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Nav ieteikta neviena persona, ar ko kopīgot"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lietotņu saraksts"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Šai lietotnei nav piešķirta ierakstīšanas atļauja, taču tā varētu tvert audio, izmantojot šo USB ierīci."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Privātais profils"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Darba profils"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Personisks skats"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Darba skats"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Bloķējis jūsu IT administrators"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Šo saturu nevar kopīgot ar darba lietotnēm"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Šo saturu nevar atvērt darba lietotnēs"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Šo saturu nevar kopīgot ar personīgajām lietotnēm"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Šo saturu nevar atvērt personīgajās lietotnēs"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Darba profila darbība ir apturēta."</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Lai ieslēgtu, pieskarieties"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Nav darba lietotņu"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Nav personīgu lietotņu"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Vai atvērt lietotni <xliff:g id="APP">%s</xliff:g> jūsu personīgajā profilā?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Vai atvērt lietotni <xliff:g id="APP">%s</xliff:g> jūsu darba profilā?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Izmantot personīgo pārlūku"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Izmantot darba pārlūku"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Izslēgt tekstu"</string>
+ <string name="include_text" msgid="642280283268536140">"Iekļaut tekstu"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Izslēgt saiti"</string>
+ <string name="include_link" msgid="827855767220339802">"Iekļaut saiti"</string>
+</resources>
diff --git a/java/res/values-mk/strings.xml b/java/res/values-mk/strings.xml
new file mode 100644
index 00000000..001772fa
--- /dev/null
+++ b/java/res/values-mk/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Активирај со"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Завршување на дејството со <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Заврши го дејството"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Отвори со"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Отворање со <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Отвори"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Отворајте линкови на <xliff:g id="HOST">%1$s</xliff:g> со"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Отворајте линкови со"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Отворајте линкови со <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Отворајте линкови на <xliff:g id="HOST">%1$s</xliff:g> со <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Дозволете пристап"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Измени со"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Изменување со <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Измени"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Сподели"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Споделување со <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Сподели"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Испрати преку"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Испраќање преку <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Испрати"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Изберете ја апликацијата Почетен"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Користење на <xliff:g id="APP">%1$s</xliff:g> како апликација на почетен екран"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Сними слика"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Сними слика со"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Снимање слика со <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Сними слика"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Користи различна апликација"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Избирање дејство"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Нема апликации што можат да го извршат ова дејство."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Ја користите апликацијата надвор од работниот профил"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Ја користите апликацијата во работниот профил"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Секогаш"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Само еднаш"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> не поддржува работен профил"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Закачи <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Откачи <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Измени"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # датотека}one{{file_name} + # датотека}other{{file_name} + # датотеки}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # датотека}one{+ # датотека}other{+ # датотеки}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Се споделува текст"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Се споделува линк"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Се споделува слика}one{Се споделува # слика}other{Се споделуваат # слики}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Се споделува видео}one{Се споделува # видео}other{Се споделуваат # видеа}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Се споделува # ставка}one{Се споделува # ставка}other{Се споделуваат # ставки}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Се споделува слика со текст"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Се споделува слика со линк"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Нема препорачани луѓе со кои може да се сподели"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Список со апликации"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"На апликацијава не ѝ е доделена дозвола за снимање, но може да снима аудио преку овој USB-уред."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Лични"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"За работа"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Личен приказ"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Работен приказ"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Блокирано од IT-администраторот"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Овие содржини не може да се споделуваат со работни апликации"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Овие содржини не може да се отвораат со работни апликации"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Овие содржини не може да се споделуваат со лични апликации"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Овие содржини не може да се отвораат со лични апликации"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Работниот профил е паузиран"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Допрете за да вклучите"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Нема работни апликации"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Нема лични апликации"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Да се отвори <xliff:g id="APP">%s</xliff:g> во личниот профил?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Да се отвори <xliff:g id="APP">%s</xliff:g> во работниот профил?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Користи личен прелистувач"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Користи работен прелистувач"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Исклучи текст"</string>
+ <string name="include_text" msgid="642280283268536140">"Опфати текст"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Исклучи линк"</string>
+ <string name="include_link" msgid="827855767220339802">"Вклучи линк"</string>
+</resources>
diff --git a/java/res/values-ml/strings.xml b/java/res/values-ml/strings.xml
new file mode 100644
index 00000000..b91adae8
--- /dev/null
+++ b/java/res/values-ml/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"പൂർണ്ണമായ പ്രവർത്തനം ഉപയോഗിക്കുന്നു"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> ഉപയോഗിച്ച് പ്രവർത്തനം പൂർത്തിയാക്കുക"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"പ്രവർത്തനം പൂർത്തിയാക്കുക"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"ഇത് ഉപയോഗിച്ച് തുറക്കുക"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> ഉപയോഗിച്ച് തുറക്കുക"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"തുറക്കുക"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"ഇനിപ്പറയുന്നത് ഉപയോഗിച്ച് <xliff:g id="HOST">%1$s</xliff:g> ലിങ്കുകൾ തുറക്കുക"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"ഇനിപ്പറയുന്നത് ഉപയോഗിച്ച് ലിങ്കുകൾ തുറക്കുക"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> ഉപയോഗിച്ച് ലിങ്കുകൾ തുറക്കുക"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> ലിങ്കുകൾ <xliff:g id="APPLICATION">%2$s</xliff:g> ഉപയോഗിച്ച് തുറക്കുക"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"ആക്‌സസ് നൽകുക"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"ഇത് ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> ഉപയോഗിച്ച് എഡിറ്റ് ചെയ്യുക"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"എഡിറ്റ് ചെയ്യുക"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"പങ്കിടുക"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> ഉപയോഗിച്ച് പങ്കിടുക"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"പങ്കിടുക"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"ഇനിപ്പറയുന്നത് ഉപയോഗിച്ച് അയയ്ക്കുക"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> ഉപയോഗിച്ച് അയയ്ക്കുക"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"അയയ്‌ക്കുക"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"ഒരു ഹോം അപ്ലിക്കേഷൻ തിരഞ്ഞെടുക്കുക"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"ഹോം ആപ്പ് ആയി <xliff:g id="APP">%1$s</xliff:g> ഉപയോഗിക്കുക"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"ചിത്രം എടുക്കുക"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"ഇനിപ്പറയുന്നതിൽ ചിത്രം എടുക്കുക:"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> ഉപയോഗിച്ച് ചിത്രം എടുക്കുക"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"ചിത്രം എടുക്കുക"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"മറ്റൊരു അപ്ലിക്കേഷൻ ഉപയോഗിക്കുക"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"ഒരു പ്രവർത്തനം തിരഞ്ഞെടുക്കുക"</string>
+ <string name="noApplications" msgid="1139487441772284671">"അപ്ലിക്കേഷനുകൾക്കൊന്നും ഈ പ്രവർത്തനം നിർവഹിക്കാനാവില്ല."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിന് പുറത്ത് ഈ അപ്ലിക്കേഷൻ ഉപയോഗിക്കുന്നു"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിൽ ഈ അപ്ലിക്കേഷൻ ഉപയോഗിക്കുന്നു"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"എല്ലായ്‌പ്പോഴും"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"ഒരിക്കൽ മാത്രം"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g>, ഔദ്യോഗിക പ്രൊഫൈൽ പിന്തുണയ്‌ക്കുന്നില്ല"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> പിൻ ചെയ്യുക"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> അൺപിൻ ചെയ്യുക"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"എഡിറ്റ് ചെയ്യുക"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ഫയൽ}other{{file_name} + # ഫയലുകൾ}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ഫയൽ}other{+ # ഫയലുകൾ}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"ടെക്‌സ്‌റ്റ് പങ്കിടുന്നു"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"ലിങ്ക് പങ്കിടുന്നു"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{ചിത്രം പങ്കിടുന്നു}other{# ചിത്രങ്ങൾ പങ്കിടുന്നു}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{വീഡിയോ പങ്കിടുന്നു}other{# വീഡിയോകൾ പങ്കിടുന്നു}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# ഇനം പങ്കിടുന്നു}other{# ഇനങ്ങൾ പങ്കിടുന്നു}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"ടെക്സ്റ്റിനൊപ്പം ചിത്രം പങ്കിടുന്നു"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"ലിങ്കിനൊപ്പം ചിത്രം പങ്കിടുന്നു"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"പങ്കിടാൻ, നിർദ്ദേശിക്കപ്പെട്ട ആളുകളൊന്നുമില്ല"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"ആപ്പുകളുടെ ലിസ്‌റ്റ്"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"ഈ ആപ്പിന് റെക്കോർഡ് അനുമതി നൽകിയിട്ടില്ല, എന്നാൽ ഈ USB ഉപകരണത്തിലൂടെ ഓഡിയോ ക്യാപ്‌ചർ ചെയ്യാനാവും."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"വ്യക്തിപരം"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"ഔദ്യോഗികം"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"വ്യക്തിപര കാഴ്‌ച"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"ഔദ്യോഗിക കാഴ്‌ച"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"നിങ്ങളുടെ ഐടി അഡ്‌മിൻ ബ്ലോക്ക് ചെയ്‌തു"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"ഔദ്യോഗിക ആപ്പുകൾ ഉപയോഗിച്ച് ഈ ഉള്ളടക്കം പങ്കിടാനാകില്ല"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"ഔദ്യോഗിക ആപ്പുകൾ ഉപയോഗിച്ച് ഈ ഉള്ളടക്കം തുറക്കാനാകില്ല"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"വ്യക്തിപര ആപ്പുകൾ ഉപയോഗിച്ച് ഈ ഉള്ളടക്കം പങ്കിടാനാകില്ല"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"വ്യക്തിപര ആപ്പുകൾ ഉപയോഗിച്ച് ഈ ഉള്ളടക്കം തുറക്കാനാകില്ല"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"ഔദ്യോഗിക പ്രൊഫൈൽ തൽക്കാലം നിർത്തിയിരിക്കുന്നു"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ഓണാക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"ഔദ്യോഗിക ആപ്പുകൾ ഇല്ല"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"വ്യക്തിപര ആപ്പുകൾ ഇല്ല"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g>, നിങ്ങളുടെ വ്യക്തിപരമായ പ്രൊഫൈലിൽ തുറക്കണോ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g>, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിൽ തുറക്കണോ?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"വ്യക്തിപരമായ ബ്രൗസർ ഉപയോഗിക്കുക"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"ഔദ്യോഗിക ബ്രൗസർ ഉപയോഗിക്കുക"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"ടെക്‌സ്‌റ്റ് ഒഴിവാക്കുക"</string>
+ <string name="include_text" msgid="642280283268536140">"ടെക്‌സ്റ്റ് ഉൾപ്പെടുത്തുക"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"ലിങ്ക് ഒഴിവാക്കുക"</string>
+ <string name="include_link" msgid="827855767220339802">"ലിങ്ക് ഉൾപ്പെടുത്തുക"</string>
+</resources>
diff --git a/java/res/values-mn/strings.xml b/java/res/values-mn/strings.xml
new file mode 100644
index 00000000..ad356c08
--- /dev/null
+++ b/java/res/values-mn/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Үйлдлийг дуусгах"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g>-г ашиглан үйлдлийг дуусгах"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Үйлдлийг дуусгах"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Нээх"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g>-р нээх"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Нээх"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g>-н холбоосуудыг дараахаар нээх"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Холбоосуудыг дараахаар нээх"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Холбоосуудыг <xliff:g id="APPLICATION">%1$s</xliff:g>-р нээх"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g>-н холбоосуудыг <xliff:g id="APPLICATION">%2$s</xliff:g>-р нээх"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Хандах эрх өгөх"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Засварлах"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g>-р засах"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Засах"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Хуваалцах"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g>-тай хуваалцах"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Хуваалцах"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Ашиглан илгээх"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g>-г ашиглан илгээх"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Илгээх"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Үндсэн апп-г сонгох"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g>-г Үндсэн нүүрний аппаар ашиглах"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Зураг авах"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Дараахаар зураг авах"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g>-р зураг авах"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Зураг авах"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Өөр апп ашиглах"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Үйлдэл сонгох"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Энэ ажиллагааг гүйцэтгэх апп байхгүй."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Та энэ апп-г өөрийн ажлын профайлаас гадуур ашиглаж байна"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Та энэ апп-г өөрийн ажлын профайл дотор ашиглаж байна"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Байнга"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Нэг удаа"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ажлын профайлыг дэмждэггүй"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g>-г бэхлэх"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g>-г тогтоосныг болиулах"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Засах"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # файл}other{{file_name} + # файл}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # файл}other{+ # файл}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Текст хуваалцаж байна"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Холбоос хуваалцаж байна"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Зураг хуваалцаж байна}other{# зураг хуваалцаж байна}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Видео хуваалцаж байна}other{# видео хуваалцаж байна}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# зүйл хуваалцаж байна}other{# зүйл хуваалцаж байна}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Тексттэй зураг хуваалцаж байна"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Холбоостой зураг хуваалцаж байна"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Хуваалцахыг санал болгосон хүн байхгүй"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Аппын жагсаалт"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Энэ апликейшнд бичих зөвшөөрөл олгогдоогүй ч энэ USB төхөөрөмжөөр дамжуулан аудио бичиж чадсан."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Хувийн"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Ажил"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Хувийн харагдах байдал"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Ажлын харагдах байдал"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Таны IT админ блоклосон"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Энэ контентыг ажлын аппуудаар хуваалцах боломжгүй"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Энэ контентыг ажлын аппуудаар нээх боломжгүй"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Энэ контентыг хувийн аппуудаар хуваалцах боломжгүй"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Энэ контентыг хувийн аппуудаар нээх боломжгүй"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Ажлын профайлыг түр зогсоосон"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Асаахын тулд товших"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Ямар ч ажлын апп байхгүй байна"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Ямар ч хувийн апп байхгүй байна"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Хувийн профайл дээрээ <xliff:g id="APP">%s</xliff:g>-г нээх үү?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Ажлын профайл дээрээ <xliff:g id="APP">%s</xliff:g>-г нээх үү?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Хувийн хөтөч ашиглах"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Ажлын хөтөч ашиглах"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Текстийг хасах"</string>
+ <string name="include_text" msgid="642280283268536140">"Текстийг оруулах"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Холбоосыг хасах"</string>
+ <string name="include_link" msgid="827855767220339802">"Холбоосыг оруулах"</string>
+</resources>
diff --git a/java/res/values-mr/strings.xml b/java/res/values-mr/strings.xml
new file mode 100644
index 00000000..469adb4b
--- /dev/null
+++ b/java/res/values-mr/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"याचा वापर करून क्रिया पूर्ण करा"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> वापरून कृती पूर्ण करा"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"क्रिया पूर्ण झाली"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"यासह उघडा"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> वापरून उघडा"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"उघडा"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"वापरून <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडा"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"हे वापरून लिंक उघडा"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> वापरून लिंक उघडा"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="APPLICATION">%2$s</xliff:g> वापरून <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडा"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"अ‍ॅक्सेस द्या"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"सह संपादित करा"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> वापरून संपादित करा"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"संपादित करा"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"शेअर करा"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> वापरून शेअर करा"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"शेअर करा"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"वापरून पाठवा"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> वापरून पाठवा"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"पाठवा"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"होम अ‍ॅप निवडा"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> चा वापर होम म्हणून करा"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"इमेज कॅप्चर करा"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"यासह इमेज कॅप्चर करा"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> वापरून इमेज कॅप्चर करा"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"इमेज कॅप्चर करा"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"एक भिन्न अ‍ॅप वापरा"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"कृती निवडा"</string>
+ <string name="noApplications" msgid="1139487441772284671">"कोणतेही अ‍ॅप्स ही क्रिया करू शकत नाहीत."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"तुम्ही हा अ‍ॅप आपल्‍या कार्य प्रोफाईलच्या बाहेर वापरत आहात"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"तुम्ही हा अ‍ॅप आपल्या कार्य प्रोफाईलमध्‍ये वापरत आहात"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"नेहमी"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"फक्त एकदाच"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> कार्य प्रोफाइलला सपोर्ट नाही"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> पिन करा"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> ला अनपिन करा"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"संपादित करा"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # फाइल}other{{file_name} + # फाइल}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # फाइल}other{+ # फाइल}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"मजकूर शेअर करत आहे"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"लिंक शेअर करत आहे"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{इमेज शेअर करत आहे}other{# इमेज शेअर करत आहे}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{व्हिडिओ शेअर करत आहे}other{# व्हिडिओ शेअर करत आहे}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# आयटम शेअर करत आहे}other{# आयटम शेअर करत आहे}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"मजकुरासह इमेज शेअर करत आहे"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"लिंकसह इमेज शेअर करत आहे"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"शेअर करण्यासाठी शिफारस केलेल्या कोणत्याही व्यक्ती नाहीत"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"अ‍ॅप्स सूची"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"या अ‍ॅपला रेकॉर्ड करण्याची परवानगी दिली गेली नाही पण हे USB डिव्हाइस वापरून ऑडिओ कॅप्चर केला जाऊ शकतो."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"वैयक्तिक"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"कार्य"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"वैयक्तिक दृश्य"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"कार्य दृश्य"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"तुमच्या IT ॲडमिनने ब्लॉक केले"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"हा आशय कार्य ॲप्ससह शेअर केला जाऊ शकत नाही"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"हा आशय कार्य ॲप्स वापरून उघडला जाऊ शकत नाही"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"हा आशय वैयक्तिक ॲप्ससह शेअर केला जाऊ शकत नाही"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"हा आशय वैयक्तिक ॲप्स वापरून उघडला जाऊ शकत नाही"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"कार्य प्रोफाइल थांबवली आहे"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"सुरू करण्यासाठी टॅप करा"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"कोणतीही कार्य ॲप्स सपोर्ट करत नाहीत"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"कोणतीही वैयक्तिक ॲप्स सपोर्ट करत नाहीत"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"तुमच्या वैयक्तिक प्रोफाइलमध्ये <xliff:g id="APP">%s</xliff:g> उघडायचे आहे का?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"तुमच्या कार्य प्रोफाइलमध्ये <xliff:g id="APP">%s</xliff:g> उघडायचे आहे का?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"वैयक्तिक ब्राउझर वापरा"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"कार्य ब्राउझर वापरा"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"मजकूर वगळा"</string>
+ <string name="include_text" msgid="642280283268536140">"मजकूर समाविष्ट करा"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"लिंक वगळा"</string>
+ <string name="include_link" msgid="827855767220339802">"लिंक समाविष्ट करा"</string>
+</resources>
diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml
new file mode 100644
index 00000000..4d6eb7ca
--- /dev/null
+++ b/java/res/values-ms/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Selesaikan tindakan menggunakan"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Selesaikan tindakan menggunakan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Selesaikan tindakan"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Buka dengan"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Buka menggunakan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Buka"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Buka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Buka pautan dengan"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Buka pautan dengan <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Buka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Beri akses"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Edit dengan"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Edit dengan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Edit"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Kongsi"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Kongsi dengan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Kongsi"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Hantar menggunakan"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Hantar menggunakan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Hantar"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Pilih apl Laman Utama"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Gunakan <xliff:g id="APP">%1$s</xliff:g> sebagai Laman Utama"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Tangkap imej"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Tangkap imej menggunakan"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Tangkap imej menggunakan <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Tangkap imej"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Gunakan apl lain"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Pilih tindakan"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Tiada apl yang boleh menjalankan tindakan ini."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Anda menggunakan apl ini di luar profil kerja anda"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Anda menggunakan apl ini dalam profil kerja anda"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Sentiasa"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Hanya sekali"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> tidak menyokong profil kerja"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Sematkan <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Nyahsemat <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Edit"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # fail}other{{file_name} + # fail}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # fail}other{+ # fail}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Berkongsi teks"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Berkongsi pautan"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Berkongsi imej}other{Berkongsi # imej}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Berkongsi video}other{Berkongsi # video}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Berkongsi # item}other{Berkongsi # item}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Berkongsi imej dengan teks"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Berkongsi imej dengan pautan"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Tiada orang yang disyorkan untuk berkongsi"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Senarai apl"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Apl ini belum diberikan kebenaran merakam tetapi dapat merakam audio melalui peranti USB ini."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Peribadi"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Kerja"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Paparan peribadi"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Paparan kerja"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Disekat oleh pentadbir IT anda"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Kandungan ini tidak boleh dikongsi dengan apl kerja"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Kandungan ini tidak boleh dibuka dengan apl kerja"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Kandungan ini tidak boleh dikongsi dengan apl peribadi"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Kandungan ini tidak boleh dibuka dengan apl peribadi"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Profil kerja dijeda"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Ketik untuk menghidupkan profil"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Tiada apl kerja"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Tiada apl peribadi"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Buka <xliff:g id="APP">%s</xliff:g> dalam profil peribadi anda?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Buka <xliff:g id="APP">%s</xliff:g> dalam profil kerja anda?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Gunakan penyemak imbas peribadi"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Gunakan penyemak imbas kerja"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Kecualikan teks"</string>
+ <string name="include_text" msgid="642280283268536140">"Sertakan teks"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Kecualikan pautan"</string>
+ <string name="include_link" msgid="827855767220339802">"Sertakan pautan"</string>
+</resources>
diff --git a/java/res/values-my/strings.xml b/java/res/values-my/strings.xml
new file mode 100644
index 00000000..0b175357
--- /dev/null
+++ b/java/res/values-my/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"အောက်ပါတို့ကို အသုံးပြုမှု အပြီးသတ်ခြင်း"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> သုံး၍ လုပ်ဆောင်ချက်ကို အပြီးသတ်ခြင်း"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"လုပ်ဆောင်ချက်ကို အပြီးသတ်ပါ"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"...ဖြင့် ဖွင့်မည်"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> ဖြင့် ဖွင့်ခြင်း"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"ဖွင့်ရန်"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> လင့်ခ်များကို အောက်ပါဖြင့် ဖွင့်ရန်−"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"လင့်ခ်များကို အောက်ပါဖြင့် ဖွင့်ရန်−"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"လင့်ခ်ကို <xliff:g id="APPLICATION">%1$s</xliff:g> ဖြင့် ဖွင့်ရန်"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> လင့်ခ်များကို <xliff:g id="APPLICATION">%2$s</xliff:g> ဖြင့် ဖွင့်ရန်"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"သုံးခွင့်ပေးရန်"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"...နှင့် တည်းဖြတ်ရန်"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> ဖြင့် တည်းဖြတ်ခြင်း"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"တည်းဖြတ်ပါ"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"မျှဝေပါ"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> ဖြင့် မျှဝေခြင်း"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"မျှဝေပါ"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"ကိုအသုံးပြု၍ ပို့ပါ"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> သုံး၍ ပို့ခြင်း"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"ပို့ရန်"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"ပင်မ အက်ပ်ကို ရွေးပါ"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> ကို ‘ပင်မစာမျက်နှာ’ အဖြစ် သုံးခြင်း"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"ဓာတ်ပုံရိုက်ပါ"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"ဖြင့် ဓာတ်ပုံရိုက်ပါ"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> ဖြင့် ဓာတ်ပုံရိုက်ခြင်း"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"ဓာတ်ပုံရိုက်ပါ"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"အခြား အက်ပ်ကို သုံးပါ"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"လုပ်ဆောင်ချက် ရွေးခြင်း"</string>
+ <string name="noApplications" msgid="1139487441772284671">"မည်သည့်အက်ပ်ကမျှ ဤလုပ်ဆောင်ချက်ကို မလုပ်ကိုင်နိုင်ပါ။"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"သင်သည် ဒီအက်ပ်ကို သင့်အလုပ်ပရိုဖိုင် ပြင်ပတွင် အသုံးပြုနေ၏"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"သင်သည် ဒီအက်ပ်ကို သင်၏ အလုပ် ပရိုဖိုင် ထဲမှာ အသုံးပြုနေသည်"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"အမြဲတမ်း"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"တစ်ခါတည်း"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> သည် အလုပ်ပရိုဖိုင်ကို မပံ့ပိုးပါ"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> ကို ပင်ထိုးရန်"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> ကို ပင်ဖြုတ်ရန်"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"တည်းဖြတ်ရန်"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ဖိုင်}other{{file_name} + # ဖိုင်}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ဖိုင်}other{+ # ဖိုင်}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"စာသား မျှဝေနေသည်"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"လင့်ခ် မျှဝေနေသည်"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{ပုံ မျှဝေနေသည်}other{ပုံ # ပုံ မျှဝေနေသည်}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{ဗီဒီယို မျှဝေနေသည်}other{ဗီဒီယို # ခု မျှဝေနေသည်}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# ခု မျှဝေနေသည်}other{# ခု မျှဝေနေသည်}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"စာပါသောပုံ မျှဝေနေသည်"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"လင့်ခ်ပါသောပုံ မျှဝေနေသည်"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"မျှဝေရန် အကြံပြုထားသူများ မရှိပါ"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"အက်ပ်စာရင်း"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"ဤအက်ပ်ကို အသံဖမ်းခွင့် ပေးမထားသော်လည်း ၎င်းသည် ဤ USB စက်ပစ္စည်းမှတစ်ဆင့် အသံများကို ဖမ်းယူနိုင်ပါသည်။"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"ကိုယ်ပိုင်"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"အလုပ်"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"ပုဂ္ဂိုလ်ရေးဆိုင်ရာ မြင်ကွင်း"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"အလုပ် မြင်ကွင်း"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"သင်၏ IT စီမံခန့်ခွဲသူက ပိတ်ထားသည်"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"ဤအကြောင်းအရာကို အလုပ်သုံးအက်ပ်များဖြင့် မမျှဝေနိုင်ပါ"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"ဤအကြောင်းအရာကို အလုပ်သုံးအက်ပ်များဖြင့် မဖွင့်နိုင်ပါ"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"ဤအကြောင်းအရာကို ကိုယ်ပိုင်အက်ပ်များဖြင့် မမျှဝေနိုင်ပါ"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"ဤအကြောင်းအရာကို ကိုယ်ပိုင်အက်ပ်များဖြင့် မဖွင့်နိုင်ပါ"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"အလုပ်ပရိုဖိုင် ခဏရပ်ထားသည်"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ဖွင့်ရန်တို့ပါ"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"အလုပ်သုံးအက်ပ်များ မရှိပါ"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"ကိုယ်ပိုင်အက်ပ်များ မရှိပါ"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g> ကို သင့်ကိုယ်ပိုင်ပရိုဖိုင်တွင် ဖွင့်မလား။"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g> ကို သင့်အလုပ်ပရိုဖိုင်တွင် ဖွင့်မလား။"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"ကိုယ်ပိုင်ဘရောင်ဇာ သုံးရန်"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"အလုပ်သုံးဘရောင်ဇာ သုံးရန်"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"စာသား ဖယ်ထုတ်ရန်"</string>
+ <string name="include_text" msgid="642280283268536140">"စာသားထည့်သွင်းရန်"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"လင့်ခ် ဖယ်ထုတ်ရန်"</string>
+ <string name="include_link" msgid="827855767220339802">"လင့်ခ်ထည့်သွင်းရန်"</string>
+</resources>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
new file mode 100644
index 00000000..b6e49cd2
--- /dev/null
+++ b/java/res/values-nb/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Fullfør med"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Utfør handlingen med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Fullfør handlingen"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Åpne med"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Åpne med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Åpne"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Åpne linker med"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Åpne linker med <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Gi tilgang"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Rediger med"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Rediger med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Endre"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Del"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Del med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Del"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Send via"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Send via <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Send"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Velg en startsideapp"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Bruk <xliff:g id="APP">%1$s</xliff:g> som startside"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Ta bilde"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Ta bilde med"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Ta bilde med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Ta bilde"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Bruk en annen app"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Velg en handling"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Ingen apper kan gjøre dette."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Du bruker denne appen utenfor jobbprofilen"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Du bruker denne appen i jobbprofilen din"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Alltid"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Bare én gang"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> støtter ikke jobbprofiler"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fest <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Løsne <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Endre"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # fil}other{{file_name} + # filer}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # fil}other{+ # filer}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Deler teksten"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Deler linken"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Deler bildet}other{Deler # bilder}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Deler videoen}other{Deler # videoer}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Deler # element}other{Deler # elementer}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Deler bildet med tekst"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Deler bildet med link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Det finnes ingen anbefalte personer å dele med"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Appliste"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Denne appen har ikke fått tillatelse til å spille inn, men kan ta opp lyd med denne USB-enheten."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personlig"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Jobb"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Personlig visning"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Jobbvisning"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blokkert av IT-administratoren din"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Dette innholdet kan ikke deles med jobbapper"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Dette innholdet kan ikke åpnes med jobbapper"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Dette innholdet kan ikke deles med personlige apper"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Dette innholdet kan ikke åpnes med personlige apper"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Jobbprofilen er satt på pause"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Trykk for å slå på"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Ingen jobbapper"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Ingen personlige apper"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Vil du åpne <xliff:g id="APP">%s</xliff:g> i den personlige profilen din?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Vil du åpne <xliff:g id="APP">%s</xliff:g> i jobbprofilen din?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Bruk den personlige nettleseren"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Bruk jobbnettleseren"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Ekskluder teksten"</string>
+ <string name="include_text" msgid="642280283268536140">"Inkluder teksten"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Ekskluder linken"</string>
+ <string name="include_link" msgid="827855767220339802">"Inkluder linken"</string>
+</resources>
diff --git a/java/res/values-ne/strings.xml b/java/res/values-ne/strings.xml
new file mode 100644
index 00000000..9bf20518
--- /dev/null
+++ b/java/res/values-ne/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"प्रयोग गरेर कारबाही पुरा गर्नुहोस्"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> प्रयोग गरी कारबाही पूरा गर्नुहोस्"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"पूर्ण कारबाही"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"निम्नबाट खोल्नुहोस्"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> मार्फत खोल्नुहोस्"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"खोल्नुहोस्"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"निम्नमार्फत <xliff:g id="HOST">%1$s</xliff:g> का लिंकहरू खोल्नुहोस्"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"निम्नमार्फत लिंकहरू खोल्नुहोस्"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> मार्फत लिंकहरू खोल्नुहोस्"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="APPLICATION">%2$s</xliff:g> मार्फत <xliff:g id="HOST">%1$s</xliff:g> का लिंकहरू खोल्नुहोस्"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"एक्सेस दिनुहोस्"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"सँग सम्पादन गर्नुहोस्"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> मार्फत सम्पादन गर्नुहोस्"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"सम्पादन गर्नुहोस्"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"सेयर गर्नुहोस्"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> मार्फत सेयर गर्नुहोस्"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"सेयर गर्नुहोस्"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"यसको प्रयोग गरी पठाउनुहोस्"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> प्रयोग गरी पठाउनुहोस्"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"पठाउनुहोस्"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"होम एप चयन गर्नुहोस्"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> लाई होम एपका रूपमा प्रयोग गर्नुहोस्"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"छविलाई कैंद गर्नुहोस्"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"यस मार्फत छविलाई कैंद गर्नुहोस्"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> मार्फत फोटो खिच्नुहोस्"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"छविलाई कैंद गर्नुहोस्"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"फरक एप प्रयोग गर्नुहोस्"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"कारबाही चयन गर्नुहोस्"</string>
+ <string name="noApplications" msgid="1139487441772284671">"कुनै पनि एपहरूले यो कार्य गर्न सक्दैनन्।"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"तपाईं तपाईंको कार्य प्रोफाइल बाहिर यो एप प्रयोग गरिरहनु भएको छ"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"तपाईं आफ्नो कार्य प्रोफाइलमा यो एप प्रयोग गरिरहनु भएको छ"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"सधैँ"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"एक पटक मात्र"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ले कार्य प्रोफाइलमा काम गर्दैन"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> पिन गर्नुहोस्"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> लाई अनपिन गर्नुहोस्"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"सम्पादन गर्नुहोस्"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # फाइल}other{{file_name} + # वटा फाइल}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{# भन्दा बढी फाइल}other{# भन्दा बढी फाइलहरू}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"टेक्स्ट सेयर गरिँदै छ"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"लिंक सेयर गरिँदै छ"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{फोटो सेयर गरिँदै छ}other{# वटा फोटो सेयर गरिँदै छ}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{भिडियो सेयर गरिँदै छ}other{# वटा भिडियो सेयर गरिँदै छ}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# सामग्री सेयर गरिँदै छ}other{# वटा सामग्री सेयर गरिँदै छ}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"टेक्स्ट भएको फोटो सेयर गरिँदै छ"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"लिंक भएको फोटो सेयर गरिँदै छ"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"कुनै पनि व्यक्तिसँग सेयर गर्ने सिफारिस गरिएको छैन"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"अनुप्रयोगहरूको सूची"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"यो एपलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले यो USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"व्यक्तिगत"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"काम"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"व्यक्तिगत दृश्य"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"कार्य दृश्य"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"तपाईंका IT एड्मिनले ब्लक गर्नुभएको छ"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"यो सामग्री कामसम्बन्धी एपहरूमार्फत सेयर गर्न मिल्दैन"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"यो सामग्री कामसम्बन्धी एपहरूमार्फत खोल्न मिल्दैन"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"यो सामग्री व्यक्तिगत एपहरूमार्फत सेयर गर्न मिल्दैन"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"यो सामग्री व्यक्तिगत एपहरूमार्फत खोल्न मिल्दैन"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"कार्य प्रोफाइल पज गरिएको छ"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"अन गर्न ट्याप गर्नुहोस्"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"यो सामग्री खोल्न मिल्ने कुनै पनि कामसम्बन्धी एप छैन"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"यो सामग्री खोल्न मिल्ने कुनै पनि व्यक्तिगत एप छैन"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g> तपाईंको व्यक्तिगत प्रोफाइलमा खोल्ने हो?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g> तपाईंको कार्य प्रोफाइलमा खोल्ने हो?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"व्यक्तिगत ब्राउजर प्रयोग गर्नुहोस्"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"कार्य ब्राउजर प्रयोग गर्नुहोस्"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"टेक्स्ट हटाउनुहोस्"</string>
+ <string name="include_text" msgid="642280283268536140">"टेक्स्ट समावेश गर्नुहोस्"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"लिंक हटाउनुहोस्"</string>
+ <string name="include_link" msgid="827855767220339802">"लिंक समावेश गर्नुहोस्"</string>
+</resources>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
new file mode 100644
index 00000000..a779bf68
--- /dev/null
+++ b/java/res/values-nl/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Actie voltooien met"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Actie voltooien met <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Actie voltooien"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Openen met"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Openen met <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Openen"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Links van <xliff:g id="HOST">%1$s</xliff:g> openen met"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Links openen met"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Links openen met <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Links van <xliff:g id="HOST">%1$s</xliff:g> openen met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Toegang geven"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Bewerken met"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Bewerken met <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Bewerken"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Delen"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Delen met <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Delen"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Verzenden met"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Versturen met <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Verzenden"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Een startschermapp selecteren"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> gebruiken als Home"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Afbeelding vastleggen"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Afbeelding vastleggen met"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Afbeelding vastleggen met <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Afbeelding vastleggen"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Een andere app gebruiken"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Een actie selecteren"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Geen enkele app kan deze actie uitvoeren."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Je gebruikt deze app buiten je werkprofiel"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"U gebruikt deze app in je werkprofiel"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Altijd"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Eén keer"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ondersteunt werkprofiel niet"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> vastzetten"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> losmaken"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Bewerken"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # bestand}other{{file_name} + # bestanden}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # bestand}other{+ # bestanden}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Tekst delen"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Link delen"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Afbeelding delen}other{# afbeeldingen delen}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Video delen}other{# video\'s delen}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# item delen}other{# items delen}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Afbeelding delen met tekst"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Afbeelding delen met link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Geen aanbevolen mensen om mee te delen"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lijst met apps"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Deze app heeft geen opnamerechten gekregen, maar zou audio kunnen vastleggen via dit USB-apparaat."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Persoonlijk"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Werk"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Persoonlijke weergave"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Werkweergave"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Geblokkeerd door je IT-beheerder"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Deze content kan niet worden gedeeld met werk-apps"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Deze content kan niet worden geopend met werk-apps"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Deze content kan niet worden gedeeld met persoonlijke apps"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Deze content kan niet worden geopend met persoonlijke apps"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Werkprofiel is onderbroken"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Tik om aan te zetten"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Geen werk-apps"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Geen persoonlijke apps"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g> openen in je persoonlijke profiel?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g> openen in je werkprofiel?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Persoonlijke browser gebruiken"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Werkbrowser gebruiken"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Tekst uitsluiten"</string>
+ <string name="include_text" msgid="642280283268536140">"Tekst opnemen"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Link uitsluiten"</string>
+ <string name="include_link" msgid="827855767220339802">"Link opnemen"</string>
+</resources>
diff --git a/java/res/values-or/strings.xml b/java/res/values-or/strings.xml
new file mode 100644
index 00000000..0ed83589
--- /dev/null
+++ b/java/res/values-or/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"ସହିତ ଖୋଲନ୍ତୁ"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଖୋଲନ୍ତୁ"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"ଖୋଲନ୍ତୁ"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"ଏଥିରେ <xliff:g id="HOST">%1$s</xliff:g> ଲିଙ୍କ୍‍ଗୁଡ଼ିକ ଖୋଲନ୍ତୁ"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"ଏଥିରେ ଲିଙ୍କ୍‍ଗୁଡ଼ିକ ଖୋଲନ୍ତୁ"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> ମାଧ୍ୟମରେ ଲିଙ୍କ୍‍ଗୁଡ଼ିକ ଖୋଲନ୍ତୁ"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="APPLICATION">%2$s</xliff:g> ମାଧ୍ୟମରେ <xliff:g id="HOST">%1$s</xliff:g> ଲିଙ୍କ୍‍ଗୁଡ଼ିକ ଖୋଲନ୍ତୁ"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"ଆକ୍ସେସ ଦିଅନ୍ତୁ"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"ସହିତ ଏଡିଟ କରନ୍ତୁ"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> ମାଧ୍ୟମରେ ଏଡିଟ କରନ୍ତୁ"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"ଏଡିଟ କରନ୍ତୁ"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"ସେୟାର୍ କରନ୍ତୁ"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> ସହ ସେୟାର କରନ୍ତୁ"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"ସେୟାର୍‌ କରନ୍ତୁ"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"ଏହା ଜରିଆରେ ପଠାନ୍ତୁ"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> ବ୍ୟବହାର କରି ପଠାନ୍ତୁ"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"ପଠାନ୍ତୁ"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"ଏକ ହୋମ ଆପ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"ହୋମ ଭାବେ <xliff:g id="APP">%1$s</xliff:g>କୁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"ଇମେଜ୍‍ କ୍ୟାପଚର୍ କରନ୍ତୁ"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"ଏହା ସହ ଇମେଜ୍‍ କ୍ୟାପଚର୍ କରନ୍ତୁ"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> ମାଧ୍ୟମରେ ଇମେଜ କେପଚର କରନ୍ତୁ"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"ଇମେଜ୍‍ କ୍ୟାପଚର୍ କରନ୍ତୁ"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"ଏକ ଭିନ୍ନ ଆପ୍‌ର ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"ଏକ କାର୍ଯ୍ୟ ବାଛନ୍ତୁ"</string>
+ <string name="noApplications" msgid="1139487441772284671">"କୌଣସି ଆପ୍‍ ଏହି କାର୍ଯ୍ୟ କରିପାରିବ ନାହିଁ।"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"ଆପଣ ନିଜର ୱର୍କ ପ୍ରୋଫାଇଲ୍‌ ବାହାରେ ଏହି ଆପ୍‌ର ପ୍ରୟୋଗ କରୁଛନ୍ତି"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"ଆପଣ ନିଜ ୱର୍କ ପ୍ରୋଫାଇଲ୍‌ରେ ଏହି ଆପ୍‌ର ବ୍ୟବହାର କରୁଛନ୍ତି"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"ସର୍ବଦା"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"ଥରେ ମାତ୍ର"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ୱାର୍କ ପ୍ରୋଫାଇଲକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g>କୁ ପିନ କରନ୍ତୁ"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g>ରେ ଅନ୍‌ପିନ୍ କରନ୍ତୁ"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"ଏଡିଟ କରନ୍ତୁ"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + #ଟି ଫାଇଲ}other{{file_name} + #ଟି ଫାଇଲ}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ #ଟି ଫାଇଲ}other{+ #ଟି ଫାଇଲ}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"ଟେକ୍ସଟ ସେୟାର କରାଯାଉଛି"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"ଲିଙ୍କ ସେୟାର କରାଯାଉଛି"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{ଇମେଜ ସେୟାର କରାଯାଉଛି}other{#ଟିି ଇମେଜ ସେୟାର କରାଯାଉଛି}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{ଭିଡିଓ ସେୟାର କରାଯାଉଛି}other{#ଟି ଭିଡିଓ ସେୟାର କରାଯାଉଛି}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{#ଟି ଆଇଟମ ସେୟାର କରାଯାଉଛି}other{#ଟି ଆଇଟମ ସେୟାର କରାଯାଉଛି}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"ଟେକ୍ସଟରେ ଇମେଜ ସେୟାର ହେଉଛି"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"ଲିଙ୍କରେ ଇମେଜ ସେୟାର ହେଉଛି"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"ଏହାକୁ ସେୟାର୍ କରିବା ପାଇଁ କୌଣସି ସୁପାରିଶ କରାଯାଇଥିବା ଲୋକ ନାହାଁନ୍ତି"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"ଆପ୍ସ ତାଲିକା"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"ଏହି ଆପ୍‌କୁ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ କିନ୍ତୁ ଏହି USB ଡିଭାଇସ୍ ଜରିଆରେ ଅଡିଓ କ୍ୟାପ୍‍ଚର୍‍ କରିପାରିବ।"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"ବ୍ୟକ୍ତିଗତ"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"ୱାର୍କ"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"ବ୍ୟକ୍ତିଗତ ଭ୍ୟୁ"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"ୱାର୍କ ଭ୍ୟୁ"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"ଆପଣଙ୍କ IT ଆଡମିନଙ୍କ ଦ୍ୱାରା ବ୍ଲକ୍ କରାଯାଇଛି"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"ଏହି ବିଷୟବସ୍ତୁ ୱାର୍କ ଆପଗୁଡ଼ିକରେ ସେୟାର୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"ଏହି ବିଷୟବସ୍ତୁ ୱାର୍କ ଆପଗୁଡ଼ିକରେ ଖୋଲାଯାଇପାରିବ ନାହିଁ"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"ଏହି ବିଷୟବସ୍ତୁ ବ୍ୟକ୍ତିଗତ ଆପଗୁଡ଼ିକରେ ସେୟାର୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"ଏହି ବିଷୟବସ୍ତୁ ବ୍ୟକ୍ତିଗତ ଆପଗୁଡ଼ିକରେ ଖୋଲାଯାଇପାରିବ ନାହିଁ"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"ୱାର୍କ ପ୍ରୋଫାଇଲକୁ ବିରତ କରାଯାଇଛି"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ଚାଲୁ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"କୌଣସି ୱାର୍କ ଆପ୍ ନାହିଁ"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"କୌଣସି ବ୍ୟକ୍ତିଗତ ଆପ୍ ନାହିଁ"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g>କୁ ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ପ୍ରୋଫାଇଲରେ ଖୋଲିବେ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g>କୁ ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲରେ ଖୋଲିବେ?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"ବ୍ୟକ୍ତିଗତ ବ୍ରାଉଜର୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"ୱାର୍କ ବ୍ରାଉଜର୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"ଟେକ୍ସଟକୁ ବାଦ ଦିଅନ୍ତୁ"</string>
+ <string name="include_text" msgid="642280283268536140">"ଟେକ୍ସଟକୁ ଅନ୍ତର୍ଭୁକ୍ତ କରନ୍ତୁ"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"ଲିଙ୍କକୁ ବାଦ ଦିଅନ୍ତୁ"</string>
+ <string name="include_link" msgid="827855767220339802">"ଲିଙ୍କକୁ ଅନ୍ତର୍ଭୁକ୍ତ କରନ୍ତୁ"</string>
+</resources>
diff --git a/java/res/values-pa/strings.xml b/java/res/values-pa/strings.xml
new file mode 100644
index 00000000..3076880d
--- /dev/null
+++ b/java/res/values-pa/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"ਇਸਨੂੰ ਵਰਤਦੇ ਹੋਏ ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਨਾਲ ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"ਨਾਲ ਖੋਲ੍ਹੋ"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> ਨਾਲ ਖੋਲ੍ਹੋ"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"ਖੋਲ੍ਹੋ"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ ਇਸ ਨਾਲ ਖੋਲ੍ਹੋ"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"ਲਿੰਕਾਂ ਨੂੰ ਇਸ ਨਾਲ ਖੋਲ੍ਹੋ"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"ਲਿੰਕਾਂ ਨੂੰ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਖੋਲ੍ਹੋ"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ <xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ ਖੋਲ੍ਹੋ"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"ਪਹੁੰਚ ਦਿਓ"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"ਇਸ ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"ਸੰਪਾਦਨ ਕਰੋ"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"ਸਾਂਝਾ ਕਰੋ"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> ਨਾਲ ਸਾਂਝਾ ਕਰੋ"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"ਸਾਂਝਾ ਕਰੋ"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"ਇਸ ਦੀ ਵਰਤੋਂ ਨਾਲ ਭੇਜੋ"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਨਾਲ ਭੇਜੋ"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"ਭੇਜੋ"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"ਇੱਕ ਹੋਮ ਐਪ ਚੁਣੋ"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> ਨੂੰ ਘਰ ਵਜੋਂ ਵਰਤੋ"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"ਚਿਤਰ ਕੈਪਚਰ ਕਰੋ"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"ਇਸ ਨਾਲ ਚਿਤਰ ਕੈਪਚਰ ਕਰੋ"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> ਨਾਲ ਚਿੱਤਰ ਨੂੰ ਕੈਪਚਰ ਕਰੋ"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"ਚਿਤਰ ਕੈਪਚਰ ਕਰੋ"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"ਇੱਕ ਵੱਖਰਾ ਖਾਤਾ ਵਰਤੋ"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"ਕਾਰਵਾਈ ਚੁਣੋ"</string>
+ <string name="noApplications" msgid="1139487441772284671">"ਕੋਈ ਐਪਾਂ ਇਸ ਕਾਰਵਾਈ ਨੂੰ ਨਹੀਂ ਕਰ ਸਕਦੀਆਂ।"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"ਤੁਸੀਂ ਇਹ ਐਪ ਆਪਣੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦੇ ਬਾਹਰ ਵਰਤ ਰਹੇ ਹੋ"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"ਤੁਸੀਂ ਇਹ ਐਪ ਆਪਣੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਵਰਤ ਰਹੇ ਹੋ"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"ਹਮੇਸ਼ਾਂ"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"ਕੇਵਲ ਇੱਕ ਵਾਰ"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ ਹੈ"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> ਨੂੰ ਪਿੰਨ ਕਰੋ"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> ਨੂੰ ਅਨਪਿੰਨ ਕਰੋ"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"ਸੰਪਾਦਨ ਕਰੋ"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ਫ਼ਾਈਲ}one{{file_name} + # ਫ਼ਾਈਲ}other{{file_name} + # ਫ਼ਾਈਲਾਂ}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ਫ਼ਾਈਲ}one{+ # ਫ਼ਾਈਲ}other{+ # ਫ਼ਾਈਲਾਂ}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"ਲਿਖਤ ਸੁਨੇਹਾ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"ਲਿੰਕ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{ਚਿੱਤਰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}one{# ਚਿੱਤਰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}other{# ਚਿੱਤਰ ਸਾਂਝੇ ਕੀਤੇ ਜਾ ਰਹੇ ਹਨ}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{ਵੀਡੀਓ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}one{# ਵੀਡੀਓ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}other{# ਵੀਡੀਓ ਸਾਂਝੇ ਕੀਤੇ ਜਾ ਰਹੇ ਹਨ}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# ਆਈਟਮ ਸਾਂਝੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ}one{# ਆਈਟਮ ਸਾਂਝੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ}other{# ਆਈਟਮਾਂ ਸਾਂਝੀਆਂ ਕੀਤੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"ਲਿਖਤ ਸੁਨੇਹੇ ਨਾਲ ਚਿੱਤਰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"ਲਿੰਕ ਨਾਲ ਚਿੱਤਰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"ਸਾਂਝਾ ਕਰਨ ਲਈ ਕੋਈ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੇ ਲੋਕ ਨਹੀਂ"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"ਐਪ ਸੂਚੀ"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"ਇਸ ਐਪ ਨੂੰ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਪਰ ਇਹ USB ਡੀਵਾਈਸ ਰਾਹੀਂ ਆਡੀਓ ਕੈਪਚਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"ਨਿੱਜੀ"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"ਕੰਮ ਸੰਬੰਧੀ"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"ਵਿਅਕਤੀਗਤ ਦ੍ਰਿਸ਼"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"ਕਾਰਜ ਦ੍ਰਿਸ਼"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"ਤੁਹਾਡੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"ਇਸ ਸਮੱਗਰੀ ਨੂੰ ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਨਾਲ ਸਾਂਝਾ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"ਇਸ ਸਮੱਗਰੀ ਨੂੰ ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਨਾਲ ਨਹੀਂ ਖੋਲ੍ਹਿਆ ਜਾ ਸਕਦਾ"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"ਇਸ ਸਮੱਗਰੀ ਨੂੰ ਨਿੱਜੀ ਐਪਾਂ ਨਾਲ ਸਾਂਝਾ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"ਇਸ ਸਮੱਗਰੀ ਨੂੰ ਨਿੱਜੀ ਐਪਾਂ ਨਾਲ ਨਹੀਂ ਖੋਲ੍ਹਿਆ ਜਾ ਸਕਦਾ"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ਚਾਲੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"ਕੋਈ ਕੰਮ ਸੰਬੰਧੀ ਐਪ ਨਹੀਂ"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"ਕੋਈ ਨਿੱਜੀ ਐਪ ਨਹੀਂ"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"ਕੀ ਆਪਣੇ ਨਿੱਜੀ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ <xliff:g id="APP">%s</xliff:g> ਨੂੰ ਖੋਲ੍ਹਣਾ ਹੈ?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"ਕੀ ਆਪਣੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ <xliff:g id="APP">%s</xliff:g> ਨੂੰ ਖੋਲ੍ਹਣਾ ਹੈ?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"ਨਿੱਜੀ ਬ੍ਰਾਊਜ਼ਰ ਵਰਤੋ"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"ਕੰਮ ਸੰਬੰਧੀ ਬ੍ਰਾਊਜ਼ਰ ਵਰਤੋ"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"ਲਿਖਤ ਨੂੰ ਸ਼ਾਮਲ ਨਾ ਕਰੋ"</string>
+ <string name="include_text" msgid="642280283268536140">"ਲਿਖਤ ਨੂੰ ਸ਼ਾਮਲ ਕਰੋ"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"ਲਿੰਕ ਨੂੰ ਸ਼ਾਮਲ ਨਾ ਕਰੋ"</string>
+ <string name="include_link" msgid="827855767220339802">"ਲਿੰਕ ਸ਼ਾਮਲ ਕਰੋ"</string>
+</resources>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
new file mode 100644
index 00000000..634a32d4
--- /dev/null
+++ b/java/res/values-pl/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Wykonaj czynność przez..."</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Wykonaj działanie w aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Wykonaj działanie"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Otwórz w aplikacji"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Otwórz w aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Otwórz"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Otwieraj linki z <xliff:g id="HOST">%1$s</xliff:g> w"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Otwieraj linki w"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Otwieraj linki w aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Otwieraj linki z <xliff:g id="HOST">%1$s</xliff:g> w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Przyznaj dostęp"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Edytuj w aplikacji"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Edytuj w aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Edytuj"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Udostępnianie"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Udostępnij w aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Udostępnij"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Wyślij za pomocą"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Wyślij za pomocą aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Wyślij"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Wybierz aplikację ekranu głównego"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Użyj aplikacji <xliff:g id="APP">%1$s</xliff:g> jako aplikacji Home"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Zrób zdjęcie"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Zrób zdjęcie w aplikacji"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Zrób zdjęcie w aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Zrób zdjęcie"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Użyj innej aplikacji"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Wybierz działanie"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Żadna z aplikacji nie może wykonać tej czynności."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Używasz tej aplikacji poza profilem służbowym"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Używasz tej aplikacji w swoim profilu służbowym"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Zawsze"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Tylko raz"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"Aplikacja <xliff:g id="APP">%1$s</xliff:g> nie obsługuje profilu służbowego"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Przypnij aplikację <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Odepnij: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Edytuj"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # plik}few{{file_name} + # pliki}many{{file_name} + # plików}other{{file_name} + # pliku}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{i jeszcze # plik}few{i jeszcze # pliki}many{i jeszcze # plików}other{i jeszcze # pliku}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Udostępnianie tekstu"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Udostępnianie linku"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Udostępnianie obrazu}few{Udostępnianie # obrazów}many{Udostępnianie # obrazów}other{Udostępnianie # obrazu}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Udostępnianie filmu}few{Udostępnianie # filmów}many{Udostępnianie # filmów}other{Udostępnianie # filmu}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Udostępnianie # elementu}few{Udostępnianie # elementów}many{Udostępnianie # elementów}other{Udostępnianie # elementu}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Udostępnianie obrazu z tekstem"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Udostępnianie obrazu z linkiem"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Brak polecanych osób, którym możesz udostępniać"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lista aplikacji"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Ta aplikacja nie ma uprawnień do nagrywania, ale może rejestrować dźwięk za pomocą tego urządzenia USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Osobiste"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Służbowe"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Widok osobisty"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Widok służbowy"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Działanie zablokowane przez administratora IT"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Tych treści nie można udostępniać w aplikacjach służbowych"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Tych treści nie można otworzyć w aplikacjach służbowych"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Tych treści nie można udostępniać w aplikacjach osobistych"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Tych treści nie można otworzyć w aplikacjach osobistych"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Działanie profilu służbowego jest wstrzymane"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Kliknij, aby włączyć"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Brak aplikacji służbowych"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Brak aplikacji osobistych"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Otworzyć aplikację <xliff:g id="APP">%s</xliff:g> w profilu osobistym?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Otworzyć aplikację <xliff:g id="APP">%s</xliff:g> w profilu służbowym?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Użyj przeglądarki osobistej"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Użyj przeglądarki służbowej"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Wyklucz tekst"</string>
+ <string name="include_text" msgid="642280283268536140">"Dołącz tekst"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Wyklucz link"</string>
+ <string name="include_link" msgid="827855767220339802">"Dołącz link"</string>
+</resources>
diff --git a/java/res/values-pt-rBR/strings.xml b/java/res/values-pt-rBR/strings.xml
new file mode 100644
index 00000000..8f1746fe
--- /dev/null
+++ b/java/res/values-pt-rBR/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Complete a ação usando"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Complete a ação usando o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Concluir ação"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Abrir com"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Abra com o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Abrir"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> usando"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Abrir links com"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Abrir links com <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> usando <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Permitir acesso"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Editar com"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Edite com o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Editar"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Compartilhar"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Compartilhe com o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Compartilhar"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Enviar usando"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Envie usando o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Enviar"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Selecione um app de início"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Use <xliff:g id="APP">%1$s</xliff:g> como app inicial"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Capturar imagem"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Capturar imagem com"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Capture uma imagem com o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Capturar imagem"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Usar outro app"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Escolha uma ação"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Nenhum app pode realizar esta ação."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Este app está sendo usado fora de seu perfil de trabalho"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Você está usando este app em seu perfil de trabalho"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Sempre"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Só uma vez"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"O app <xliff:g id="APP">%1$s</xliff:g> não tem suporte ao perfil de trabalho"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fixar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Liberar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Editar"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # arquivo}one{{file_name} + # arquivo}many{{file_name} + # arquivos}other{{file_name} + # arquivos}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{Mais # arquivo}one{Mais # arquivo}many{Mais # de arquivos}other{Mais # arquivos}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Compartilhando texto"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Compartilhando link"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Compartilhando imagem}one{Compartilhando # imagem}many{Compartilhando # de imagens}other{Compartilhando # imagens}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Compartilhando vídeo}one{Compartilhando # vídeo}many{Compartilhando # de vídeos}other{Compartilhando # vídeos}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Compartilhando # item}one{Compartilhando # item}many{Compartilhando # de itens}other{Compartilhando # itens}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Compartilhando imagem com texto"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Compartilhando imagem com link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Não há sugestões de pessoas para compartilhar"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lista de apps"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Pessoal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Trabalho"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Visualização pessoal"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Visualização de trabalho"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Compartilhamento bloqueado pelo administrador de TI"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Não é possível compartilhar esse conteúdo com apps de trabalho"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Não é possível abrir esse conteúdo com apps de trabalho"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Não é possível compartilhar esse conteúdo com apps pessoais"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Não é possível abrir esse conteúdo com apps pessoais"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"O perfil de trabalho está pausado"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Toque para ativar"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Nenhum app de trabalho"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Nenhum app pessoal"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Abrir o app <xliff:g id="APP">%s</xliff:g> no seu perfil pessoal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Abrir o app <xliff:g id="APP">%s</xliff:g> no seu perfil de trabalho?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Usar o navegador pessoal"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Usar o navegador de trabalho"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Excluir texto"</string>
+ <string name="include_text" msgid="642280283268536140">"Incluir texto"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Excluir link"</string>
+ <string name="include_link" msgid="827855767220339802">"Incluir link"</string>
+</resources>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
new file mode 100644
index 00000000..cc2bd472
--- /dev/null
+++ b/java/res/values-pt-rPT/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Concluir ação utilizando"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Conclua a ação com a app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Concluir ação"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Abrir com"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Abra com a app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Abrir"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Abrir os links de <xliff:g id="HOST">%1$s</xliff:g> com:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Abrir os links com:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Abra os links com a app <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Abra os links de <xliff:g id="HOST">%1$s</xliff:g> com a app <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Dê acesso"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Editar com"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Edite com a app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Editar"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Partilhar"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Partilhe com a app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Partilhar"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Enviar com"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Envie com a app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Enviar"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Selecione uma app Página inicial"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Use a app <xliff:g id="APP">%1$s</xliff:g> como Página inicial"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Capturar imagem"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Capturar imagem com"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Capture a imagem com a app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Capturar imagem"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Usar outra app"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Escolha uma ação"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Nenhuma app pode efetuar esta ação."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Está a utilizar esta app fora do seu perfil de trabalho"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Está a utilizar esta app no seu perfil de trabalho"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Sempre"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Apenas uma vez"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"A app <xliff:g id="APP">%1$s</xliff:g> não suporta o perfil de trabalho"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fixar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Soltar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Editar"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ficheiro}many{{file_name} + # ficheiros}other{{file_name} + # ficheiros}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ficheiro}many{+ # ficheiros}other{+ # ficheiros}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"A partilhar texto"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"A partilhar link"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{A partilhar imagem}many{A partilhar # imagens}other{A partilhar # imagens}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{A partilhar vídeo}many{A partilhar # vídeos}other{A partilhar # vídeos}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{A partilhar # item}many{A partilhar # itens}other{A partilhar # itens}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"A partilh. imag. c/ texto"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"A partilhar imag. c/ link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Não existem pessoas recomendadas com quem partilhar"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lista de aplicações"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Esta app não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Pessoal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Trabalho"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Vista pessoal"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Vista de trabalho"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Bloqueado pelo administrador de TI"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Não é possível partilhar este conteúdo com apps de trabalho"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Não é possível abrir este conteúdo com apps de trabalho"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Não é possível partilhar este conteúdo com apps pessoais"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Não é possível abrir este conteúdo com apps pessoais"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Perfil de trabalho em pausa"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Tocar para ativar"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Sem apps de trabalho"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Sem apps pessoais"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Abrir a app <xliff:g id="APP">%s</xliff:g> no seu perfil pessoal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Abrir a app <xliff:g id="APP">%s</xliff:g> no seu perfil de trabalho?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Usar navegador pessoal"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Usar navegador de trabalho"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Excluir texto"</string>
+ <string name="include_text" msgid="642280283268536140">"Incluir texto"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Excluir link"</string>
+ <string name="include_link" msgid="827855767220339802">"Incluir link"</string>
+</resources>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
new file mode 100644
index 00000000..8f1746fe
--- /dev/null
+++ b/java/res/values-pt/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Complete a ação usando"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Complete a ação usando o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Concluir ação"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Abrir com"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Abra com o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Abrir"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> usando"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Abrir links com"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Abrir links com <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> usando <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Permitir acesso"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Editar com"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Edite com o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Editar"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Compartilhar"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Compartilhe com o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Compartilhar"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Enviar usando"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Envie usando o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Enviar"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Selecione um app de início"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Use <xliff:g id="APP">%1$s</xliff:g> como app inicial"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Capturar imagem"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Capturar imagem com"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Capture uma imagem com o app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Capturar imagem"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Usar outro app"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Escolha uma ação"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Nenhum app pode realizar esta ação."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Este app está sendo usado fora de seu perfil de trabalho"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Você está usando este app em seu perfil de trabalho"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Sempre"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Só uma vez"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"O app <xliff:g id="APP">%1$s</xliff:g> não tem suporte ao perfil de trabalho"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fixar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Liberar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Editar"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # arquivo}one{{file_name} + # arquivo}many{{file_name} + # arquivos}other{{file_name} + # arquivos}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{Mais # arquivo}one{Mais # arquivo}many{Mais # de arquivos}other{Mais # arquivos}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Compartilhando texto"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Compartilhando link"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Compartilhando imagem}one{Compartilhando # imagem}many{Compartilhando # de imagens}other{Compartilhando # imagens}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Compartilhando vídeo}one{Compartilhando # vídeo}many{Compartilhando # de vídeos}other{Compartilhando # vídeos}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Compartilhando # item}one{Compartilhando # item}many{Compartilhando # de itens}other{Compartilhando # itens}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Compartilhando imagem com texto"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Compartilhando imagem com link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Não há sugestões de pessoas para compartilhar"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lista de apps"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Pessoal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Trabalho"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Visualização pessoal"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Visualização de trabalho"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Compartilhamento bloqueado pelo administrador de TI"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Não é possível compartilhar esse conteúdo com apps de trabalho"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Não é possível abrir esse conteúdo com apps de trabalho"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Não é possível compartilhar esse conteúdo com apps pessoais"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Não é possível abrir esse conteúdo com apps pessoais"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"O perfil de trabalho está pausado"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Toque para ativar"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Nenhum app de trabalho"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Nenhum app pessoal"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Abrir o app <xliff:g id="APP">%s</xliff:g> no seu perfil pessoal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Abrir o app <xliff:g id="APP">%s</xliff:g> no seu perfil de trabalho?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Usar o navegador pessoal"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Usar o navegador de trabalho"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Excluir texto"</string>
+ <string name="include_text" msgid="642280283268536140">"Incluir texto"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Excluir link"</string>
+ <string name="include_link" msgid="827855767220339802">"Incluir link"</string>
+</resources>
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
new file mode 100644
index 00000000..72962442
--- /dev/null
+++ b/java/res/values-ro/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Finalizare acțiune utilizând"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Finalizează acțiunea folosind <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Finalizează acțiunea"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Deschide cu"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Deschide cu <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Deschide"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Deschide linkurile <xliff:g id="HOST">%1$s</xliff:g> cu"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Deschide linkurile cu"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Deschide linkurile cu <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Deschide linkurile <xliff:g id="HOST">%1$s</xliff:g> cu <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Permite accesul"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Editează cu"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Editează cu <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Editează"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Trimite"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Permite accesul pentru <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Trimite"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Trimite folosind"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Trimite folosind <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Trimite"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Selectează o aplicație de pe ecranul de pornire"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Folosește <xliff:g id="APP">%1$s</xliff:g> ca aplicație pentru casă"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Fotografiază"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Fotografiază cu"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Fotografiază cu <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Fotografiază"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Folosește altă aplicație"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Alege o acțiune"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Această acțiune nu poate fi efectuată de nicio aplicație."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Folosești această aplicație în afara profilului de serviciu"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Folosești această aplicație în profilul de serviciu"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Întotdeauna"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Numai o dată"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> nu acceptă profilul de serviciu"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fixează <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Anulează fixarea pentru <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Editează"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # fișier}few{{file_name} + # fișiere}other{{file_name} + # de fișiere}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # fișier}few{+ # fișiere}other{+ # de fișiere}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Se trimite textul"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Se trimite linkul"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Se trimite imaginea}few{Se trimit # imagini}other{Se trimit # de imagini}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Se trimite videoclipul}few{Se trimit # videoclipuri}other{Se trimit # de videoclipuri}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Se trimite # element}few{Se trimit # elemente}other{Se trimit # de elemente}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Se trimite imaginea cu text"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Se trimite imaginea cu linkul"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Nu există persoane recomandate pentru permiterea accesului"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lista de aplicații"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Permisiunea de înregistrare nu a fost acordată aplicației, dar aceasta poate să înregistreze conținut audio prin intermediul acestui dispozitiv USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Serviciu"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Afișarea conținutului personal"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Afișarea conținutului de lucru"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blocat de administratorul IT"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Acest conținut nu poate fi trimis cu aplicații pentru lucru"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Acest conținut nu poate fi deschis cu aplicații pentru lucru"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Acest conținut nu poate fi trimis cu aplicații personale"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Acest conținut nu poate fi deschis cu aplicații personale"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Profilul de serviciu este întrerupt"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Atinge pentru a activa"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Nicio aplicație pentru lucru"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Nicio aplicație personală"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Deschizi <xliff:g id="APP">%s</xliff:g> în profilul personal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Deschizi <xliff:g id="APP">%s</xliff:g> în profilul de serviciu?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Folosește browserul personal"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Folosește browserul de serviciu"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Exclude textul"</string>
+ <string name="include_text" msgid="642280283268536140">"Include textul"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Exclude linkul"</string>
+ <string name="include_link" msgid="827855767220339802">"Include linkul"</string>
+</resources>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
new file mode 100644
index 00000000..2db2c5ea
--- /dev/null
+++ b/java/res/values-ru/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Что использовать?"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Выполнить действие с помощью приложения \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Выполнить действие"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Открыть с помощью приложения:"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Открыть с помощью приложения \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Открыть"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Открывать ссылки <xliff:g id="HOST">%1$s</xliff:g> с помощью:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Открывать ссылки с помощью:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Открывать ссылки в браузере <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Открывать ссылки <xliff:g id="HOST">%1$s</xliff:g> в браузере <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Открыть доступ"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Редактировать с помощью приложения:"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Редактировать с помощью приложения \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Изменить"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Поделиться"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Поделиться с помощью приложения \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Поделиться"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Выберите приложение"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Отправить с помощью приложения \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Отправить"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Выберите главное приложение"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Использовать приложение \"<xliff:g id="APP">%1$s</xliff:g>\" для главного экрана"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Сделать снимок"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Делать снимки с помощью:"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Сделать снимок с помощью приложения \"<xliff:g id="APP">%1$s</xliff:g>\""</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Сделать снимок"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Другое приложение"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Выберите действие"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Действие не поддерживается ни в одном приложении."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Это приложение используется в личном профиле"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Вы перешли в рабочий профиль"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Всегда"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Только сейчас"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"Приложение \"<xliff:g id="APP">%1$s</xliff:g>\" недоступно в рабочем профиле."</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Закрепить приложение \"<xliff:g id="LABEL">%1$s</xliff:g>\""</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Открепить приложение \"<xliff:g id="LABEL">%1$s</xliff:g>\""</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Изменить"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{\"{file_name}\" и ещё # файл}one{\"{file_name}\" и ещё # файл}few{\"{file_name}\" и ещё # файла}many{\"{file_name}\" и ещё # файлов}other{\"{file_name}\" и ещё # файла}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{и ещё # файл}one{и ещё # файл}few{и ещё # файла}many{и ещё # файлов}other{и ещё # файла}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Отправка сообщения"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Отправка ссылки"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Отправка изображения}one{Отправка # изображения}few{Отправка # изображений}many{Отправка # изображений}other{Отправка # изображения}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Отправка видео}one{Отправка # видео}few{Отправка # видео}many{Отправка # видео}other{Отправка # видео}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Отправка # объекта}one{Отправка # объекта}few{Отправка # объектов}many{Отправка # объектов}other{Отправка # объекта}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Сообщение с изображением"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Ссылка на изображение"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Рекомендованных получателей нет."</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Список приложений"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Приложению не разрешено записывать звук, однако оно может делать это с помощью этого USB-устройства."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Личное"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Рабочее"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Просмотр личных данных"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Просмотр рабочих данных"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Заблокировано вашим администратором"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Этот контент нельзя открывать через рабочие приложения."</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Этот контент нельзя открыть в рабочем приложении."</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Этот контент нельзя открывать через личные приложения."</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Этот контент нельзя открыть в личном приложении."</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Действие рабочего профиля приостановлено."</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Нажмите, чтобы включить"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Не поддерживается рабочими приложениями."</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Не поддерживается личными приложениями."</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Открыть приложение \"<xliff:g id="APP">%s</xliff:g>\" в личном профиле?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Открыть приложение \"<xliff:g id="APP">%s</xliff:g>\" в рабочем профиле?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Использовать личный браузер"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Использовать рабочий браузер"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Исключить текст"</string>
+ <string name="include_text" msgid="642280283268536140">"Вернуть текст"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Исключить ссылку"</string>
+ <string name="include_link" msgid="827855767220339802">"Вернуть ссылку"</string>
+</resources>
diff --git a/java/res/values-si/strings.xml b/java/res/values-si/strings.xml
new file mode 100644
index 00000000..bbb01071
--- /dev/null
+++ b/java/res/values-si/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"පහත භාවිතයෙන් ක්‍රියාව සම්පූර්ණ කරන්න"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> භාවිතයෙන් ක්‍රියාව සම්පූර්ණ කරන්න"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"ක්‍රියාව සම්පූර්ණ කරන්න"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"සමඟ විවෘත කරන්න"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> සමග විවෘත කරන්න"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"විවෘත කරන්න"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"සමග <xliff:g id="HOST">%1$s</xliff:g> සබැඳි විවෘත කරන්න"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"සමඟ සබැඳි විවෘත කරන්න"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> සමඟ සබැඳි විවෘත කරන්න"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="APPLICATION">%2$s</xliff:g> සමග <xliff:g id="HOST">%1$s</xliff:g> සබැඳි විවෘත කරන්න"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"ප්‍රවේශය දෙන්න"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"සමඟ සංස්කරණය කරන්න"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> සමග සංස්කරණය කරන්න"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"සංස්කරණය"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"බෙදා ගන්න"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> සමග බෙදා ගන්න"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"බෙදා ගන්න"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"මෙය භාවිතයෙන් යවන්න"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> භාවිතයෙන් යවන්න"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"යවන්න"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"මුල් පිටු යෙදුම තෝරන්න"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> නිවස ලෙස භාවිතා කරන්න"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"රූපය ග්‍රහණය කර ගන්න"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"මෙය සමග රූපය ග්‍රහණය කර ගන්න"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> සමග රූපය ග්‍රහණය කර ගන්න"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"රූපය ග්‍රහණය කර ගන්න"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"වෙනත් යෙදුමක් භාවිතා කරන්න"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"ක්‍රියාවක් තෝරා ගන්න"</string>
+ <string name="noApplications" msgid="1139487441772284671">"මෙම ක්‍රියාව සිදු කිරීමට කිසිදු යෙදුමකට නොහැකිය."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"මෙම යෙදුම ඔබගේ කාර්යාල පැතිකඩින් පිට දී ඔබ භාවිතා කරයි"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"මෙම යෙදුම ඔබගේ පුද්ගලික කොටසේ ඔබ භාවිතා කරයි"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"සැම විටම"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"එක් වාරයයි"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> වැඩ පැතිකඩට සහාය නොදක්වයි"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> අමුණන්න"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> ඇමුණුම ඉවත් කරන්න"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"සංස්කරණය"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + ගොනු #}one{{file_name} + ගොනු #}other{{file_name} + ගොනු #}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ගොනුවක්}one{ගොනු + #}other{ගොනු + #}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"පෙළ බෙදා ගැනීම"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"සබැඳිය බෙදා ගැනීම"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{රූපය බෙදා ගැනීම}one{රූප #ක් බෙදා ගැනීම}other{රූප #ක් බෙදා ගැනීම}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{වීඩියෝව බෙදා ගැනීම}one{වීඩියෝ #ක් බෙදා ගැනීම}other{වීඩියෝ #ක් බෙදා ගැනීම}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# අයිතමයක් බෙදා ගැනීම}one{අයිතම #ක් බෙදා ගැනීම}other{අයිතම #ක් බෙදා ගැනීම}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"පෙළ සමග රූපය බෙදා ගැනීම"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"සබැඳිය සමග රූපය බෙදාගැනීම"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"බෙදා ගැනීමට නිර්දේශිත පුද්ගලයන් නැත"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"යෙදුම් ලැයිස්තුව"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"මෙම යෙදුමට පටිගත කිරීම් අවසරයක් ලබා දී නොමැති නමුත් මෙම USB උපාංගය හරහා ශ්‍රව්‍ය ග්‍රහණය කර ගත හැකිය."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"පුද්ගලික"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"කාර්යාල"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"පෞද්ගලික දසුන"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"කාර්යාල දසුන"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"ඔබගේ IT පරිපාලක විසින් අවහිර කර ඇත"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"මෙම අන්තර්ගතය කාර්යාල යෙදුම් සමඟ බෙදා ගත නොහැකිය"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"මෙම අන්තර්ගතය කාර්යාල යෙදුම් සමඟ විවෘත කළ නොහැකිය"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"මෙම අන්තර්ගතය පුද්ගලික යෙදුම් සමඟ බෙදා ගත නොහැකිය"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"මෙම අන්තර්ගතය පුද්ගලික යෙදුම් සමඟ විවෘත කළ නොහැකිය"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"කාර්යාල පැතිකඩ විරාම කර ඇත"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ක්‍රියාත්මක කිරීමට තට්ටු කරන්න"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"කාර්යාල යෙදුම් නැත"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"පුද්ගලික යෙදුම් නැත"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g> ඔබගේ පුද්ගලික පැතිකඩ තුළ විවෘත කරන්නද?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g> ඔබගේ කාර්යාල පැතිකඩ තුළ විවෘත කරන්නද?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"පුද්ගලික බ්‍රව්සරය භාවිත කරන්න"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"කාර්යාල බ්‍රව්සරය භාවිත කරන්න"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"පාඨය බැහැර කරන්න"</string>
+ <string name="include_text" msgid="642280283268536140">"පාඨය ඇතළත් කරන්න"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"සබැඳිය බැහැර කරන්න"</string>
+ <string name="include_link" msgid="827855767220339802">"සබැඳිය ඇතුළත් කරන්න"</string>
+</resources>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
new file mode 100644
index 00000000..7e96d4ad
--- /dev/null
+++ b/java/res/values-sk/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Dokončiť akciu pomocou aplikácie"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Dokončite akciu pomocou aplikácie <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Dokončiť akciu"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Otvoriť v aplikácii"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Otvorte pomocou aplikácie <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Otvoriť"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Otvárať odkazy <xliff:g id="HOST">%1$s</xliff:g> v aplikácii"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Otvárať odkazy v aplikácii"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Otvárať odkazy v aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Otvárať odkazy <xliff:g id="HOST">%1$s</xliff:g> v aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Udeliť prístup"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Upraviť pomocou"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Upravte pomocou aplikácie <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Upraviť"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Zdieľať"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Zdieľajte s aplikáciou <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Zdieľať"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Odoslať pomocou aplikácie"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Odošlite pomocou aplikácie <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Odoslať"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Výber vstupnej aplikácie"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Používajte <xliff:g id="APP">%1$s</xliff:g> ako domovskú aplikáciu"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Nasnímať fotografiu"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Nasnímať fotografiu pomocou aplikácie"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Odfoťte obrázok pomocou aplikácie <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Nasnímať fotografiu"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Použiť inú aplikáciu"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Zvoľte akciu"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Túto akciu nemôžu vykonávať žiadne aplikácie."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Túto aplikáciu používate mimo svojho pracovného profilu"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Túto aplikáciu používate vo svojom pracovnom profile"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Vždy"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Len raz"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> nepodporuje pracovný profil"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Pripnúť aplikáciu <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Odopnúť <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Upraviť"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # súbor}few{{file_name} + # súbory}many{{file_name} + # files}other{{file_name} + # súborov}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # súbor}few{+ # súbory}many{+ # files}other{+ # súborov}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Zdieľa sa textová správa"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Zdieľa sa odkaz"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Zdieľa sa obrázok}few{Zdieľajú sa # obrázky}many{Sharing # images}other{Zdieľa sa # obrázkov}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Zdieľa sa video}few{Zdieľajú sa # videá}many{Sharing # videos}other{Zdieľa sa # videí}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Zdieľa sa # položka}few{Zdieľajú sa # položky}many{Sharing # items}other{Zdieľa sa # položiek}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Zdieľa sa obr. s textom"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Zdieľa sa obr. s odkazom"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Žiadni odporúčaní príjemcovia"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Zoznam aplikácií"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Tejto aplikácii nebolo udelené povolenie na nahrávanie, ale môže nasnímať zvuk cez toto zariadenie USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Osobné"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Práca"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Osobné zobrazenie"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Pracovné zobrazenie"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blokované vaším správcom IT"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Tento obsah sa nedá zdieľať pomocou pracovných aplikácií"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Tento obsah sa nedá otvoriť pomocou pracovných aplikácií"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Tento obsah sa nedá zdieľať pomocou osobných aplikácií"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Tento obsah sa nedá otvoriť pomocou osobných aplikácií"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Pracovný profil je pozastavený"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Zapnúť klepnutím"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Žiadne pracovné aplikácie"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Žiadne osobné aplikácie"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Chcete otvoriť <xliff:g id="APP">%s</xliff:g> v osobnom profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Chcete otvoriť <xliff:g id="APP">%s</xliff:g> v pracovnom profile?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Použiť osobný prehliadač"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Použiť pracovný prehliadač"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Vylúčiť text"</string>
+ <string name="include_text" msgid="642280283268536140">"Zahrnúť text"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Vylúčiť odkaz"</string>
+ <string name="include_link" msgid="827855767220339802">"Zahrnúť odkaz"</string>
+</resources>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
new file mode 100644
index 00000000..b2aabdd0
--- /dev/null
+++ b/java/res/values-sl/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Dokončanje dejanja z aplikacijo"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Dokončanje dejanja z aplikacijo <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Izvedba dejanja"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Odpiranje z aplikacijo"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Odpiranje z aplikacijo <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Odpiranje"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z aplikacijo"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Odpiranje povezav z"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Odpiranje povezav z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Omogoči dostop"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Urejanje z aplikacijo"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Urejanje z aplikacijo <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Urejanje"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Deljenje z drugimi"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Deljenje z drugimi prek aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Deljenje"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Pošiljanje z aplikacijo"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Pošiljanje z aplikacijo <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Pošiljanje"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Izbira aplikacije na začetnem zaslonu"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Uporaba aplikacije <xliff:g id="APP">%1$s</xliff:g> kot domače aplikacije"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Snemanje slike"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Snemanje slike z aplikacijo"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Snemanje slike z aplikacijo <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Snemanje slike"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Uporaba druge aplikacije"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Izberite dejanje"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Tega dejanja ne more izvesti nobena aplikacija."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Aplikacijo uporabljate zunaj delovnega profila"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"To aplikacijo uporabljate v delovnem profilu"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Vedno"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Samo tokrat"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> ne podpira delovnega profila"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Pripni aplikacijo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Odpni aplikacijo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Uredi"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # datoteka}one{{file_name} + # datoteka}two{{file_name} + # datoteki}few{{file_name} + # datoteke}other{{file_name} + # datotek}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # datoteka}one{+ # datoteka}two{+ # datoteki}few{+ # datoteke}other{+ # datotek}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Deljenje besedila"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Deljenje povezave"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Deljenje slike}one{Deljenje # slike}two{Deljenje # slik}few{Deljenje # slik}other{Deljenje # slik}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Deljenje videoposnetka}one{Deljenje # videoposnetka}two{Deljenje # videoposnetkov}few{Deljenje # videoposnetkov}other{Deljenje # videoposnetkov}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Deljenje # elementa}one{Deljenje # elementa}two{Deljenje # elementov}few{Deljenje # elementov}other{Deljenje # elementov}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Deljenje slike z besedilom"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Deljenje slike s povezavo"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Ni priporočenih oseb za deljenje vsebine."</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Seznam aplikacij"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Ta aplikacija sicer nima dovoljenja za snemanje, vendar bi lahko zajemala zvok prek te naprave USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Osebno"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Služba"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Pogled osebnega profila"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Pogled delovnega profila"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blokiral skrbnik za IT"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Te vsebine ni mogoče deliti z delovnimi aplikacijami."</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Te vsebine ni mogoče odpreti z delovnimi aplikacijami."</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Te vsebine ni mogoče deliti z osebnimi aplikacijami."</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Te vsebine ni mogoče odpreti z osebnimi aplikacijami."</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Delovni profil je začasno zaustavljen"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Dotaknite se za vklop"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Nobena delovna aplikacija ni na voljo"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Nobena osebna aplikacija"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Želite aplikacijo <xliff:g id="APP">%s</xliff:g> odpreti v osebnem profilu?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Želite aplikacijo <xliff:g id="APP">%s</xliff:g> odpreti v delovnem profilu?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Uporabi osebni brskalnik"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Uporabi delovni brskalnik"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Izloči besedilo"</string>
+ <string name="include_text" msgid="642280283268536140">"Vključi besedilo"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Izloči povezavo"</string>
+ <string name="include_link" msgid="827855767220339802">"Vključi povezavo"</string>
+</resources>
diff --git a/java/res/values-sq/strings.xml b/java/res/values-sq/strings.xml
new file mode 100644
index 00000000..37fb755f
--- /dev/null
+++ b/java/res/values-sq/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Përfundo veprimin duke përdorur"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Përfundo veprimin duke përdorur <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Përfundo veprimin"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Hap me"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Hap me <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Hap"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Hapi lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Hapi lidhjet me"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Hapi lidhjet me <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Hapi lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Jep qasje"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Redakto me"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Modifiko me <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Redakto"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Ndaj"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Shpërndaj me <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Ndaj"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Dërgo me"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Dërgo duke përdorur <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Dërgo"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Përzgjidh një aplikacion nga ekrani bazë"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Përdor <xliff:g id="APP">%1$s</xliff:g> si ekran bazë"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Regjistro imazhin"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Regjistro imazhin me"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Regjistro imazhin me <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Regjistro imazhin"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Përdor një aplikacion tjetër"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Zgjidh një veprim"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Asnjë aplikacion nuk mund ta kryejë këtë veprim."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Po e përdor këtë aplikacion jashtë profilit tënd të punës"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Këtë aplikacion po e përdor në profilin tënd të punës"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Gjithmonë"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Vetëm një herë"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> nuk mbështet profilin e punës"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Gozhdo \"<xliff:g id="LABEL">%1$s</xliff:g>\""</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Zhgozhdoje <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Modifiko"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # skedar}other{{file_name} + # skedarë}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # skedar}other{+ # skedarë}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Po ndahet teksti"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Po ndahet lidhja"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Po ndahet imazh}other{Po ndahen # imazhe}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Po ndahet videoja}other{Po ndahen # video}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Po ndahet # artikull}other{Po ndahen # artikuj}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Po ndahet imazh me tekst"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Po ndahet imazh me lidhje"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Nuk ka persona të rekomanduar për ta ndarë"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Lista e aplikacioneve"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Këtij aplikacioni nuk i është dhënë leje për regjistrim, por mund të regjistrojë audio përmes kësaj pajisjeje USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Puna"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Pamja personale"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Pamja e punës"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Bllokuar nga administratori yt i teknologjisë së informacionit"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Kjo përmbajtje nuk mund të shpërndahet me aplikacione pune"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Kjo përmbajtje nuk mund të hapet me aplikacione pune"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Kjo përmbajtje nuk mund të shpërndahet me aplikacione personale"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Kjo përmbajtje nuk mund të hapet me aplikacione personale"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Profili i punës është në pauzë"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Trokit për ta aktivizuar"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Nuk ka aplikacione pune"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Nuk ka aplikacione personale"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Të hapet <xliff:g id="APP">%s</xliff:g> në profilin tënd personal?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Të hapet <xliff:g id="APP">%s</xliff:g> në profilin tënd të punës?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Përdor shfletuesin personal"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Përdor shfletuesin e punës"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Përjashto tekstin"</string>
+ <string name="include_text" msgid="642280283268536140">"Përfshi tekstin"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Përjashto lidhjen"</string>
+ <string name="include_link" msgid="827855767220339802">"Përfshi lidhjen"</string>
+</resources>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
new file mode 100644
index 00000000..fb881642
--- /dev/null
+++ b/java/res/values-sr/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Доврши радњу преко"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Довршите радњу помоћу апликације <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Заврши радњу"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Отворите помоћу"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Отворите помоћу апликације <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Отвори"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Отварајте <xliff:g id="HOST">%1$s</xliff:g> линкове помоћу"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Отварај линкове помоћу"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Отварајте линкове помоћу апликације <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Отварајте <xliff:g id="HOST">%1$s</xliff:g> линкове помоћу апликације <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Дозволи приступ"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Измените помоћу"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Измените помоћу апликације <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Измени"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Делите"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Делите помоћу апликације <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Дели"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Пошаљите помоћу:"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Пошаљите помоћу апликације <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Пошаљи"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Изаберите апликацију за почетну страницу"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Користите <xliff:g id="APP">%1$s</xliff:g> за почетну"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Снимите слику"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Снимите слику помоћу апликације"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Снимите слику помоћу апликације <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Снимите слику"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Користите другу апликацију"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Одаберите радњу"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Ниједна апликација не може да обавља ову радњу."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Користите ову апликацију изван пословног профила"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Користите ову апликацију на пословном профилу"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Увек"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Само једном"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> не подржава пословни профил"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Закачите особу <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Откачи апликацију <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Измени"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # фајл}one{{file_name} + # фајл}few{{file_name} + # фајла}other{{file_name} + # фајлова}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{и још # фајл}one{и још # фајл}few{и још # фајла}other{и још # фајлова}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Дели се текст"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Дели се линк"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Дели се слика}one{Дели се # слика}few{Деле се # слике}other{Дели се # слика}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Дели се видео}one{Дели се # видео}few{Деле се # видео снимка}other{Дели се # видео снимака}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Дели се # ставка}one{Дели се # ставка}few{Деле се # ставке}other{Дели се # ставки}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Дели се слика са текстом"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Дели се слика са линком"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Нема препоручених људи за дељење"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Листа апликација"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Ова апликација нема дозволу за снимање, али би могла да снима звук помоћу овог USB уређаја."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Лично"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Пословно"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Лични приказ"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Приказ за посао"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Блокира ИТ администратор"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Овај садржај не може да се дели помоћу пословних апликација"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Овај садржај не може да се отвара помоћу пословних апликација"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Овај садржај не може да се дели помоћу личних апликација"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Овај садржај не може да се отвара помоћу личних апликација"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Пословни профил је паузиран"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Додирните да бисте укључили"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Нема пословних апликација"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Нема личних апликација"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Желите да на личном профилу отворите: <xliff:g id="APP">%s</xliff:g>?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Желите да на пословном профилу отворите: <xliff:g id="APP">%s</xliff:g>?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Користи лични прегледач"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Користи пословни прегледач"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Искључи текст"</string>
+ <string name="include_text" msgid="642280283268536140">"Уврсти текст"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Искључи линк"</string>
+ <string name="include_link" msgid="827855767220339802">"Уврсти линк"</string>
+</resources>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
new file mode 100644
index 00000000..37c7f685
--- /dev/null
+++ b/java/res/values-sv/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Slutför åtgärd med"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Slutför åtgärd med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Slutför åtgärd"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Öppna med"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Öppna med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Öppna"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Öppna länkar på <xliff:g id="HOST">%1$s</xliff:g> med"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Öppna länkar med"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Öppna länkar med <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Öppna länkar på <xliff:g id="HOST">%1$s</xliff:g> med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Ge åtkomst"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Redigera med"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Redigera med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Redigera"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Dela"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Dela med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Dela"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Skicka med"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Skicka via <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Skicka"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Välj en startsidesapp"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Använd <xliff:g id="APP">%1$s</xliff:g> som startsida"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Ta bild"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Ta bild med"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Ta bild med <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Ta bild"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Använd en annan app"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Välj en åtgärd"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Inga appar kan utföra den här åtgärden."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Du använder den här appen i din jobbprofil"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Du använder den här appen i din jobbprofil"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Alltid"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Bara en gång"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> har inte stöd för jobbprofiler"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Fäst <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Lossa <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Redigera"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # fil}other{{file_name} + # filer}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # fil}other{+ # filer}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Delar text"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Delar länk"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Delar bild}other{Delar # bilder}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Delar video}other{Delar # videor}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Delar # objekt}other{Delar # objekt}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Delar bild med text"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Delar bild med länk"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Inga rekommenderade personer att dela med"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Applista"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Appen har inte fått inspelningsbehörighet men kan spela in ljud via denna USB-enhet."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Privat"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Jobb"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Personlig vy"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Jobbvy"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Blockeras av IT-administratören"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Det här innehållet kan inte delas med jobbappar"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Det här innehållet kan inte öppnas med jobbappar"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Det här innehållet kan inte delas med privata appar"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Det här innehållet kan inte öppnas med privata appar"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Jobbprofilen är pausad"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Tryck för att aktivera"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Inga jobbappar"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Inga privata appar"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Vill du öppna <xliff:g id="APP">%s</xliff:g> i din privata profil?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Vill du öppna <xliff:g id="APP">%s</xliff:g> i din jobbprofil?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Använd privat webbläsare"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Använd jobbwebbläsare"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Uteslut text"</string>
+ <string name="include_text" msgid="642280283268536140">"Inkludera text"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Uteslut länk"</string>
+ <string name="include_link" msgid="827855767220339802">"Inkludera länk"</string>
+</resources>
diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml
new file mode 100644
index 00000000..f8aa1ea3
--- /dev/null
+++ b/java/res/values-sw/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Kamilisha kitendo ukitumia"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Kamilisha kitendo ukitumia <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Kamilisha kitendo"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Fungua ukitumia"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Fungua ukitumia <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Fungua"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Fungua viungo vya <xliff:g id="HOST">%1$s</xliff:g> ukitumia"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Fungua viungo ukitumia"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Fungua viungo ukitumia <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Fungua viungo vya <xliff:g id="HOST">%1$s</xliff:g> ukitumia <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Ruhusu ufikiaji"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Badilisha kwa"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Badilisha ukitumia <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Badilisha"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Shiriki"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Shiriki ukitumia <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Shiriki"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Tuma kwa kutumia"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Tuma ukitumia <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Tuma"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Chagua programu ya Mwanzo"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Tumia <xliff:g id="APP">%1$s</xliff:g> kuwa Skrini ya kwanza"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Piga picha"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Piga picha ukitumia"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Piga picha ukitumia <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Piga picha"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Tumia programu tofauti"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Chagua kitendo"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Hakuna programu zinazoweza kufanya tendo hili."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Unatumia programu hii nje ya wasifu wako wa kazini"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Unatumia programu hii kwenye wasifu wako wa kazini"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Kila mara"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Mara moja tu"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> haitumii wasifu wa kazini"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Bandika <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Bandua <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Badilisha"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + faili #}other{{file_name} + faili #}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ faili #}other{+ faili #}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Inashiriki maandishi"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Inashiriki kiungo"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Inashiriki picha}other{Inashiriki picha #}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Inashiriki video}other{Inashiriki video #}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Inashiriki kipengee #}other{Inashiriki vipengee #}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Inashiriki picha na maandishi"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Inashiriki picha na kiungo"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Hujapendekezewa watu wa kushiriki nao"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Orodha ya programu"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Programu hii haijapewa ruhusa ya kurekodi lakini inaweza kurekodi sauti kupitia kifaa hiki cha USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Binafsi"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Kazini"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Mwonekano wa binafsi"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Mwonekano wa kazini"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Imezuiwa na msimamizi wako wa Tehama"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Huwezi kushiriki maudhui haya na programu za kazini"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Huwezi kufungua maudhui haya ukitumia programu za kazini"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Huwezi kushiriki maudhui haya na programu za binafsi"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Huwezi kufungua maudhui haya ukitumia programu za binafsi"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Wasifu wa kazini umesimamishwa"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Gusa ili uwashe"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Hakuna programu za kazini"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Hakuna programu za binafsi"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Je, unataka kufungua <xliff:g id="APP">%s</xliff:g> katika wasifu wako binafsi?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Je, unataka kufungua <xliff:g id="APP">%s</xliff:g> katika wasifu wako wa kazi?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Tumia kivinjari cha binafsi"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Tumia kivinjari cha kazini"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Usijumuishe maandishi"</string>
+ <string name="include_text" msgid="642280283268536140">"Jumuisha maandishi"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Usijumuishe kiungo"</string>
+ <string name="include_link" msgid="827855767220339802">"Jumuisha kiungo"</string>
+</resources>
diff --git a/java/res/values-sw600dp/dimens.xml b/java/res/values-sw600dp/dimens.xml
index b397630e..240ee067 100644
--- a/java/res/values-sw600dp/dimens.xml
+++ b/java/res/values-sw600dp/dimens.xml
@@ -18,7 +18,6 @@
*/
-->
<resources>
-
<dimen name="chooser_width">624dp</dimen>
-
+ <dimen name="modify_share_text_toggle_max_width">250dp</dimen>
</resources>
diff --git a/java/res/values-ta/strings.xml b/java/res/values-ta/strings.xml
new file mode 100644
index 00000000..da13e7d1
--- /dev/null
+++ b/java/res/values-ta/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"இதைப் பயன்படுத்தி செயலை நிறைவுசெய்"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸைப் பயன்படுத்தி செயலை நிறைவுசெய்யுங்கள்"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"செயலை முடி"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"இதன்மூலம் திற"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸ் மூலம் திறங்கள்"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"திற"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> இணைப்புகளை இதன் மூலம் திற:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"இணைப்புகளை இதன் மூலம் திற:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"இணைப்புகளை <xliff:g id="APPLICATION">%1$s</xliff:g> ஆப்ஸில் திறத்தல்"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> இணைப்புகளை <xliff:g id="APPLICATION">%2$s</xliff:g> ஆப்ஸில் திறத்தல்"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"அணுகல் வழங்கு"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"இதன் மூலம் திருத்து"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸ் மூலம் மாற்றுங்கள்"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"மாற்று"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"பகிர்"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸ் மூலம் பகிருங்கள்"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"பகிர்"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"இதைப் பயன்படுத்தி அனுப்பு:"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸைப் பயன்படுத்தி அனுப்புங்கள்"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"அனுப்பு"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"முகப்புப் பயன்பாட்டைத் தேர்வுசெய்க"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸை முகப்பாகப் பயன்படுத்துங்கள்"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"படமெடு"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"இதன் மூலம் படமெடு:"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸ் மூலம் படமெடுங்கள்"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"படமெடு"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"வேறு ஆப்ஸைப் பயன்படுத்தவும்"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"ஒரு செயலைத் தேர்ந்தெடுங்கள்"</string>
+ <string name="noApplications" msgid="1139487441772284671">"இந்தச் செயலைச் செய்ய ஆப்ஸ் எதுவுமில்லை."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"இந்தப் பயன்பாட்டைப் பணிக் கணக்கிற்கு வெளியே பயன்படுத்துகிறீர்கள்"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"பணிக் கணக்கில் பயன்பாட்டைப் பயன்படுத்துகிறீர்கள்"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"எப்போதும்"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"இப்போது மட்டும்"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ஆப்ஸில் பணிக் கணக்கைப் பயன்படுத்த முடியாது"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> ஆப்ஸைப் பின் செய்"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> ஐப் பின் நீக்கு"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"திருத்து"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ஃபைல்}other{{file_name} + # ஃபைல்கள்}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ஃபைல்}other{+ # ஃபைல்கள்}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"உரையைப் பகிர்கிறது"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"பகிர்வதற்கான இணைப்பு"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{படத்தைப் பகிர்கிறது}other{# படங்களைப் பகிர்கிறது}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{வீடியோவைப் பகிர்கிறது}other{# வீடியோக்களை பகிர்கிறது}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# ஃபைலைப் பகிர்கிறது}other{# ஃபைல்களைப் பகிர்கிறது}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"உரையுடன் படம் பகிர்தல்"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"இணைப்புடன் படம் பகிர்தல்"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"பகிர்வதற்கு எவரும் பரிந்துரைக்கப்படவில்லை"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"ஆப்ஸ் பட்டியல்"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"இந்த ஆப்ஸிற்கு ரெக்கார்டு செய்வதற்கான அனுமதி வழங்கப்படவில்லை, எனினும் இந்த USB சாதனம் மூலம் ஆடியோவைப் பதிவுசெய்ய முடியும்."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"தனிப்பட்ட சுயவிவரம்"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"பணிச் சுயவிவரம்"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"தனிப்பட்ட காட்சி"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"பணிக் காட்சி"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"இதை உங்கள் IT நிர்வாகி தடைசெய்துள்ளார்"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"பணி ஆப்ஸுடன் இந்த உள்ளடக்கத்தைப் பகிர முடியாது"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"பணி ஆப்ஸ் மூலம் இந்த உள்ளடக்கத்தைத் திறக்க முடியாது"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"தனிப்பட்ட ஆப்ஸுடன் இந்த உள்ளடக்கத்தைப் பகிர முடியாது"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"தனிப்பட்ட ஆப்ஸ் மூலம் இந்த உள்ளடக்கத்தைத் திறக்க முடியாது"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"பணிக் கணக்கு இடைநிறுத்தப்பட்டுள்ளது"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ஆன் செய்யத் தட்டுக"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"பணி ஆப்ஸ் எதுவுமில்லை"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"தனிப்பட்ட ஆப்ஸ் எதுவுமில்லை"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"உங்கள் தனிப்பட்ட கணக்கில் <xliff:g id="APP">%s</xliff:g> ஆப்ஸைத் திறக்கவா?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"உங்கள் பணிக் கணக்கில் <xliff:g id="APP">%s</xliff:g> ஆப்ஸைத் திறக்கவா?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"தனிப்பட்ட உலாவியைப் பயன்படுத்து"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"பணி உலாவியைப் பயன்படுத்து"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"வார்த்தைகளைத் தவிர்"</string>
+ <string name="include_text" msgid="642280283268536140">"வார்த்தைகளைச் சேர்"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"இணைப்பைத் தவிர்"</string>
+ <string name="include_link" msgid="827855767220339802">"இணைப்பைச் சேர்"</string>
+</resources>
diff --git a/java/res/values-te/strings.xml b/java/res/values-te/strings.xml
new file mode 100644
index 00000000..7f430eb7
--- /dev/null
+++ b/java/res/values-te/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"దీన్ని ఉపయోగించి చర్యను పూర్తి చేయండి"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> యాప్‌ను ఉపయోగించి చర్యను పూర్తి చేయండి"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"చర్యను పూర్తి చేయి"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"దీనితో తెరువు"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> యాప్‌తో తెరవండి"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"తెరువు"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"దీనితో <xliff:g id="HOST">%1$s</xliff:g> లింక్‌లను తెరవండి"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"దీనితో లింక్‌లను తెరవండి"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g>తో లింక్‌లను తెరవండి"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> లింక్‌లను <xliff:g id="APPLICATION">%2$s</xliff:g>తో తెరవండి"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"యాక్సెస్ ఇవ్వండి"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"దీనితో ఎడిట్ చేయండి"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> యాప్‌తో ఎడిట్ చేయండి"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"ఎడిట్"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"షేర్ చేయండి"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> యాప్‌తో షేర్ చేయండి"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"షేర్ చేయి"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"దీన్ని ఉపయోగించి పంపండి"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> యాప్‌ను ఉపయోగించి పంపండి"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"పంపు"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"హోమ్ యాప్‌ను ఎంచుకోండి"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> యాప్‌ను హోమ్ పేజీగా ఉపయోగించండి"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"చిత్రాన్ని క్యాప్చర్ చేయి"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"దీనితో చిత్రాన్ని క్యాప్చర్ చేయి"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> యాప్‌తో ఇమేజ్‌ను క్యాప్చర్ చేయండి"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"చిత్రాన్ని క్యాప్చర్ చేయి"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"వేరొక యాప్‌ను ఉపయోగించండి"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"చర్యను ఎంచుకోండి"</string>
+ <string name="noApplications" msgid="1139487441772284671">"ఈ చర్యను అమలు చేయగల యాప్‌లు ఏవీ లేవు."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"మీరు మీ కార్యాలయ ప్రొఫైల్‌కు వెలుపల ఈ యాప్‌ను ఉపయోగిస్తున్నారు"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"మీరు మీ కార్యాలయ ప్రొఫైల్‌లో ఈ యాప్‌ను ఉపయోగిస్తున్నారు"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"ఎల్లప్పుడూ"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"ఒకసారి మాత్రమే"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> యాప్ వర్క్ ప్రొఫైల్‌కు సపోర్ట్ చేయదు"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g>‌ను పిన్ చేయండి"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g>ను అన్‌పిన్ చేయి"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"ఎడిట్ చేయండి"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ఫైల్}other{{file_name} + # ఫైల్స్}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ఫైల్}other{+ # ఫైల్స్}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"టెక్స్ట్‌ను షేర్ చేయడం"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"లింక్‌ను షేర్ చేయడం"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{ఇమేజ్‌ను షేర్ చేయడం}other{# ఇమేజ్‌లను షేర్ చేయడం}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{వీడియోను షేర్ చేయడం}other{# వీడియోలను షేర్ చేయడం}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# ఐటెమ్‌ను షేర్ చేయడం}other{# ఐటెమ్‌లను షేర్ చేయడం}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"టెక్స్ట్‌తో ఇమేజ్‌ను షేర్ చేయడం"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"లింక్‌తో ఇమేజ్‌ను షేర్ చేయడం"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"ఎవరికి షేర్ చేయాలనే దానికి సంబంధించి సిఫార్సులేవీ లేవు"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"యాప్‌ల లిస్ట్‌"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"ఈ యాప్‌కు రికార్డ్ చేసే అనుమతి మంజూరు కాలేదు, అయినా ఈ USB పరికరం ద్వారా ఆడియోను క్యాప్చర్ చేయగలదు."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"వ్యక్తిగతం"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"ఆఫీస్"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"వ్యక్తిగత వీక్షణ"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"పని వీక్షణ"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"మీ IT అడ్మిన్ ద్వారా బ్లాక్ చేయబడింది"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"ఈ కంటెంట్ వర్క్ యాప్‌తో షేర్ చేయడం సాధ్యం కాదు"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"ఈ కంటెంట్ వర్క్ యాప్‌తో తెరవడం సాధ్యం కాదు"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"ఈ కంటెంట్ వ్యక్తిగత యాప్‌తో షేర్ చేయడం సాధ్యం కాదు"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"ఈ కంటెంట్ వ్యక్తిగత యాప్‌తో తెరవడం సాధ్యం కాదు"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"వర్క్ ప్రొఫైల్ పాజ్ చేయబడింది"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"ఆన్ చేయడానికి ట్యాప్ చేయండి"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"వర్క్ యాప్‌లు లేవు"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"వ్యక్తిగత యాప్‌లు లేవు"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g>ను మీ వ్యక్తిగత ప్రొఫైల్‌లో తెరవాలా?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g>ను మీ వర్క్ ప్రొఫైల్‌లో తెరవాలా?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"వ్యక్తిగత బ్రౌజర్‌ను ఉపయోగించండి"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"వర్క్ బ్రౌజర్‌ను ఉపయోగించండి"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"టెక్స్ట్‌ను మినహాయించండి"</string>
+ <string name="include_text" msgid="642280283268536140">"టెక్స్ట్‌ను చేర్చండి"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"లింక్‌ను మినహాయించండి"</string>
+ <string name="include_link" msgid="827855767220339802">"లింక్‌ను చేర్చండి"</string>
+</resources>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
new file mode 100644
index 00000000..70519849
--- /dev/null
+++ b/java/res/values-th/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"ทำงานให้เสร็จโดยใช้"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"ดำเนินการให้เสร็จสิ้นโดยใช้ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"ทำงานให้เสร็จสิ้น"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"เปิดด้วย"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"เปิดด้วย <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"เปิด"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"เปิดลิงก์ <xliff:g id="HOST">%1$s</xliff:g> ด้วย"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"เปิดลิงก์ด้วย"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"เปิดลิงก์ด้วย <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"เปิดลิงก์ <xliff:g id="HOST">%1$s</xliff:g> ด้วย <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"ให้สิทธิ์เข้าถึง"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"แก้ไขด้วย"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"แก้ไขด้วย <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"แก้ไข"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"แชร์"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"แชร์ด้วย <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"แชร์"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"ส่งโดยใช้"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"ส่งโดยใช้ <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"ส่ง"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"เลือกแอปหน้าแรก"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"ใช้ <xliff:g id="APP">%1$s</xliff:g> เป็นหน้าแรก"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"จับภาพ"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"จับภาพด้วย"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"จับภาพด้วย <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"จับภาพ"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"ใช้แอปอื่น"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"เลือกการดำเนินการ"</string>
+ <string name="noApplications" msgid="1139487441772284671">"ไม่มีแอปพลิเคชันใดทำงานนี้ได้"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"คุณกำลังใช้แอปนี้นอกโปรไฟล์งานของคุณ"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"คุณกำลังใช้แอปนี้ในโปรไฟล์งานของคุณ"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"ทุกครั้ง"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"เฉพาะครั้งนี้"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ไม่รองรับโปรไฟล์งาน"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"ปักหมุด <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"เลิกปักหมุด <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"แก้ไข"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ไฟล์}other{{file_name} + # ไฟล์}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{อีก # ไฟล์}other{อีก # ไฟล์}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"กำลังแชร์ข้อความ"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"กำลังแชร์ลิงก์"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{กำลังแชร์รูปภาพ}other{กำลังแชร์รูปภาพ # รายการ}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{กำลังแชร์วิดีโอ}other{กำลังแชร์วิดีโอ # รายการ}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{กำลังแชร์ # รายการ}other{กำลังแชร์ # รายการ}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"กำลังแชร์รูปภาพพร้อมข้อความ"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"กำลังแชร์รูปภาพพร้อมลิงก์"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"ไม่พบใครที่แนะนำให้แชร์ด้วย"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"รายชื่อแอป"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"แอปนี้ไม่ได้รับอนุญาตให้บันทึกเสียงแต่อาจเก็บเสียงผ่านอุปกรณ์ USB นี้ได้"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"ส่วนตัว"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"งาน"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"มุมมองส่วนตัว"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"ดูงาน"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"ผู้ดูแลระบบไอทีบล็อกไว้"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"แชร์เนื้อหานี้โดยใช้แอปงานไม่ได้"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"เปิดเนื้อหานี้โดยใช้แอปงานไม่ได้"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"แชร์เนื้อหานี้โดยใช้แอปส่วนตัวไม่ได้"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"เปิดเนื้อหานี้โดยใช้แอปส่วนตัวไม่ได้"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"โปรไฟล์งานหยุดชั่วคราว"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"แตะเพื่อเปิด"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"ไม่มีแอปงาน"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"ไม่มีแอปส่วนตัว"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"เปิด <xliff:g id="APP">%s</xliff:g> ในโปรไฟล์ส่วนตัวไหม"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"เปิด <xliff:g id="APP">%s</xliff:g> ในโปรไฟล์งานไหม"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"ใช้เบราว์เซอร์ส่วนตัว"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"ใช้เบราว์เซอร์งาน"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"ไม่รวมข้อความ"</string>
+ <string name="include_text" msgid="642280283268536140">"รวมข้อความ"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"ไม่รวมลิงก์"</string>
+ <string name="include_link" msgid="827855767220339802">"รวมลิงก์"</string>
+</resources>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
new file mode 100644
index 00000000..b7c50d4b
--- /dev/null
+++ b/java/res/values-tl/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Kumpletuhin ang pagkilos gamit ang"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Kumpletuhin ang pagkilos gamit ang <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Gawin ang pagkilos"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Buksan gamit ang"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Buksan sa <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Buksan"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> gamit ang"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Buksan ang mga link gamit ang"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Buksan ang mga link gamit ang <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> gamit ang <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Bigyan ng access"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"I-edit gamit ang"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"I-edit sa <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"I-edit"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Ibahagi"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Ibahagi gamit ang <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Ibahagi"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Ipadala gamit ang"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Ipadala gamit ang <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Ipadala"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Pumili ng app sa Home"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Gamitin ang <xliff:g id="APP">%1$s</xliff:g> bilang Home"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Kunan ng larawan"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Kunan ng larawan gamit ang"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"I-capture ang larawan gamit ang <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Kunan ng larawan"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Gumamit ng ibang app"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Pumili ng pagkilos"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Walang apps ang makakapagsagawa ng pagkilos na ito."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Ginagamit mo ang app na ito sa labas ng iyong profile sa trabaho"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Ginagamit mo ang app na ito sa iyong profile sa trabaho"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Palagi"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Isang beses lang"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"Hindi sinusuportahan ng <xliff:g id="APP">%1$s</xliff:g> ang profile sa trabaho"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"I-pin ang <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"I-unpin ang <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"I-edit"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # file}one{{file_name} + # file}other{{file_name} + # na file}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # file}one{+ # file}other{+ # na file}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Ibinabahagi ang text"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Ibinabahagi ang link"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Ibinabahagi ang larawan}one{Ibinabahagi ang # larawan}other{Ibinabahagi ang # na larawan}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Ibinabahagi ang video}one{Ibinabahagi ang # video}other{Ibinabahagi ang # na video}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Ibinabahagi ang # item}one{Ibinabahagi ang # item}other{Ibinabahagi ang # na item}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Larawang may text"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Larawang may link"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Walang inirerekomendang taong mapagbabahagian"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Listahan ng mga app"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Hindi nabigyan ng pahintulot ang app na ito para mag-record pero nakakapag-capture ito ng audio sa pamamagitan ng USB device na ito."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Personal"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Trabaho"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Personal na view"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"View ng trabaho"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Na-block ng iyong IT admin"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Hindi puwedeng ibahagi sa mga app para sa trabaho ang content na ito"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Hindi puwedeng buksan sa mga app para sa trabaho ang content na ito"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Hindi puwedeng ibahagi sa mga personal na app ang content na ito"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Hindi puwedeng buksan sa mga personal na app ang content na ito"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Naka-pause ang profile sa trabaho"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"I-tap para i-on"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Walang app para sa trabaho"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Walang personal na app"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Buksan ang <xliff:g id="APP">%s</xliff:g> sa iyong personal na profile?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Buksan ang <xliff:g id="APP">%s</xliff:g> sa iyong profile sa trabaho?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Gamitin ang personal na browser"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Gamitin ang browser sa trabaho"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Huwag isama ang text"</string>
+ <string name="include_text" msgid="642280283268536140">"Isama ang text"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Huwag isama ang link"</string>
+ <string name="include_link" msgid="827855767220339802">"Isama ang link"</string>
+</resources>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
new file mode 100644
index 00000000..71168718
--- /dev/null
+++ b/java/res/values-tr/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"İşlemi şunu kullanarak tamamla"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"İşlemi <xliff:g id="APP">%1$s</xliff:g> uygulamasını kullanarak tamamla"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"İşlemi tamamla"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Şununla aç:"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> ile açın"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Aç"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> bağlantılarını şununla aç:"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Bağlantıları şununla aç:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Bağlantıları <xliff:g id="APPLICATION">%1$s</xliff:g> ile aç"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> bağlantılarını <xliff:g id="APPLICATION">%2$s</xliff:g> ile aç"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Erişim izni ver"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Şununla düzenle:"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> ile düzenleyin"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Düzenle"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Paylaş"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> ile paylaşın"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Paylaş"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Göndermek için kullanılacak uygulama"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> uygulamasını kullanarak gönderin"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Gönder"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Ana Ekran uygulaması seçin"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> uygulamasını ana ekran olarak kullanın"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Fotoğraf çek"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Fotoğraf çekmek için şu uygulamayı kullan:"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Fotoğraf çekmek için <xliff:g id="APP">%1$s</xliff:g> uygulamasını kullanın"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Fotoğraf çek"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Farklı bir uygulama kullan"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"İşlem seçin"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Bu eylemi hiçbir uygulama gerçekleştiremez."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Bu uygulamayı iş profilinizin dışında kullanıyorsunuz"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Bu uygulamayı iş profilinizde kullanıyorsunuz"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Her zaman"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Yalnızca bir defa"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> iş profilini desteklemiyor"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Şunu sabitle: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> uygulamasının sabitlemesini kaldır"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Düzenle"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # dosya}other{{file_name} + # dosya}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # dosya}other{+ # dosya}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Metin paylaşılıyor"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Bağlantı paylaşılıyor"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Resim paylaşılıyor}other{# resim paylaşılıyor}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Video paylaşılıyor}other{# video paylaşılıyor}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# öğe paylaşılıyor}other{# öğe paylaşılıyor}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Metin ekli resim paylaşılıyor"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Bağlantı ekli resim paylaşılıyor"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Paylaşmak için önerilen kullanıcı yok"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Uygulama listesi"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Bu uygulamaya ses kaydetme izni verilmedi ancak bu USB cihazı üzerinden sesleri yakalayabilir."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Kişisel"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"İş"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Kişisel görünüm"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"İş görünümü"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"BT yöneticiniz tarafından engellendi"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Bu içerik, iş uygulamalarıyla paylaşılamaz"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Bu içerik, iş uygulamalarıyla açılamaz"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Bu içerik, kişisel uygulamalarla paylaşılamaz"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Bu içerik, kişisel uygulamalarla açılamaz"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"İş profili duraklatıldı"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Açmak için dokunun"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"İş uygulaması yok"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Kişisel uygulama yok"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g> uygulaması kişisel profilinizde açılsın mı?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g> uygulaması iş profilinizde açılsın mı?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Kişisel tarayıcıyı kullan"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"İş tarayıcısını kullan"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Metni hariç tut"</string>
+ <string name="include_text" msgid="642280283268536140">"Metni dahil et"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Bağlantıyı hariç tut"</string>
+ <string name="include_link" msgid="827855767220339802">"Bağlantıyı dahil et"</string>
+</resources>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
new file mode 100644
index 00000000..8a744661
--- /dev/null
+++ b/java/res/values-uk/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Що використовувати?"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Завершити дію за допомогою додатка <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Завершити дію"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Відкрити за допомогою"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Відкрити за допомогою додатка <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Відкрити"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Відкривати посилання <xliff:g id="HOST">%1$s</xliff:g> за допомогою"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Відкривати посилання за допомогою"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Відкривати посилання за допомогою додатка <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Відкривати посилання <xliff:g id="HOST">%1$s</xliff:g> за допомогою додатка <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Надати доступ"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Редагувати за допомогою"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Змінити за допомогою додатка <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Редагувати"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Поділитися"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Поділитися через додаток <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Поділитися"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Надіслати через додаток"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Надіслати через додаток <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Надіслати"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Вибрати головний додаток"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Використовувати додаток <xliff:g id="APP">%1$s</xliff:g> як головний екран"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Зробити знімок"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Зробити знімок за допомогою"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Зробити знімок за допомогою додатка <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Зробити знімок"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Використовувати інший додаток"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Виберіть дію"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Жодний додаток не може виконати цю дію."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Ви використовуєте цей додаток за межами робочого профілю"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Ви використовуєте цей додаток у своєму робочому профілі"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Завжди"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Лише цього разу"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"Додаток <xliff:g id="APP">%1$s</xliff:g> не підтримує робочий профіль"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Закріпити додаток <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Відкріпити додаток <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Редагувати"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} і ще # файл}one{{file_name} і ще # файл}few{{file_name} і ще # файли}many{{file_name} і ще # файлів}other{{file_name} і ще # файлу}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{і ще # файл}one{і ще # файл}few{і ще # файли}many{і ще # файлів}other{і ще # файлу}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Надсилається текст"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Надсилається посилання"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Надсилається зображення}one{Надсилається # зображення}few{Надсилаються # зображення}many{Надсилаються # зображень}other{Надсилається # зображення}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Надсилається відео}one{Надсилається # відео}few{Надсилаються # відео}many{Надсилаються # відео}other{Надсилається # відео}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Надсилається # об’єкт}one{Надсилається # об’єкт}few{Надсилаються # об’єкти}many{Надсилаються # об’єктів}other{Надсилається # об’єкта}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Надсил. зображ. з текстом"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Надсил. зображ. з посил."</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Немає рекомендацій про те, з ким поділитися"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Список додатків"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Цей додаток не має дозволу на запис, але він може фіксувати звук через цей USB-пристрій."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Особисте"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Робоче"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Особистий перегляд"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Робочий перегляд"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Заблоковано адміністратором"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Цим контентом не можна ділитися в робочих додатках"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Цей контент не можна відкривати в робочих додатках"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Цим контентом не можна ділитися в особистих додатках"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Цей контент не можна відкривати в особистих додатках"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Робочий профіль призупинено"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Торкніться, щоб увімкнути"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Немає робочих додатків"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Немає особистих додатків"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Відкрити додаток <xliff:g id="APP">%s</xliff:g> в особистому профілі?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Відкрити додаток <xliff:g id="APP">%s</xliff:g> у робочому профілі?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Використати особистий веб-переглядач"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Використати робочий веб-переглядач"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Вилучити текст"</string>
+ <string name="include_text" msgid="642280283268536140">"Додати текст"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Вилучити посилання"</string>
+ <string name="include_link" msgid="827855767220339802">"Додати посилання"</string>
+</resources>
diff --git a/java/res/values-ur/strings.xml b/java/res/values-ur/strings.xml
new file mode 100644
index 00000000..493ffef4
--- /dev/null
+++ b/java/res/values-ur/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"اس کا استعمال کرکے کارروائی مکمل کریں"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> کا استعمال کر کے کاروائی مکمل کریں"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"کارروائی مکمل کریں"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"اس کے ساتھ کھولیں"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> کے ساتھ کھولیں"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"کھولیں"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"‫‫<xliff:g id="HOST">%1$s</xliff:g> لنکس اس کے ساتھ کھولیں"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"اس کے ساتھ لنکس کھولیں"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"<xliff:g id="APPLICATION">%1$s</xliff:g> کے ذریعے لنکس کھولیں"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> لنکس کو <xliff:g id="APPLICATION">%2$s</xliff:g> کے ذریعے کھولیں"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"رسائی دیں"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"اس کے ساتھ ترمیم کریں"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> کے ساتھ ترمیم کریں"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"ترمیم کریں"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"اشتراک کریں"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> کے ساتھ اشتراک کریں"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"اشتراک کریں"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"بھیجیں بذریعہ"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> کا استعمال کر کے بھیجیں"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"بھیجیں"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"‏ایک Home ایپ منتخب کریں"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> کا استعمال بطور"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"تصویر کیپچر کریں"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"اس کے ساتھ تصویر کیپچر کریں"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> کے ساتھ تصویر کیپچر کریں"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"تصویر کیپچر کریں"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"ایک مختلف ایپ استعمال کریں"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"ایک کارروائی منتخب کریں"</string>
+ <string name="noApplications" msgid="1139487441772284671">"کوئی ایپس یہ کارروائی نہیں کر سکتی ہیں۔"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"آپ اس ایپ کا استعمال اپنے دفتری پروفائل کے باہر کر رہے ہیں"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"آپ اس ایپ کو اپنے دفتری پروفائل میں استعمال کر رہے ہیں"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"ہمیشہ"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"بس ایک مرتبہ"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> دفتری پروفائل کا تعاون نہیں کرتی ہے"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"<xliff:g id="LABEL">%1$s</xliff:g> کو پن کریں"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"<xliff:g id="LABEL">%1$s</xliff:g> سے پن ہٹائیں"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"ترمیم کریں"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # فائل}other{{file_name} + # فائلز}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # فائل}other{+ # فائلز}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"ٹیکسٹ کا اشتراک کیا جا رہا ہے"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"لنک کا اشتراک کیا جا رہا ہے"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{تصویر کا اشتراک کیا جا رہا ہے}other{# تصاویر کا اشتراک کیا جا رہا ہے}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{ویڈیو کا اشتراک کیا جا رہا ہے}other{# ویڈیوز کا اشتراک کیا جا رہا ہے}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# آئٹم کا اشتراک کیا جا رہا ہے}other{# آئٹمز کا اشتراک کیا جا رہا ہے}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"ٹیکسٹ کے ساتھ تصویر کا اشتراک کیا جا رہا ہے"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"لنک کے ساتھ تصویر کا اشتراک کیا جا رہا ہے"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"اشتراک کرنے کے لیے کوئی تجویز کردہ لوگ نہیں"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"ایپس کی فہرست"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"‏اس ایپ کو ریکارڈ کرنے کی اجازت عطا نہیں کی گئی ہے مگر اس USB آلہ کے ذریعے آڈیو کیپچر کر سکتی ہے۔"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"ذاتی"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"دفتر"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"ذاتی ملاحظہ"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"دفتری ملاحظہ"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"‏آپ کے IT منتظم کے ذریعے مسدود کردہ"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"اس مواد کا اشتراک ورک ایپس کے ساتھ نہیں کیا جا سکتا"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"اس مواد کو ورک ایپس کے ساتھ نہیں کھولا جا سکتا"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"اس مواد کا اشتراک ذاتی ایپس کے ساتھ نہیں کیا جا سکتا"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"اس مواد کو ذاتی ایپس کے ساتھ نہیں کھولا جا سکتا"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"دفتری پروفائل روک دی گئی ہے"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"آن کرنے کیلئے تھپتھپائیں"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"کوئی ورک ایپ نہیں"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"کوئی ذاتی ایپ نہیں"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"اپنی ذاتی پروفائل میں <xliff:g id="APP">%s</xliff:g> کھولیں؟"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"اپنی دفتری پروفائل میں <xliff:g id="APP">%s</xliff:g> کھولیں؟"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"ذاتی براؤزر استعمال کریں"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"ورک براؤزر استعمال کریں"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"ٹیکسٹ خارج کریں"</string>
+ <string name="include_text" msgid="642280283268536140">"ٹیکسٹ شامل کریں"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"لنک خارج کریں"</string>
+ <string name="include_link" msgid="827855767220339802">"لنک شامل کریں"</string>
+</resources>
diff --git a/java/res/values-uz/strings.xml b/java/res/values-uz/strings.xml
new file mode 100644
index 00000000..2596c7cc
--- /dev/null
+++ b/java/res/values-uz/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Nima ishlatilsin?"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"<xliff:g id="APP">%1$s</xliff:g> orqali amal bajarish"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Amalni bajarish"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Ochish…"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"<xliff:g id="APP">%1$s</xliff:g> orqali ochish"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Ochish"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini quyidagi orqali ochish"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Havolalarni quyidagi orqali ochish"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Havolalarni <xliff:g id="APPLICATION">%1$s</xliff:g> orqali ochish"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini <xliff:g id="APPLICATION">%2$s</xliff:g> orqali ochish"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Ruxsat berish"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Tahrirlash…"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"<xliff:g id="APP">%1$s</xliff:g> orqali tahrirlash"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Tahrirlash"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Ulashish"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"<xliff:g id="APP">%1$s</xliff:g> orqali ulashish"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Ulashish"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Ilovani tanlang"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"<xliff:g id="APP">%1$s</xliff:g> orqali fayl yuborish"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Yuborish"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Bosh ilovani tanlang"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"<xliff:g id="APP">%1$s</xliff:g> bosh ilova boʻlsin"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Suratga olish"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Suratga olish uchun ilovani tanlang:"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"<xliff:g id="APP">%1$s</xliff:g> orqali suratga olish"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Suratga olish"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Boshqa ilova"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Amalni tanlash"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Hech qanday ilova ushbu amalni bajara olmaydi."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Siz ushbu ilovadan ishchi profilingizdan tashqarida foydalanmoqdasiz"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Siz ushbu ilovadan ishchi profilingizda foydalanmoqdasiz"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Har doim"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Faqat shu safar"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> ishchi profilda ishlamaydi"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Mahkamlash: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Yechib olish: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Tahrirlash"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # ta fayl}other{{file_name} + # ta fayl}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # ta fayl}other{+ # ta fayl}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Matn ulashilmoqda"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Havola ulashilmoqda"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Rasm ulashilmoqda}other{# ta rasm ulashilmoqda}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Video ulashilmoqda}other{# ta video ulashilmoqda}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{# ta fayl ulashilmoqda}other{# ta fayl ulashilmoqda}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Matnli havola ulashilmoqda"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Havolali rasm ulashilmoqda"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Ulashish uchun hech kim tavsiya qilinmagan"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Ilovalar roʻyxati"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Bu ilovaga yozib olish ruxsati berilmagan, lekin shu USB orqali ovozlarni yozib olishi mumkin."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Shaxsiy"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Ish"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Shaxsiy rejim"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Ishchi rejim"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Administratoringiz tomonidan bloklangan"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Bu kontent ishga oid ilovalar bilan ulashilmaydi"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Bu kontent ishga oid ilovalar bilan ochilmaydi"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Bu kontent shaxsiy ilovalar bilan ulashilmaydi"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Bu kontent shaxsiy ilovalar bilan ochilmaydi"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Ish profili pauzada"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Yoqish uchun bosing"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Ishga oid ilovalar topilmadi"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Shaxsiy ilovalar topilmadi"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"<xliff:g id="APP">%s</xliff:g> shaxsiy profilda ochilsinmi?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"<xliff:g id="APP">%s</xliff:g> shaxsiy profilda ochilsinmi?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Shaxsiy brauzerdan foydalanish"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Ishga oid brauzerdan foydalanish"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Matnni chiqarib tashlash"</string>
+ <string name="include_text" msgid="642280283268536140">"Matnni kiritish"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Havolani chiqarib tashlash"</string>
+ <string name="include_link" msgid="827855767220339802">"Havolani kiritish"</string>
+</resources>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
new file mode 100644
index 00000000..ed649986
--- /dev/null
+++ b/java/res/values-vi/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Hoàn tất thao tác bằng"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Hoàn tất thao tác bằng <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Hoàn thành tác vụ"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Mở bằng"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Mở bằng <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Mở"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Mở đường liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Mở đường liên kết bằng"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Mở đường liên kết bằng <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Mở đường liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Cấp quyền truy cập"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Chỉnh sửa bằng"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Chỉnh sửa bằng <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Chỉnh sửa"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Chia sẻ"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Chia sẻ qua <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Chia sẻ"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Gửi bằng"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Gửi bằng <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Gửi"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Chọn ứng dụng Home"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Dùng <xliff:g id="APP">%1$s</xliff:g> làm ứng dụng chính"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Chụp ảnh"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Chụp ảnh bằng"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Chụp ảnh bằng <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Chụp ảnh"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Sử dụng một ứng dụng khác"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Chọn một thao tác"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Không ứng dụng nào có thể thực hiện tác vụ này."</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Bạn đang sử dụng ứng dụng này bên ngoài hồ sơ công việc của mình"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Bạn đang sử dụng ứng dụng này trong hồ sơ công việc của mình"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Luôn chọn"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Chỉ một lần"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> không hỗ trợ hồ sơ công việc"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Ghim <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Bỏ ghim <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Chỉnh sửa"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + # tệp}other{{file_name} + # tệp}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{+ # tệp}other{+ # tệp}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Đang chia sẻ văn bản"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Đang chia sẻ liên kết"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Đang chia sẻ hình ảnh}other{Đang chia sẻ # hình ảnh}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Đang chia sẻ video}other{Đang chia sẻ # video}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Đang chia sẻ # mục}other{Đang chia sẻ # mục}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Đang chia sẻ hình ảnh có văn bản"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Đang chia sẻ hình ảnh có liên kết"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Không có gợi ý nào về người mà bạn có thể chia sẻ"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Danh sách ứng dụng"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Ứng dụng này chưa được cấp quyền ghi âm nhưng vẫn có thể ghi âm thông qua thiết bị USB này."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Cá nhân"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Công việc"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Chế độ xem cá nhân"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Chế độ xem công việc"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Bị quản trị viên CNTT chặn"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Bạn không thể chia sẻ nội dung này bằng ứng dụng công việc"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Bạn không thể mở nội dung này bằng ứng dụng công việc"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Bạn không thể chia sẻ nội dung này bằng ứng dụng cá nhân"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Bạn không thể mở nội dung này bằng ứng dụng cá nhân"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Hồ sơ công việc đã bị tạm dừng"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Nhấn để bật"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Không có ứng dụng công việc"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Không có ứng dụng cá nhân"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Mở <xliff:g id="APP">%s</xliff:g> trong hồ sơ cá nhân của bạn?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Mở <xliff:g id="APP">%s</xliff:g> trong hồ sơ công việc của bạn?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Dùng trình duyệt cá nhân"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Dùng trình duyệt công việc"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Loại trừ văn bản"</string>
+ <string name="include_text" msgid="642280283268536140">"Thêm văn bản"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Loại trừ đường liên kết"</string>
+ <string name="include_link" msgid="827855767220339802">"Thêm đường liên kết"</string>
+</resources>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
new file mode 100644
index 00000000..4541bea6
--- /dev/null
+++ b/java/res/values-zh-rCN/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"选择要使用的应用:"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"使用“<xliff:g id="APP">%1$s</xliff:g>”完成操作"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"完成操作"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"打开方式"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"用“<xliff:g id="APP">%1$s</xliff:g>”打开"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"打开"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"<xliff:g id="HOST">%1$s</xliff:g> 链接打开方式"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"链接打开方式"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"使用<xliff:g id="APPLICATION">%1$s</xliff:g>打开链接"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"使用<xliff:g id="APPLICATION">%2$s</xliff:g>打开 <xliff:g id="HOST">%1$s</xliff:g> 链接"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"授予访问权限"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"编辑方式"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"使用“<xliff:g id="APP">%1$s</xliff:g>”编辑"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"编辑"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"分享"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"与“<xliff:g id="APP">%1$s</xliff:g>”分享"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"分享"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"通过以下应用发送"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"通过“<xliff:g id="APP">%1$s</xliff:g>”发送"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"发送"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"选择主屏幕应用"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"将“<xliff:g id="APP">%1$s</xliff:g>”用作主屏幕应用"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"截图"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"使用以下应用截图"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"使用“<xliff:g id="APP">%1$s</xliff:g>”截图"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"截图"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"使用其他应用"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"选择操作"</string>
+ <string name="noApplications" msgid="1139487441772284671">"没有应用可执行此操作。"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"您目前是在工作资料之外使用此应用"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"您目前是在工作资料内使用此应用"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"始终"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"仅此一次"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"“<xliff:g id="APP">%1$s</xliff:g>”不支持工作资料"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"固定<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"取消置顶<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"编辑"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} 以及另外 # 个文件}other{{file_name} 以及另外 # 个文件}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{另外 # 个文件}other{另外 # 个文件}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"正在分享文本"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"正在分享链接"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{正在分享图片}other{正在分享 # 张图片}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{正在分享视频}other{正在分享 # 个视频}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{正在分享 # 个项目}other{正在分享 # 个项目}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"正在分享带有文本的图片"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"正在分享带有链接的图片"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"没有任何推荐的分享对象"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"应用列表"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"此应用未获得录音权限,但能通过此 USB 设备录制音频。"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"个人"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"工作"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"个人视图"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"工作视图"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"已被 IT 管理员禁止"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"无法使用工作应用分享该内容"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"无法使用工作应用打开该内容"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"无法使用个人应用分享该内容"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"无法使用个人应用打开该内容"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"工作资料已被暂停"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"点按即可开启"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"没有支持该内容的工作应用"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"没有支持该内容的个人应用"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"要使用个人资料打开 <xliff:g id="APP">%s</xliff:g> 吗?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"要使用工作资料打开 <xliff:g id="APP">%s</xliff:g> 吗?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"使用个人浏览器"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"使用工作浏览器"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"排除文本"</string>
+ <string name="include_text" msgid="642280283268536140">"包括文本"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"排除链接"</string>
+ <string name="include_link" msgid="827855767220339802">"包括链接"</string>
+</resources>
diff --git a/java/res/values-zh-rHK/strings.xml b/java/res/values-zh-rHK/strings.xml
new file mode 100644
index 00000000..1a5fcc33
--- /dev/null
+++ b/java/res/values-zh-rHK/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"完成操作需使用"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"使用 <xliff:g id="APP">%1$s</xliff:g> 完成操作"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"完成操作"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"選擇開啟方式"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"透過 <xliff:g id="APP">%1$s</xliff:g> 開啟"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"開啟"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結的方式"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"開啟連結的方式"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"使用 <xliff:g id="APPLICATION">%1$s</xliff:g> 開啟連結"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"使用 <xliff:g id="APPLICATION">%2$s</xliff:g> 開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"授予存取權"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"使用以下選擇器編輯:"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"透過 <xliff:g id="APP">%1$s</xliff:g> 編輯"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"編輯"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"分享"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"與 <xliff:g id="APP">%1$s</xliff:g> 分享"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"分享"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"使用以下應用程式傳送:"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"透過 <xliff:g id="APP">%1$s</xliff:g> 傳送"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"傳送"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"選取主螢幕應用程式"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"將 <xliff:g id="APP">%1$s</xliff:g> 用作主畫面應用程式"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"擷取圖片"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"使用以下應用程式擷取圖片:"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"透過 <xliff:g id="APP">%1$s</xliff:g> 擷取圖片"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"擷取圖片"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"使用不同的應用程式"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"選擇一項操作"</string>
+ <string name="noApplications" msgid="1139487441772284671">"沒有應用程式可執行這項操作。"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"您目前並未透過公司檔案使用這個應用程式"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"您目前透過公司檔案使用這個應用程式"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"一律採用"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"只此一次"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"<xliff:g id="APP">%1$s</xliff:g> 不支援工作設定檔"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"固定<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"取消將<xliff:g id="LABEL">%1$s</xliff:g>置頂"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"編輯"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{「{file_name}」和另外 # 個檔案}other{「{file_name}」和另外 # 個檔案}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{和 # 個檔案}other{和 # 個檔案}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"正在分享文字"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"正在分享連結"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{正在分享圖片}other{正在分享 # 張圖片}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{正在分享影片}other{正在分享 # 部影片}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{正在分享 # 個項目}other{正在分享 # 個項目}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"正在分享圖片 (含有文字)"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"正在分享圖片 (含有連結)"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"沒有推薦的分享對象"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"應用程式清單"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"此應用程式尚未獲授予錄音權限,但可透過此 USB 裝置記錄音訊。"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"個人"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"工作"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"個人檢視模式"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"工作檢視模式"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"已被您的 IT 管理員封鎖"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"無法使用工作應用程式分享此內容"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"無法使用工作應用程式開啟此內容"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"無法使用個人應用程式分享此內容"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"無法使用個人應用程式開啟此內容"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"工作設定檔已暫停使用"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"輕按即可啟用"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"沒有適用的工作應用程式"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"沒有適用的個人應用程式"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"要在個人設定檔中開啟「<xliff:g id="APP">%s</xliff:g>」嗎?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"要在工作設定檔中開啟「<xliff:g id="APP">%s</xliff:g>」嗎?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"使用個人瀏覽器"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"使用工作瀏覽器"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"不包括文字"</string>
+ <string name="include_text" msgid="642280283268536140">"加入文字"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"不包括連結"</string>
+ <string name="include_link" msgid="827855767220339802">"加入連結"</string>
+</resources>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
new file mode 100644
index 00000000..29003473
--- /dev/null
+++ b/java/res/values-zh-rTW/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"選擇要使用的應用程式"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"使用「<xliff:g id="APP">%1$s</xliff:g>」完成操作"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"完成操作"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"選擇開啟工具"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"透過「<xliff:g id="APP">%1$s</xliff:g>」開啟"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"開啟"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結時使用的瀏覽器/應用程式"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"開啟連結時使用的瀏覽器"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"使用「<xliff:g id="APPLICATION">%1$s</xliff:g>」開啟連結"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"使用「<xliff:g id="APPLICATION">%2$s</xliff:g>」開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"授予存取權"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"選擇編輯工具"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"透過「<xliff:g id="APP">%1$s</xliff:g>」編輯"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"編輯"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"分享"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"與「<xliff:g id="APP">%1$s</xliff:g>」分享"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"分享"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"透過以下應用程式傳送:"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"透過「<xliff:g id="APP">%1$s</xliff:g>」傳送"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"傳送"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"選取主畫面應用程式"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"將「<xliff:g id="APP">%1$s</xliff:g>」做為主畫面應用程式"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"擷取圖片"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"使用以下應用程式擷取圖片:"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"透過「<xliff:g id="APP">%1$s</xliff:g>」擷取圖片"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"擷取圖片"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"使用其他應用程式"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"選擇一項操作"</string>
+ <string name="noApplications" msgid="1139487441772284671">"沒有應用程式可執行這項操作。"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"你目前並非透過工作資料夾使用這個應用程式"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"你目前透過工作設定檔使用這個應用程式"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"一律採用"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"僅限一次"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"「<xliff:g id="APP">%1$s</xliff:g>」不支援工作資料夾"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"將「<xliff:g id="LABEL">%1$s</xliff:g>」置頂"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"將「<xliff:g id="LABEL">%1$s</xliff:g>」取消固定"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"編輯"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{「{file_name}」和另外 # 個檔案}other{「{file_name}」和另外 # 個檔案}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{和 # 個檔案}other{和 # 個檔案}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"正在分享文字"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"正在分享連結"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{正在分享圖片}other{正在分享 # 張圖片}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{正在分享影片}other{正在分享 # 部影片}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{正在分享 # 個項目}other{正在分享 # 個項目}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"正在分享含有文字的圖片"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"正在分享含有連結的圖片"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"沒有建議的分享對象"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"應用程式清單"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"這個應用程式未取得錄製內容的權限,但可以透過這部 USB 裝置錄製音訊。"</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"個人"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"工作"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"個人檢視模式"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"工作檢視模式"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"IT 管理員已封鎖這項操作"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"無法透過工作應用程式分享這項內容"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"無法使用工作應用程式開啟這項內容"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"無法透過個人應用程式分享這項內容"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"無法使用個人應用程式開啟這項內容"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"工作資料夾已暫停使用"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"輕觸即可啟用"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"沒有適用的工作應用程式"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"沒有適用的個人應用程式"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"要在個人資料夾中開啟「<xliff:g id="APP">%s</xliff:g>」嗎?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"要在工作資料夾中開啟「<xliff:g id="APP">%s</xliff:g>」嗎?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"使用個人瀏覽器"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"使用工作瀏覽器"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"排除文字"</string>
+ <string name="include_text" msgid="642280283268536140">"加回文字"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"排除連結"</string>
+ <string name="include_link" msgid="827855767220339802">"加回連結"</string>
+</resources>
diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml
new file mode 100644
index 00000000..9e1a207f
--- /dev/null
+++ b/java/res/values-zu/strings.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="whichApplication" msgid="2309561338625872614">"Qedela isenzo usebenzisa"</string>
+ <string name="whichApplicationNamed" msgid="8514249643796783492">"Qedela isenzo usebenzisa i-<xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichApplicationLabel" msgid="4312929689807826793">"Qedela isenzo"</string>
+ <string name="whichViewApplication" msgid="7660051361612888119">"Vula nge-"</string>
+ <string name="whichViewApplicationNamed" msgid="8231810543224200555">"Vula nge-<xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichViewApplicationLabel" msgid="9123647023323311663">"Kuvuliwe"</string>
+ <string name="whichOpenHostLinksWith" msgid="6664206254809230738">"Vula izixhumanisi ze-<xliff:g id="HOST">%1$s</xliff:g> nge"</string>
+ <string name="whichOpenLinksWith" msgid="3468042265545684416">"Vula izixhumanisi nge"</string>
+ <string name="whichOpenLinksWithApp" msgid="8832514962474825330">"Vula izixhumanisi nge-<xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="6626134603937682461">"Vula izixhumanisi ze-<xliff:g id="HOST">%1$s</xliff:g> nge-<xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichGiveAccessToApplicationLabel" msgid="5120142857844152131">"Nikeza ukufinyela"</string>
+ <string name="whichEditApplication" msgid="5097563012157950614">"Hlela nge-"</string>
+ <string name="whichEditApplicationNamed" msgid="3150137489226219100">"Hlela nge-<xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichEditApplicationLabel" msgid="5992662938338600364">"Hlela"</string>
+ <string name="whichSendApplication" msgid="59510564281035884">"Yabelana"</string>
+ <string name="whichSendApplicationNamed" msgid="495577664218765855">"Yabelana ne-<xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendApplicationLabel" msgid="2391198069286568035">"Yabelana"</string>
+ <string name="whichSendToApplication" msgid="2724450540348806267">"Thumela usebenzisa"</string>
+ <string name="whichSendToApplicationNamed" msgid="1996548940365954543">"Thumela usebenzisa i-<xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichSendToApplicationLabel" msgid="6909037198280591110">"Thumela"</string>
+ <string name="whichHomeApplication" msgid="8797832422254564739">"Khetha uhlelo lokusebenza lasekhaya"</string>
+ <string name="whichHomeApplicationNamed" msgid="3943122502791761387">"Sebenzisa i-<xliff:g id="APP">%1$s</xliff:g> Njengekhaya"</string>
+ <string name="whichHomeApplicationLabel" msgid="2066319585322981524">"Thwebula isithombe"</string>
+ <string name="whichImageCaptureApplication" msgid="7830965894804399333">"Thwebula isithombe nge-"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="5927801386307049780">"Thwebula isithombe nge-<xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="987153638235357094">"Thwebula isithombe"</string>
+ <string name="use_a_different_app" msgid="2062380818535918975">"Sebenzisa uhlelo lokusebenza oluhlukile"</string>
+ <string name="chooseActivity" msgid="6659724877523973446">"Khetha okufanele kwenziwe"</string>
+ <string name="noApplications" msgid="1139487441772284671">"Azikho izinhlelo zokusebenza ezingenza lokhu"</string>
+ <string name="forward_intent_to_owner" msgid="6454987608971162379">"Usebenzisa lolu hlelo lokusebenza ngaphandle kwephrofayela yakho yomsebenzi"</string>
+ <string name="forward_intent_to_work" msgid="2906094223089139419">"Usebenzisa lolu hlelo lokusebenza kuphrofayela yakho yomsebenzi"</string>
+ <string name="activity_resolver_use_always" msgid="8674194687637555245">"Njalo"</string>
+ <string name="activity_resolver_use_once" msgid="594173435998892989">"Kanye nje"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="8228711455685203580">"I-<xliff:g id="APP">%1$s</xliff:g> ayisekeli iphrofayela yokusebenza"</string>
+ <string name="pin_specific_target" msgid="5057063421361441406">"Phina i-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_specific_target" msgid="3115158908159857777">"Susa ukuphina ku-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="screenshot_edit" msgid="3857183660047569146">"Hlela"</string>
+ <string name="file_count" msgid="3991190034661965836">"{count,plural, =1{{file_name} + ifayela elingu-#}one{{file_name} + amafayela angu-#}other{{file_name} + amafayela angu-#}}"</string>
+ <string name="other_files" msgid="4501185823517473875">"{count,plural, =1{Ifayela eli-+ #}one{Amafayela angu-+ #}other{Amafayela angu-+ #}}"</string>
+ <string name="sharing_text" msgid="8137537443603304062">"Yabelana ngombhalo"</string>
+ <string name="sharing_link" msgid="2307694372813942916">"Yabelana ngelinki"</string>
+ <string name="sharing_images" msgid="5251443722186962006">"{count,plural, =1{Yabelana ngomfanekiso}one{Yabelana ngemifanekiso engu-#}other{Yabelana ngemifanekiso engu-#}}"</string>
+ <string name="sharing_videos" msgid="3583423190182877434">"{count,plural, =1{Yabelana ngevidiyo}one{Yabelana ngamavidiyo angu-#}other{Yabelana ngamavidiyo angu-#}}"</string>
+ <string name="sharing_items" msgid="5266543892527310331">"{count,plural, =1{Yabelana ngento engu-#}one{Yabelana ngezinto ezingu-#}other{Yabelana ngezinto ezingu-#}}"</string>
+ <string name="sharing_image_with_text" msgid="3844438616236662145">"Yabelana ngomfanekiso ngombhalo"</string>
+ <string name="sharing_image_with_link" msgid="5318319026387721227">"Yabelana ngomfanekiso ngelinki"</string>
+ <string name="chooser_no_direct_share_targets" msgid="4233416657754261844">"Ayinconyelwa ukuba abantu bayabelane"</string>
+ <string name="chooser_all_apps_button_label" msgid="5655027129615750712">"Uhlu lwezinhlelo zokusebenza"</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="4254493957548169620">"Lolu hlelo lokusebenza alunikeziwe imvume yokurekhoda kodwa lungathwebula umsindo ngale divayisi ye-USB."</string>
+ <string name="resolver_personal_tab" msgid="1381052735324320565">"Okomuntu siqu"</string>
+ <string name="resolver_work_tab" msgid="3588325717455216412">"Umsebenzi"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="4467784352232582574">"Ukubuka komuntu siqu"</string>
+ <string name="resolver_work_tab_accessibility" msgid="7581878836587799920">"Ukubuka komsebenzi"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3515194063758605377">"Kuvinjelwe umlawuli wakho we-IT"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="2984105853145456723">"Lokhu okuqukethwe akukwazi ukwabiwa nama-app womsebenzi"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="1463093773348988122">"Lokhu okuqukethwe akukwazi ukukopishwa ngama-app womsebenzi"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6406971348929464569">"Lokhu okuqukethwe akukwazi ukwabiwa nama-app womuntu siqu"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="6209543716289792706">"Lokhu okuqukethwe akukwazi ukukopishwa ngama-app womuntu siqu"</string>
+ <string name="resolver_turn_on_work_apps" msgid="6464225110988983641">"Iphrofayela yomsebenzi iphunyuziwe"</string>
+ <string name="resolver_switch_on_work" msgid="4615505942222617333">"Thepha ukuze uvule"</string>
+ <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"Awekho ama-app womsebenzi"</string>
+ <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"Awekho ama-app womuntu siqu"</string>
+ <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Vula i-<xliff:g id="APP">%s</xliff:g> kwiphrofayela yakho siqu?"</string>
+ <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Vula i-<xliff:g id="APP">%s</xliff:g> kwiphrofayela yakho yomsebenzi?"</string>
+ <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Sebenzisa isiphequluli somuntu siqu"</string>
+ <string name="miniresolver_use_work_browser" msgid="7892699758493230342">"Sebenzisa isiphequluli somsebenzi"</string>
+ <string name="exclude_text" msgid="5508128757025928034">"Ungafaki umbhalo"</string>
+ <string name="include_text" msgid="642280283268536140">"Faka umbhalo"</string>
+ <string name="exclude_link" msgid="1332778255031992228">"Ungafaki ilinki"</string>
+ <string name="include_link" msgid="827855767220339802">"Faka ilinki"</string>
+</resources>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 2f2bbda2..67acb3ae 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -41,4 +41,14 @@
<attr name="layout_hasNestedScrollIndicator" format="boolean" />
<attr name="layout_maxHeight" format="dimension"/>
</declare-styleable>
+
+ <declare-styleable name="RoundedRectImageView">
+ <attr name="radius" format="dimension" />
+ </declare-styleable>
+
+ <declare-styleable name="ScrollableImagePreviewView">
+ <attr name="itemInnerSpacing" format="dimension" />
+ <attr name="itemOuterSpacing" format="dimension" />
+ <attr name="maxWidthHint" format="dimension" />
+ </declare-styleable>
</resources>
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index f8addc9f..1890bc6d 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -39,5 +39,5 @@
This name is in the ComponentName flattened format (package/class) [DO NOT TRANSLATE] -->
<string name="config_systemImageEditor" translatable="false">@*android:string/config_systemImageEditor</string>
- <integer name="config_chooser_max_targets_per_row">@*android:integer/config_chooser_max_targets_per_row</integer>
+ <integer name="config_chooser_max_targets_per_row">5</integer>
</resources>
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 87eec7fb..6590d70e 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -17,18 +17,20 @@
<dimen name="resolver_max_width">480dp</dimen>
<!-- chooser/resolver (sharesheet) spacing -->
+ <dimen name="chooser_action_corner_radius">28dp</dimen>
+ <dimen name="chooser_action_horizontal_margin">2dp</dimen>
+ <dimen name="chooser_action_max_width">200dp</dimen>
<dimen name="chooser_width">412dp</dimen>
<dimen name="chooser_corner_radius">28dp</dimen>
+ <dimen name="chooser_corner_radius_small">14dp</dimen>
<dimen name="chooser_row_text_option_translate">25dp</dimen>
- <dimen name="chooser_view_spacing">18dp</dimen>
- <dimen name="chooser_edge_margin_thin">16dp</dimen>
- <dimen name="chooser_edge_margin_normal">24dp</dimen>
+ <dimen name="chooser_edge_margin_thin">8dp</dimen>
+ <dimen name="chooser_edge_margin_normal">16dp</dimen>
+ <dimen name="chooser_edge_margin_normal_half">8dp</dimen>
<dimen name="chooser_preview_image_font_size">20sp</dimen>
<dimen name="chooser_preview_image_border">1dp</dimen>
<dimen name="chooser_preview_image_width">120dp</dimen>
- <dimen name="chooser_preview_image_height">104dp</dimen>
<dimen name="chooser_preview_image_max_dimen">200dp</dimen>
- <dimen name="chooser_preview_width">-1px</dimen>
<dimen name="chooser_header_scroll_elevation">4dp</dimen>
<dimen name="chooser_max_collapsed_height">288dp</dimen>
<dimen name="chooser_direct_share_label_placeholder_max_width">72dp</dimen>
@@ -50,8 +52,16 @@
<dimen name="resolver_empty_state_container_padding_top">48dp</dimen>
<dimen name="resolver_empty_state_container_padding_bottom">8dp</dimen>
<dimen name="resolver_profile_tab_margin">4dp</dimen>
-
- <dimen name="chooser_action_button_icon_size">18dp</dimen>
<dimen name="chooser_action_view_icon_size">22dp</dimen>
<dimen name="chooser_action_margin">0dp</dimen>
+ <dimen name="modify_share_text_toggle_max_width">150dp</dimen>
+ <dimen name="chooser_view_spacing">16dp</dimen>
+
+ <!-- Note that the values in this section are for landscape phones. For screen configs taller
+ than 480dp, the values are set in values-h480dp/dimens.xml -->
+ <dimen name="chooser_preview_width">412dp</dimen>
+ <dimen name="chooser_preview_image_height_tall">46dp</dimen>
+ <dimen name="grid_padding">8dp</dimen>
+ <dimen name="width_text_image_preview_size">46dp</dimen>
+ <!-- END SECTION -->
</resources>
diff --git a/java/res/values/integers.xml b/java/res/values/integers.xml
new file mode 100644
index 00000000..6d57e43e
--- /dev/null
+++ b/java/res/values/integers.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <!-- Note that this is the value for landscape phones, the value for all screens taller than
+ 480dp is set in values-h480dp/integers.xml -->
+ <integer name="text_preview_lines">1</integer>
+</resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 24604ed3..4b5367c0 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -17,17 +17,92 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Title of the IntentResolver application. [CHAR LIMIT=50] -->
- <string name="app_label">IntentResolver</string>
+ <string name="app_label" translatable="false">IntentResolver</string>
+ <!-- Title of intent resolver dialog when selecting an application to run. -->
+ <string name="whichApplication">Complete action using</string>
+ <!-- Title of intent resolver dialog when selecting an application to run
+ and a previously used application is known. -->
+ <string name="whichApplicationNamed">Complete action using <xliff:g id="app" example="YouTube">%1$s</xliff:g></string>
+ <!-- Generic label for a link to a intent resolver. -->
+ <string name="whichApplicationLabel">Complete action</string>
+ <!-- Title of intent resolver dialog when selecting a viewer application to run. -->
+ <string name="whichViewApplication">Open with</string>
+ <!-- Title of intent resolver dialog when selecting a viewer application to run
+ and a previously used application is known. -->
+ <string name="whichViewApplicationNamed">Open with <xliff:g id="app" example="YouTube">%1$s</xliff:g></string>
<!-- Label for a link to a intent resolver dialog to view something -->
<string name="whichViewApplicationLabel">Open</string>
+ <!-- Title of intent resolver dialog when selecting a browser/application that opens specific URIs
+ [CHAR LIMIT=128]. -->
+ <string name="whichOpenHostLinksWith">Open <xliff:g id="host" example="mail.google.com">%1$s</xliff:g> links with</string>
+ <!-- Title of intent resolver dialog when selecting a browser that opens URI
+ [CHAR LIMIT=128]. -->
+ <string name="whichOpenLinksWith">Open links with</string>
+ <!-- Title of intent resolver dialog when defaulting to a specific browser that opens URI
+ [CHAR LIMIT=128]. -->
+ <string name="whichOpenLinksWithApp">Open links with <xliff:g id="application" example="Chrome">%1$s</xliff:g></string>
+ <!-- Title of intent resolver dialog when defaulting to a specific browser that opens URI
+ [CHAR LIMIT=128]. -->
+ <string name="whichOpenHostLinksWithApp">Open <xliff:g id="host" example="mail.google.com">%1$s</xliff:g> links with <xliff:g id="application" example="Chrome">%2$s</xliff:g></string>
+ <!-- Label for a link to an intent resolver dialog to open URI [CHAR LIMIT=18] -->
+ <string name="whichGiveAccessToApplicationLabel">Give access</string>
+ <!-- Title of intent resolver dialog when selecting an editor application to run. -->
+ <string name="whichEditApplication">Edit with</string>
+ <!-- Title of intent resolver dialog when selecting an editor application to run
+ and a previously used application is known. -->
+ <string name="whichEditApplicationNamed">Edit with <xliff:g id="app" example="YouTube">%1$s</xliff:g></string>
+ <!-- Label for a link to a intent resolver dialog when selecting an editor application -->
+ <string name="whichEditApplicationLabel">Edit</string>
+ <!-- Title of intent resolver dialog when selecting a sharing application to run. -->
+ <string name="whichSendApplication">Share</string>
+ <!-- Title of intent resolver dialog when selecting a sharing application to run
+ and a previously used application is known. -->
+ <string name="whichSendApplicationNamed">Share with <xliff:g id="app" example="YouTube">%1$s</xliff:g></string>
+ <!-- Label for a link to a intent resolver dialog to sharing something -->
+ <string name="whichSendApplicationLabel">Share</string>
+ <!-- Title of intent resolver dialog when selecting an application to run to
+ send content to a specific recipient. Often used for email. -->
+ <string name="whichSendToApplication">Send using</string>
+ <!-- Title of intent resolver dialog when selecting an application to run to
+ send content to a specific recipient and a previously used application is known.
+ Often used for email. -->
+ <string name="whichSendToApplicationNamed">Send using <xliff:g id="app" example="YouTube">%1$s</xliff:g></string>
+ <!-- Label for a link to a intent resolver dialog to send content to a specific recipient. -->
+ <string name="whichSendToApplicationLabel">Send</string>
+ <!-- Title of intent resolver dialog when selecting a HOME application to run. -->
+ <string name="whichHomeApplication">Select a Home app</string>
+ <!-- Title of intent resolver dialog when selecting a HOME application to run
+ and a previously used application is known. -->
+ <string name="whichHomeApplicationNamed">Use <xliff:g id="app" example="YouTube">%1$s</xliff:g> as Home</string>
+ <!-- Label for a link to a intent resolver dialog when selecting a HOME -->
+ <string name="whichHomeApplicationLabel">Capture image</string>
+ <!-- Option to always use the selected application resolution in the future. See the "Complete action using" dialog title-->
+ <!-- Title of intent resolver dialog when capturing an image. -->
+ <string name="whichImageCaptureApplication">Capture image with</string>
+ <!-- Title of intent resolver dialog when capturing an image
+ and a previously used application is known. -->
+ <string name="whichImageCaptureApplicationNamed">Capture image with <xliff:g id="app" example="YouTube">%1$s</xliff:g></string>
+ <!-- Label for a link to a intent resolver dialog when capturing an image -->
+ <string name="whichImageCaptureApplicationLabel">Capture image</string>
+
<!-- Title of the list of alternate options to complete an action shown when the
last used option is being displayed separately. -->
<string name="use_a_different_app">Use a different app</string>
+ <!-- Default title for the activity chooser, when one is not given. Android allows multiple
+ activities to perform an action. for example, there may be many ringtone pickers installed.
+ A dialog is shown to the user allowing them to pick which activity should be used. This is
+ the title. -->
+ <string name="chooseActivity">Choose an action</string>
<!-- Text to display when there are no activities found to display in the
activity chooser. See the "Select an action" title. -->
<string name="noApplications">No apps can perform this action.</string>
+ <!-- Message to show when an intent automatically switches users into the personal profile. -->
+ <string name="forward_intent_to_owner">You\'re using this app outside of your work profile</string>
+ <!-- Message to show when an intent automatically switches users into a work profile. -->
+ <string name="forward_intent_to_work">You\'re using this app in your work profile</string>
+
<!-- Title for a button to choose the currently selected activity
as the default in the activity resolver. [CHAR LIMIT=25] -->
<string name="activity_resolver_use_always">Always</string>
@@ -36,24 +111,142 @@
from the activity resolver to use just this once. [CHAR LIMIT=25] -->
<string name="activity_resolver_use_once">Just once</string>
+ <!-- Text for the toast that is shown when the user clicks on a launcher that
+ doesn't support the work profile. [CHAR LIMIT=100] -->
+ <string name="activity_resolver_work_profiles_support"><xliff:g id="app" example="YouTube">%1$s</xliff:g> doesn\'t support work profile</string>
+
<!-- Resolver target actions strings -->
<!-- Pin this app to the top of the Sharesheet app list. [CHAR LIMIT=60]-->
<string name="pin_specific_target">Pin <xliff:g id="label" example="Tweet">%1$s</xliff:g></string>
<!-- Un-pin this app in the Sharesheet, so that it is sorted normally. [CHAR LIMIT=60]-->
<string name="unpin_specific_target">Unpin <xliff:g id="label" example="Tweet">%1$s</xliff:g></string>
- <string name="file_count">{count, plural,
- =1 {{file_name} + # file}
- other {{file_name} + # files}
+ <!-- Notification action for editing a screenshot (drawing on it, cropping it, etc) -->
+ <string name="screenshot_edit">Edit</string>
+
+ <!-- Represents a number of other files also being shared; used as an item at the end of a list -->
+ <string name="other_files">{count, plural,
+ =1 {+ # file}
+ other {+ # files}
+ }
+ </string>
+
+ <!-- Text label indicating the number of other files also being shared -->
+ <string name="more_files">{count, plural,
+ =1 {+ # more file}
+ other {+ # more files}
+ }
+ </string>
+
+ <!-- Title atop a sharing UI indicating that text is being shared [CHAR_LIMIT=50] -->
+ <string name="sharing_text">Sharing text</string>
+ <!-- Title atop a sharing UI indicating that a link (URL) is being shared [CHAR_LIMIT=50] -->
+ <string name="sharing_link">Sharing link</string>
+ <!-- Title atop a sharing UI indicating that some images are being shared [CHAR_LIMIT=50] -->
+ <string name="sharing_images">{count, plural,
+ =1 {Sharing image}
+ other {Sharing # images}
}
</string>
+ <!-- Title atop a sharing UI indicating that some videos are being shared [CHAR_LIMIT=50] -->
+ <string name="sharing_videos">{count, plural,
+ =1 {Sharing video}
+ other {Sharing # videos}
+ }
+ </string>
+ <!-- Title atop a sharing UI indicating that some number of files are being shared
+ (for example: sharing a mixture of photos and videos) [CHAR_LIMIT=50] -->
+ <string name="sharing_files">{count, plural,
+ =1 {Sharing # file}
+ other {Sharing # files}
+ }
+ </string>
+
+ <!-- Title atop a sharing UI indicating that some number of images are being shared
+ along with text [CHAR_LIMIT=50] -->
+ <string name="sharing_images_with_text">{count, plural,
+ =1 {Sharing image with text}
+ other {Sharing # images with text}
+ }
+ </string>
+
+ <!-- Title atop a sharing UI indicating that some number of images are being shared
+ along with a web link [CHAR_LIMIT=50] -->
+ <string name="sharing_images_with_link">{count, plural,
+ =1 {Sharing image with link}
+ other {Sharing # images with link}
+ }
+ </string>
+
+ <!-- Title atop a sharing UI indicating that some number of videos are being shared
+ along with text [CHAR_LIMIT=50] -->
+ <string name="sharing_videos_with_text">{count, plural,
+ =1 {Sharing video with text}
+ other {Sharing # videos with text}
+ }
+ </string>
+
+ <!-- Title atop a sharing UI indicating that some number of videos are being shared
+ along with a web link [CHAR_LIMIT=50] -->
+ <string name="sharing_videos_with_link">{count, plural,
+ =1 {Sharing video with link}
+ other {Sharing # videos with link}
+ }
+ </string>
+
+ <!-- Title atop a sharing UI indicating that some number of files are being shared
+ along with text [CHAR_LIMIT=50] -->
+ <string name="sharing_files_with_text">{count, plural,
+ =1 {Sharing file with text}
+ other {Sharing # files with text}
+ }
+ </string>
+
+ <!-- Title atop a sharing UI indicating that some number of files are being shared
+ along with a web link [CHAR_LIMIT=50] -->
+ <string name="sharing_files_with_link">{count, plural,
+ =1 {Sharing file with link}
+ other {Sharing # files with link}
+ }
+ </string>
+
+ <!-- Message indicating that the attached text has been removed from this share and only the
+ images are being shared. [CHAR LIMIT=none] -->
+ <string name="sharing_images_only">{count, plural,
+ =1 {Image only}
+ other {Images only}
+ }
+ </string>
+
+ <!-- Message indicating that the attached text has been removed from this share and only the
+ videos are being shared. [CHAR LIMIT=none] -->
+ <string name="sharing_videos_only">{count, plural,
+ =1 {Video only}
+ other {Videos only}
+ }
+ </string>
+
+ <!-- Message indicating that the attached text has been removed from this share and only the
+ files are being shared. [CHAR LIMIT=none] -->
+ <string name="sharing_files_only">{count, plural,
+ =1 {File only}
+ other {Files only}
+ }
+ </string>
+
+ <!-- Accessibility announcement when a preview thumbnail for a shared image is selected in the
+ Chooser content preview -->
+ <string name="image_preview_a11y_description">Image preview thumbnail</string>
+ <!-- Accessibility announcement when a preview thumbnail for a shared vide item is selected in
+ the Chooser content preview -->
+ <string name="video_preview_a11y_description">Video preview thumbnail</string>
+ <!-- Accessibility announcement when a preview thumbnail for a shared file is selected in the
+ Chooser content preview -->
+ <string name="file_preview_a11y_description">File preview thumbnail</string>
<!-- ChooserActivity - No direct share targets are available. [CHAR LIMIT=NONE] -->
<string name="chooser_no_direct_share_targets">No recommended people to share with</string>
- <!-- ChooserActivity - Alphabetically sorted apps list label. [CHAR LIMIT=NONE] -->
- <string name="chooser_all_apps_button_label">Apps list</string>
-
<!-- Prompt for the USB device resolver dialog with warning text for USB device dialogs. [CHAR LIMIT=200] -->
<string name="usb_device_resolve_prompt_warn">This app has not been granted record permission but could capture audio through this USB device.</string>
@@ -83,9 +276,9 @@
<string name="resolver_cant_access_personal_apps_explanation">This content can\u2019t be opened with personal apps</string>
<!-- Error message. This text lets the user know that they need to turn on work apps in order to share or open content. There's also a button a user can tap to turn on the apps. [CHAR LIMIT=NONE] -->
- <string name="resolver_turn_on_work_apps">Work profile is paused</string>
- <!-- Button text. This button turns on a user's work profile so they can access their work apps and data. [CHAR LIMIT=NONE] -->
- <string name="resolver_switch_on_work">Tap to turn on</string>
+ <string name="resolver_turn_on_work_apps">Work apps are paused</string>
+ <!-- Button text. This button unpauses a user's work apps and data. [CHAR LIMIT=NONE] -->
+ <string name="resolver_switch_on_work">Unpause</string>
<!-- Error message. This text lets the user know that their current work apps don't support the specific content. [CHAR LIMIT=NONE] -->
<string name="resolver_no_work_apps_available">No work apps</string>
@@ -102,13 +295,6 @@
<!-- Button option. Open the link in the work browser. [CHAR LIMIT=NONE] -->
<string name="miniresolver_use_work_browser">Use work browser</string>
- <!-- Tittle for a button. Launches client-provided content reselection action. -->
- <string name="select_files">Select Files</string>
- <!-- Tittle for a button. Launches client-provided content reselection action. -->
- <string name="select_images">Select Images</string>
- <!-- Tittle for a button. Launches client-provided content reselection action. -->
- <string name="select_text">Select Text</string>
-
<!-- Title for a button. Excludes a text from the shared content (a media and a text). -->
<string name="exclude_text">Exclude text</string>
<!-- Title for a button. Adds back a (previously excluded) text into the shared content. -->
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index ba6418a8..9a31a141 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -49,9 +49,4 @@
<style name="TextAppearance.ChooserDefault"
parent="@android:style/TextAppearance.DeviceDefault" />
-
- <style name="ReselectionAction" parent="TextAppearance.ChooserDefault">
- <item name="android:paddingTop">5dp</item>
- <item name="android:paddingBottom">5dp</item>
- </style>
</resources>
diff --git a/java/src/com/android/intentresolver/AbstractMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/AbstractMultiProfilePagerAdapter.java
index e3f1b233..4b06db3b 100644
--- a/java/src/com/android/intentresolver/AbstractMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/AbstractMultiProfilePagerAdapter.java
@@ -62,6 +62,7 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
private Set<Integer> mLoadedPages;
private final EmptyStateProvider mEmptyStateProvider;
private final UserHandle mWorkProfileUserHandle;
+ private final UserHandle mCloneProfileUserHandle;
private final Supplier<Boolean> mWorkProfileQuietModeChecker; // True when work is quiet.
AbstractMultiProfilePagerAdapter(
@@ -69,11 +70,13 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
int currentPage,
EmptyStateProvider emptyStateProvider,
Supplier<Boolean> workProfileQuietModeChecker,
- UserHandle workProfileUserHandle) {
+ UserHandle workProfileUserHandle,
+ UserHandle cloneProfileUserHandle) {
mContext = Objects.requireNonNull(context);
mCurrentPage = currentPage;
mLoadedPages = new HashSet<>();
mWorkProfileUserHandle = workProfileUserHandle;
+ mCloneProfileUserHandle = cloneProfileUserHandle;
mEmptyStateProvider = emptyStateProvider;
mWorkProfileQuietModeChecker = workProfileQuietModeChecker;
}
@@ -160,6 +163,10 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
return null;
}
+ public UserHandle getCloneUserHandle() {
+ return mCloneProfileUserHandle;
+ }
+
/**
* Returns the {@link ProfileDescriptor} relevant to the given <code>pageIndex</code>.
* <ul>
diff --git a/java/src/com/android/intentresolver/AnnotatedUserHandles.java b/java/src/com/android/intentresolver/AnnotatedUserHandles.java
index b4365b84..168f36d6 100644
--- a/java/src/com/android/intentresolver/AnnotatedUserHandles.java
+++ b/java/src/com/android/intentresolver/AnnotatedUserHandles.java
@@ -22,6 +22,8 @@ import android.app.ActivityManager;
import android.os.UserHandle;
import android.os.UserManager;
+import androidx.annotation.VisibleForTesting;
+
/**
* Helper class to precompute the (immutable) designations of various user handles in the system
* that may contribute to the current Sharesheet session.
@@ -78,36 +80,138 @@ public final class AnnotatedUserHandles {
*/
public final UserHandle tabOwnerUserHandleForLaunch;
- public AnnotatedUserHandles(Activity forShareActivity) {
- userIdOfCallingApp = forShareActivity.getLaunchedFromUid();
- if ((userIdOfCallingApp < 0) || UserHandle.isIsolated(userIdOfCallingApp)) {
- throw new SecurityException("Can't start a resolver from uid " + userIdOfCallingApp);
- }
+ /** Compute all handle designations for a new Sharesheet session in the specified activity. */
+ public static AnnotatedUserHandles forShareActivity(Activity shareActivity) {
+ // TODO: consider integrating logic for `ResolverActivity.EXTRA_CALLING_USER`?
+ UserHandle userHandleSharesheetLaunchedAs = UserHandle.of(UserHandle.myUserId());
+
+ // ActivityManager.getCurrentUser() refers to the current Foreground user. When clone/work
+ // profile is active, we always make the personal tab from the foreground user.
+ // Outside profiles, current foreground user is potentially the same as the sharesheet
+ // process's user (UserHandle.myUserId()), so we continue to create personal tab with the
+ // current foreground user.
+ UserHandle personalProfileUserHandle = UserHandle.of(ActivityManager.getCurrentUser());
+
+ UserManager userManager = shareActivity.getSystemService(UserManager.class);
+
+ return newBuilder()
+ .setUserIdOfCallingApp(shareActivity.getLaunchedFromUid())
+ .setUserHandleSharesheetLaunchedAs(userHandleSharesheetLaunchedAs)
+ .setPersonalProfileUserHandle(personalProfileUserHandle)
+ .setWorkProfileUserHandle(
+ getWorkProfileForUser(userManager, personalProfileUserHandle))
+ .setCloneProfileUserHandle(
+ getCloneProfileForUser(userManager, personalProfileUserHandle))
+ .build();
+ }
- // TODO: integrate logic for `ResolverActivity.EXTRA_CALLING_USER`.
- userHandleSharesheetLaunchedAs = UserHandle.of(UserHandle.myUserId());
+ @VisibleForTesting static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * Returns the {@link UserHandle} to use when querying resolutions for intents in a
+ * {@link ResolverListController} configured for the provided {@code userHandle}.
+ */
+ public UserHandle getQueryIntentsUser(UserHandle userHandle) {
+ // In case launching app is in clonedProfile, and we are building the personal tab, intent
+ // resolution will be attempted as clonedUser instead of user 0. This is because intent
+ // resolution from user 0 and clonedUser is not guaranteed to return same results.
+ // We do not care about the case when personal adapter is started with non-root user
+ // (secondary user case), as clone profile is guaranteed to be non-active in that case.
+ UserHandle queryIntentsUser = userHandle;
+ if (isLaunchedAsCloneProfile() && userHandle.equals(personalProfileUserHandle)) {
+ queryIntentsUser = cloneProfileUserHandle;
+ }
+ return queryIntentsUser;
+ }
- personalProfileUserHandle = UserHandle.of(ActivityManager.getCurrentUser());
+ private Boolean isLaunchedAsCloneProfile() {
+ return userHandleSharesheetLaunchedAs.equals(cloneProfileUserHandle);
+ }
- UserManager userManager = forShareActivity.getSystemService(UserManager.class);
- workProfileUserHandle = getWorkProfileForUser(userManager, personalProfileUserHandle);
- cloneProfileUserHandle = getCloneProfileForUser(userManager, personalProfileUserHandle);
+ private AnnotatedUserHandles(
+ int userIdOfCallingApp,
+ UserHandle userHandleSharesheetLaunchedAs,
+ UserHandle personalProfileUserHandle,
+ @Nullable UserHandle workProfileUserHandle,
+ @Nullable UserHandle cloneProfileUserHandle) {
+ if ((userIdOfCallingApp < 0) || UserHandle.isIsolated(userIdOfCallingApp)) {
+ throw new SecurityException("Can't start a resolver from uid " + userIdOfCallingApp);
+ }
- tabOwnerUserHandleForLaunch = (userHandleSharesheetLaunchedAs == workProfileUserHandle)
- ? workProfileUserHandle : personalProfileUserHandle;
+ this.userIdOfCallingApp = userIdOfCallingApp;
+ this.userHandleSharesheetLaunchedAs = userHandleSharesheetLaunchedAs;
+ this.personalProfileUserHandle = personalProfileUserHandle;
+ this.workProfileUserHandle = workProfileUserHandle;
+ this.cloneProfileUserHandle = cloneProfileUserHandle;
+ this.tabOwnerUserHandleForLaunch =
+ (userHandleSharesheetLaunchedAs == workProfileUserHandle)
+ ? workProfileUserHandle : personalProfileUserHandle;
}
@Nullable
private static UserHandle getWorkProfileForUser(
UserManager userManager, UserHandle profileOwnerUserHandle) {
- return userManager.getProfiles(profileOwnerUserHandle.getIdentifier()).stream()
- .filter(info -> info.isManagedProfile()).findFirst()
- .map(info -> info.getUserHandle()).orElse(null);
+ return userManager.getProfiles(profileOwnerUserHandle.getIdentifier())
+ .stream()
+ .filter(info -> info.isManagedProfile())
+ .findFirst()
+ .map(info -> info.getUserHandle())
+ .orElse(null);
}
@Nullable
private static UserHandle getCloneProfileForUser(
UserManager userManager, UserHandle profileOwnerUserHandle) {
- return null; // Not yet supported in framework.
+ return userManager.getProfiles(profileOwnerUserHandle.getIdentifier())
+ .stream()
+ .filter(info -> info.isCloneProfile())
+ .findFirst()
+ .map(info -> info.getUserHandle())
+ .orElse(null);
+ }
+
+ @VisibleForTesting
+ static class Builder {
+ private int mUserIdOfCallingApp;
+ private UserHandle mUserHandleSharesheetLaunchedAs;
+ private UserHandle mPersonalProfileUserHandle;
+ private UserHandle mWorkProfileUserHandle;
+ private UserHandle mCloneProfileUserHandle;
+
+ public Builder setUserIdOfCallingApp(int id) {
+ mUserIdOfCallingApp = id;
+ return this;
+ }
+
+ public Builder setUserHandleSharesheetLaunchedAs(UserHandle user) {
+ mUserHandleSharesheetLaunchedAs = user;
+ return this;
+ }
+
+ public Builder setPersonalProfileUserHandle(UserHandle user) {
+ mPersonalProfileUserHandle = user;
+ return this;
+ }
+
+ public Builder setWorkProfileUserHandle(UserHandle user) {
+ mWorkProfileUserHandle = user;
+ return this;
+ }
+
+ public Builder setCloneProfileUserHandle(UserHandle user) {
+ mCloneProfileUserHandle = user;
+ return this;
+ }
+
+ public AnnotatedUserHandles build() {
+ return new AnnotatedUserHandles(
+ mUserIdOfCallingApp,
+ mUserHandleSharesheetLaunchedAs,
+ mPersonalProfileUserHandle,
+ mWorkProfileUserHandle,
+ mCloneProfileUserHandle);
+ }
}
}
diff --git a/java/src/com/android/intentresolver/ChooserActionFactory.java b/java/src/com/android/intentresolver/ChooserActionFactory.java
index 947155f3..6ec62753 100644
--- a/java/src/com/android/intentresolver/ChooserActionFactory.java
+++ b/java/src/com/android/intentresolver/ChooserActionFactory.java
@@ -26,12 +26,9 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Bundle;
import android.service.chooser.ChooserAction;
import android.text.TextUtils;
import android.util.Log;
@@ -40,8 +37,6 @@ import android.view.View;
import com.android.intentresolver.chooser.DisplayResolveInfo;
import com.android.intentresolver.chooser.TargetInfo;
import com.android.intentresolver.contentpreview.ChooserContentPreviewUi;
-import com.android.intentresolver.flags.FeatureFlagRepository;
-import com.android.intentresolver.flags.Flags;
import com.android.intentresolver.widget.ActionRow;
import com.android.internal.annotations.VisibleForTesting;
@@ -89,15 +84,10 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
private static final String IMAGE_EDITOR_SHARED_ELEMENT = "screenshot_preview_image";
private final Context mContext;
- private final String mCopyButtonLabel;
- private final Drawable mCopyButtonDrawable;
- private final Runnable mOnCopyButtonClicked;
- private final TargetInfo mEditSharingTarget;
- private final Runnable mOnEditButtonClicked;
- private final TargetInfo mNearbySharingTarget;
- private final Runnable mOnNearbyButtonClicked;
+ private final Runnable mCopyButtonRunnable;
+ private final Runnable mEditButtonRunnable;
private final ImmutableList<ChooserAction> mCustomActions;
- private final Runnable mOnModifyShareClicked;
+ private final @Nullable ChooserAction mModifyShareAction;
private final Consumer<Boolean> mExcludeSharedTextAction;
private final Consumer</* @Nullable */ Integer> mFinishCallback;
private final ChooserActivityLogger mLogger;
@@ -105,7 +95,6 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
/**
* @param context
* @param chooserRequest data about the invocation of the current Sharesheet session.
- * @param featureFlagRepository feature flags that may control the eligibility of some actions.
* @param integratedDeviceComponents info about other components that are available on this
* device to implement the supported action types.
* @param onUpdateSharedTextIsExcluded a delegate to be invoked when the "exclude shared text"
@@ -119,7 +108,6 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
public ChooserActionFactory(
Context context,
ChooserRequestParameters chooserRequest,
- FeatureFlagRepository featureFlagRepository,
ChooserIntegratedDeviceComponents integratedDeviceComponents,
ChooserActivityLogger logger,
Consumer<Boolean> onUpdateSharedTextIsExcluded,
@@ -128,19 +116,13 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
Consumer</* @Nullable */ Integer> finishCallback) {
this(
context,
- context.getString(com.android.internal.R.string.copy),
- context.getDrawable(com.android.internal.R.drawable.ic_menu_copy_material),
- makeOnCopyRunnable(
+ makeCopyButtonRunnable(
context,
chooserRequest.getTargetIntent(),
chooserRequest.getReferrerPackageName(),
finishCallback,
logger),
- getEditSharingTarget(
- context,
- chooserRequest.getTargetIntent(),
- integratedDeviceComponents),
- makeOnEditRunnable(
+ makeEditButtonRunnable(
getEditSharingTarget(
context,
chooserRequest.getTargetIntent(),
@@ -148,25 +130,8 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
firstVisibleImageQuery,
activityStarter,
logger),
- getNearbySharingTarget(
- context,
- chooserRequest.getTargetIntent(),
- integratedDeviceComponents),
- makeOnNearbyShareRunnable(
- getNearbySharingTarget(
- context,
- chooserRequest.getTargetIntent(),
- integratedDeviceComponents),
- activityStarter,
- finishCallback,
- logger),
chooserRequest.getChooserActions(),
- (featureFlagRepository.isEnabled(Flags.SHARESHEET_RESELECTION_ACTION)
- ? createModifyShareRunnable(
- chooserRequest.getModifyShareAction(),
- finishCallback,
- logger)
- : null),
+ chooserRequest.getModifyShareAction(),
onUpdateSharedTextIsExcluded,
logger,
finishCallback);
@@ -175,71 +140,33 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
@VisibleForTesting
ChooserActionFactory(
Context context,
- String copyButtonLabel,
- Drawable copyButtonDrawable,
- Runnable onCopyButtonClicked,
- TargetInfo editSharingTarget,
- Runnable onEditButtonClicked,
- TargetInfo nearbySharingTarget,
- Runnable onNearbyButtonClicked,
+ Runnable copyButtonRunnable,
+ Runnable editButtonRunnable,
List<ChooserAction> customActions,
- @Nullable Runnable onModifyShareClicked,
+ @Nullable ChooserAction modifyShareAction,
Consumer<Boolean> onUpdateSharedTextIsExcluded,
ChooserActivityLogger logger,
Consumer</* @Nullable */ Integer> finishCallback) {
mContext = context;
- mCopyButtonLabel = copyButtonLabel;
- mCopyButtonDrawable = copyButtonDrawable;
- mOnCopyButtonClicked = onCopyButtonClicked;
- mEditSharingTarget = editSharingTarget;
- mOnEditButtonClicked = onEditButtonClicked;
- mNearbySharingTarget = nearbySharingTarget;
- mOnNearbyButtonClicked = onNearbyButtonClicked;
+ mCopyButtonRunnable = copyButtonRunnable;
+ mEditButtonRunnable = editButtonRunnable;
mCustomActions = ImmutableList.copyOf(customActions);
- mOnModifyShareClicked = onModifyShareClicked;
+ mModifyShareAction = modifyShareAction;
mExcludeSharedTextAction = onUpdateSharedTextIsExcluded;
mLogger = logger;
mFinishCallback = finishCallback;
}
- /** Create an action that copies the share content to the clipboard. */
- @Override
- public ActionRow.Action createCopyButton() {
- return new ActionRow.Action(
- com.android.internal.R.id.chooser_copy_button,
- mCopyButtonLabel,
- mCopyButtonDrawable,
- mOnCopyButtonClicked);
- }
-
- /** Create an action that opens the share content in a system-default editor. */
@Override
@Nullable
- public ActionRow.Action createEditButton() {
- if (mEditSharingTarget == null) {
- return null;
- }
-
- return new ActionRow.Action(
- com.android.internal.R.id.chooser_edit_button,
- mEditSharingTarget.getDisplayLabel(),
- mEditSharingTarget.getDisplayIconHolder().getDisplayIcon(),
- mOnEditButtonClicked);
+ public Runnable getEditButtonRunnable() {
+ return mEditButtonRunnable;
}
- /** Create a "Share to Nearby" action. */
@Override
@Nullable
- public ActionRow.Action createNearbyButton() {
- if (mNearbySharingTarget == null) {
- return null;
- }
-
- return new ActionRow.Action(
- com.android.internal.R.id.chooser_nearby_button,
- mNearbySharingTarget.getDisplayLabel(),
- mNearbySharingTarget.getDisplayIconHolder().getDisplayIcon(),
- mOnNearbyButtonClicked);
+ public Runnable getCopyButtonRunnable() {
+ return mCopyButtonRunnable;
}
/** Create custom actions */
@@ -247,8 +174,15 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
public List<ActionRow.Action> createCustomActions() {
List<ActionRow.Action> actions = new ArrayList<>();
for (int i = 0; i < mCustomActions.size(); i++) {
+ final int position = i;
ActionRow.Action actionRow = createCustomAction(
- mContext, mCustomActions.get(i), mFinishCallback, i, mLogger);
+ mContext,
+ mCustomActions.get(i),
+ mFinishCallback,
+ () -> {
+ mLogger.logCustomActionSelected(position);
+ }
+ );
if (actionRow != null) {
actions.add(actionRow);
}
@@ -261,27 +195,14 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
*/
@Override
@Nullable
- public Runnable getModifyShareAction() {
- return mOnModifyShareClicked;
- }
-
- private static Runnable createModifyShareRunnable(
- PendingIntent pendingIntent,
- Consumer<Integer> finishCallback,
- ChooserActivityLogger logger) {
- if (pendingIntent == null) {
- return null;
- }
-
- return () -> {
- try {
- pendingIntent.send();
- } catch (PendingIntent.CanceledException e) {
- Log.d(TAG, "Payload reselection action has been cancelled");
- }
- logger.logActionSelected(ChooserActivityLogger.SELECTION_TYPE_MODIFY_SHARE);
- finishCallback.accept(Activity.RESULT_OK);
- };
+ public ActionRow.Action getModifyShareAction() {
+ return createCustomAction(
+ mContext,
+ mModifyShareAction,
+ mFinishCallback,
+ () -> {
+ mLogger.logActionSelected(ChooserActivityLogger.SELECTION_TYPE_MODIFY_SHARE);
+ });
}
/**
@@ -298,7 +219,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
return mExcludeSharedTextAction;
}
- private static Runnable makeOnCopyRunnable(
+ private static Runnable makeCopyButtonRunnable(
Context context,
Intent targetIntent,
String referrerPackageName,
@@ -386,7 +307,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
final DisplayResolveInfo dri = DisplayResolveInfo.newDisplayResolveInfo(
originalIntent,
ri,
- context.getString(com.android.internal.R.string.screenshot_edit),
+ context.getString(R.string.screenshot_edit),
"",
resolveIntent,
null);
@@ -395,7 +316,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
return dri;
}
- private static Runnable makeOnEditRunnable(
+ private static Runnable makeEditButtonRunnable(
TargetInfo editSharingTarget,
Callable</* @Nullable */ View> firstVisibleImageQuery,
ActionActivityStarter activityStarter,
@@ -418,71 +339,15 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
};
}
- private static TargetInfo getNearbySharingTarget(
- Context context,
- Intent originalIntent,
- ChooserIntegratedDeviceComponents integratedComponents) {
- final ComponentName cn = integratedComponents.getNearbySharingComponent();
- if (cn == null) {
- return null;
- }
-
- final Intent resolveIntent = new Intent(originalIntent);
- resolveIntent.setComponent(cn);
- final ResolveInfo ri = context.getPackageManager().resolveActivity(
- resolveIntent, PackageManager.GET_META_DATA);
- if (ri == null || ri.activityInfo == null) {
- Log.e(TAG, "Device-specified nearby sharing component (" + cn
- + ") not available");
- return null;
- }
-
- // Allow the nearby sharing component to provide a more appropriate icon and label
- // for the chip.
- CharSequence name = null;
- Drawable icon = null;
- final Bundle metaData = ri.activityInfo.metaData;
- if (metaData != null) {
- try {
- final Resources pkgRes = context.getPackageManager().getResourcesForActivity(cn);
- final int nameResId = metaData.getInt(CHIP_LABEL_METADATA_KEY);
- name = pkgRes.getString(nameResId);
- final int resId = metaData.getInt(CHIP_ICON_METADATA_KEY);
- icon = pkgRes.getDrawable(resId);
- } catch (NameNotFoundException | Resources.NotFoundException ex) { /* ignore */ }
- }
- if (TextUtils.isEmpty(name)) {
- name = ri.loadLabel(context.getPackageManager());
- }
- if (icon == null) {
- icon = ri.loadIcon(context.getPackageManager());
- }
-
- final DisplayResolveInfo dri = DisplayResolveInfo.newDisplayResolveInfo(
- originalIntent, ri, name, "", resolveIntent, null);
- dri.getDisplayIconHolder().setDisplayIcon(icon);
- return dri;
- }
-
- private static Runnable makeOnNearbyShareRunnable(
- TargetInfo nearbyShareTarget,
- ActionActivityStarter activityStarter,
- Consumer<Integer> finishCallback,
- ChooserActivityLogger logger) {
- return () -> {
- logger.logActionSelected(ChooserActivityLogger.SELECTION_TYPE_NEARBY);
- // Action bar is user-independent; always start as primary.
- activityStarter.safelyStartActivityAsPersonalProfileUser(nearbyShareTarget);
- };
- }
-
@Nullable
private static ActionRow.Action createCustomAction(
Context context,
ChooserAction action,
Consumer<Integer> finishCallback,
- int position,
- ChooserActivityLogger logger) {
+ Runnable loggingRunnable) {
+ if (action == null || action.getAction() == null) {
+ return null;
+ }
Drawable icon = action.getIcon().loadDrawable(context);
if (icon == null && TextUtils.isEmpty(action.getLabel())) {
return null;
@@ -507,7 +372,9 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
} catch (PendingIntent.CanceledException e) {
Log.d(TAG, "Custom action, " + action.getLabel() + ", has been cancelled");
}
- logger.logCustomActionSelected(position);
+ if (loggingRunnable != null) {
+ loggingRunnable.run();
+ }
finishCallback.accept(Activity.RESULT_OK);
}
);
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java
index ae5be26d..63ac6435 100644
--- a/java/src/com/android/intentresolver/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/ChooserActivity.java
@@ -57,7 +57,6 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
-import android.provider.DeviceConfig;
import android.service.chooser.ChooserTarget;
import android.util.Log;
import android.util.Slog;
@@ -73,6 +72,7 @@ import android.view.animation.LinearInterpolator;
import android.widget.TextView;
import androidx.annotation.MainThread;
+import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;
@@ -83,20 +83,23 @@ import com.android.intentresolver.NoCrossProfileEmptyStateProvider.DevicePolicyB
import com.android.intentresolver.chooser.DisplayResolveInfo;
import com.android.intentresolver.chooser.MultiDisplayResolveInfo;
import com.android.intentresolver.chooser.TargetInfo;
+import com.android.intentresolver.contentpreview.BasePreviewViewModel;
import com.android.intentresolver.contentpreview.ChooserContentPreviewUi;
+import com.android.intentresolver.contentpreview.HeadlineGeneratorImpl;
+import com.android.intentresolver.contentpreview.PreviewViewModel;
import com.android.intentresolver.flags.FeatureFlagRepository;
import com.android.intentresolver.flags.FeatureFlagRepositoryFactory;
-import com.android.intentresolver.flags.Flags;
import com.android.intentresolver.grid.ChooserGridAdapter;
-import com.android.intentresolver.grid.DirectShareViewHolder;
+import com.android.intentresolver.icons.DefaultTargetDataLoader;
+import com.android.intentresolver.icons.TargetDataLoader;
+import com.android.intentresolver.measurements.Tracer;
import com.android.intentresolver.model.AbstractResolverComparator;
import com.android.intentresolver.model.AppPredictionServiceResolverComparator;
import com.android.intentresolver.model.ResolverRankerServiceResolverComparator;
import com.android.intentresolver.shortcuts.AppPredictorFactory;
import com.android.intentresolver.shortcuts.ShortcutLoader;
-import com.android.intentresolver.widget.ResolverDrawerLayout;
+import com.android.intentresolver.widget.ImagePreviewView;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.content.PackageMonitor;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -139,21 +142,11 @@ public class ChooserActivity extends ResolverActivity implements
*/
public static final String FIRST_IMAGE_PREVIEW_TRANSITION_NAME = "screenshot_preview_image";
- private static final String PREF_NUM_SHEET_EXPANSIONS = "pref_num_sheet_expansions";
-
- private static final String CHIP_LABEL_METADATA_KEY = "android.service.chooser.chip_label";
- private static final String CHIP_ICON_METADATA_KEY = "android.service.chooser.chip_icon";
-
private static final boolean DEBUG = true;
public static final String LAUNCH_LOCATION_DIRECT_SHARE = "direct_share";
private static final String SHORTCUT_TARGET = "shortcut_target";
- private static final String PLURALS_COUNT = "count";
- private static final String PLURALS_FILE_NAME = "file_name";
-
- private static final String IMAGE_EDITOR_SHARED_ELEMENT = "screenshot_preview_image";
-
// TODO: these data structures are for one-time use in shuttling data from where they're
// populated in `ShortcutToChooserTargetConverter` to where they're consumed in
// `ShortcutSelectionLogic` which packs the appropriate elements into the final `TargetInfo`.
@@ -180,18 +173,6 @@ public class ChooserActivity extends ResolverActivity implements
@Retention(RetentionPolicy.SOURCE)
public @interface ShareTargetType {}
- public static final float DIRECT_SHARE_EXPANSION_RATE = 0.78f;
-
- private static final int DEFAULT_SALT_EXPIRATION_DAYS = 7;
- private final int mMaxHashSaltDays = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.HASH_SALT_MAX_DAYS,
- DEFAULT_SALT_EXPIRATION_DAYS);
-
- private static final int URI_PERMISSION_INTENT_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
- | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
- | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
-
private ChooserIntegratedDeviceComponents mIntegratedDeviceComponents;
/* TODO: this is `nullable` because we have to defer the assignment til onCreate(). We make the
@@ -248,6 +229,7 @@ public class ChooserActivity extends ResolverActivity implements
@Override
protected void onCreate(Bundle savedInstanceState) {
+ Tracer.INSTANCE.markLaunched();
final long intentReceivedTime = System.currentTimeMillis();
mLatencyTracker.onActionStart(ACTION_LOAD_SHARE_SHEET);
@@ -261,7 +243,6 @@ public class ChooserActivity extends ResolverActivity implements
getIntent(),
getReferrerPackageName(),
getReferrer(),
- mIntegratedDeviceComponents,
mFeatureFlagRepository);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Caller provided invalid Chooser request parameters", e);
@@ -270,28 +251,37 @@ public class ChooserActivity extends ResolverActivity implements
return;
}
- mRefinementManager = new ChooserRefinementManager(
- this,
- mChooserRequest.getRefinementIntentSender(),
- (validatedRefinedTarget) -> {
- maybeRemoveSharedText(validatedRefinedTarget);
- if (super.onTargetSelected(validatedRefinedTarget, false)) {
- finish();
- }
- },
- () -> {
- mRefinementManager.destroy();
- finish();
- });
+ mRefinementManager = new ViewModelProvider(this).get(ChooserRefinementManager.class);
+
+ mRefinementManager.getRefinementCompletion().observe(this, completion -> {
+ if (completion.consume()) {
+ TargetInfo targetInfo = completion.getTargetInfo();
+ // targetInfo is non-null if the refinement process was successful.
+ if (targetInfo != null) {
+ maybeRemoveSharedText(targetInfo);
+
+ // We already block suspended targets from going to refinement, and we probably
+ // can't recover a Chooser session if that's the reason the refined target fails
+ // to launch now. Fire-and-forget the refined launch; ignore the return value
+ // and just make sure the Sharesheet session gets cleaned up regardless.
+ ChooserActivity.super.onTargetSelected(targetInfo, false);
+ }
+ finish();
+ }
+ });
+
+ BasePreviewViewModel previewViewModel =
+ new ViewModelProvider(this, createPreviewViewModelFactory())
+ .get(BasePreviewViewModel.class);
mChooserContentPreviewUi = new ChooserContentPreviewUi(
+ getLifecycle(),
+ previewViewModel.createOrReuseProvider(mChooserRequest),
mChooserRequest.getTargetIntent(),
- getContentResolver(),
- this::isImageType,
- createPreviewImageLoader(),
+ previewViewModel.createOrReuseImageLoader(),
createChooserActionFactory(),
mEnterTransitionAnimationDelegate,
- mFeatureFlagRepository);
+ new HeadlineGeneratorImpl(this));
setAdditionalTargets(mChooserRequest.getAdditionalTargets());
@@ -318,7 +308,8 @@ public class ChooserActivity extends ResolverActivity implements
mChooserRequest.getDefaultTitleResource(),
mChooserRequest.getInitialIntents(),
/* rList: List<ResolveInfo> = */ null,
- /* supportsAlwaysUseOption = */ false);
+ /* supportsAlwaysUseOption = */ false,
+ new DefaultTargetDataLoader(this, getLifecycle(), false));
mChooserShownTime = System.currentTimeMillis();
final long systemCost = mChooserShownTime - intentReceivedTime;
@@ -328,26 +319,10 @@ public class ChooserActivity extends ResolverActivity implements
if (mResolverDrawerLayout != null) {
mResolverDrawerLayout.addOnLayoutChangeListener(this::handleLayoutChange);
- // expand/shrink direct share 4 -> 8 viewgroup
- if (mChooserRequest.isSendActionTarget()) {
- mResolverDrawerLayout.setOnScrollChangeListener(this::handleScroll);
- }
-
mResolverDrawerLayout.setOnCollapsedChangedListener(
- new ResolverDrawerLayout.OnCollapsedChangedListener() {
-
- // Only consider one expansion per activity creation
- private boolean mWrittenOnce = false;
-
- @Override
- public void onCollapsedChanged(boolean isCollapsed) {
- if (!isCollapsed && !mWrittenOnce) {
- incrementNumSheetExpansions();
- mWrittenOnce = true;
- }
- getChooserActivityLogger()
- .logSharesheetExpansionChanged(isCollapsed);
- }
+ isCollapsed -> {
+ mChooserMultiProfilePagerAdapter.setIsCollapsed(isCollapsed);
+ getChooserActivityLogger().logSharesheetExpansionChanged(isCollapsed);
});
}
@@ -388,7 +363,10 @@ public class ChooserActivity extends ResolverActivity implements
private void createProfileRecords(
AppPredictorFactory factory, IntentFilter targetIntentFilter) {
UserHandle mainUserHandle = getPersonalProfileUserHandle();
- createProfileRecord(mainUserHandle, targetIntentFilter, factory);
+ ProfileRecord record = createProfileRecord(mainUserHandle, targetIntentFilter, factory);
+ if (record.shortcutLoader == null) {
+ Tracer.INSTANCE.endLaunchToShortcutTrace();
+ }
UserHandle workUserHandle = getWorkProfileUserHandle();
if (workUserHandle != null) {
@@ -396,7 +374,7 @@ public class ChooserActivity extends ResolverActivity implements
}
}
- private void createProfileRecord(
+ private ProfileRecord createProfileRecord(
UserHandle userHandle, IntentFilter targetIntentFilter, AppPredictorFactory factory) {
AppPredictor appPredictor = factory.create(userHandle);
ShortcutLoader shortcutLoader = ActivityManager.isLowRamDeviceStatic()
@@ -407,9 +385,9 @@ public class ChooserActivity extends ResolverActivity implements
userHandle,
targetIntentFilter,
shortcutsResult -> onShortcutsLoaded(userHandle, shortcutsResult));
- mProfileRecords.put(
- userHandle.getIdentifier(),
- new ProfileRecord(appPredictor, shortcutLoader));
+ ProfileRecord record = new ProfileRecord(appPredictor, shortcutLoader);
+ mProfileRecords.put(userHandle.getIdentifier(), record);
+ return record;
}
@Nullable
@@ -426,6 +404,7 @@ public class ChooserActivity extends ResolverActivity implements
Consumer<ShortcutLoader.Result> callback) {
return new ShortcutLoader(
context,
+ getLifecycle(),
appPredictor,
userHandle,
targetIntentFilter,
@@ -452,13 +431,14 @@ public class ChooserActivity extends ResolverActivity implements
protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter(
Intent[] initialIntents,
List<ResolveInfo> rList,
- boolean filterLastUsed) {
+ boolean filterLastUsed,
+ TargetDataLoader targetDataLoader) {
if (shouldShowTabs()) {
mChooserMultiProfilePagerAdapter = createChooserMultiProfilePagerAdapterForTwoProfiles(
- initialIntents, rList, filterLastUsed);
+ initialIntents, rList, filterLastUsed, targetDataLoader);
} else {
mChooserMultiProfilePagerAdapter = createChooserMultiProfilePagerAdapterForOneProfile(
- initialIntents, rList, filterLastUsed);
+ initialIntents, rList, filterLastUsed, targetDataLoader);
}
return mChooserMultiProfilePagerAdapter;
}
@@ -495,33 +475,37 @@ public class ChooserActivity extends ResolverActivity implements
return new NoCrossProfileEmptyStateProvider(getPersonalProfileUserHandle(),
noWorkToPersonalEmptyState, noPersonalToWorkEmptyState,
- createCrossProfileIntentsChecker(), createMyUserIdProvider());
+ createCrossProfileIntentsChecker(), getTabOwnerUserHandleForLaunch());
}
private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForOneProfile(
Intent[] initialIntents,
List<ResolveInfo> rList,
- boolean filterLastUsed) {
+ boolean filterLastUsed,
+ TargetDataLoader targetDataLoader) {
ChooserGridAdapter adapter = createChooserGridAdapter(
/* context */ this,
/* payloadIntents */ mIntents,
initialIntents,
rList,
filterLastUsed,
- /* userHandle */ UserHandle.of(UserHandle.myUserId()));
+ /* userHandle */ getPersonalProfileUserHandle(),
+ targetDataLoader);
return new ChooserMultiProfilePagerAdapter(
/* context */ this,
adapter,
createEmptyStateProvider(/* workProfileUserHandle= */ null),
/* workProfileQuietModeChecker= */ () -> false,
/* workProfileUserHandle= */ null,
+ getCloneProfileUserHandle(),
mMaxTargetsPerRow);
}
private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles(
Intent[] initialIntents,
List<ResolveInfo> rList,
- boolean filterLastUsed) {
+ boolean filterLastUsed,
+ TargetDataLoader targetDataLoader) {
int selectedProfile = findSelectedProfile();
ChooserGridAdapter personalAdapter = createChooserGridAdapter(
/* context */ this,
@@ -529,14 +513,16 @@ public class ChooserActivity extends ResolverActivity implements
selectedProfile == PROFILE_PERSONAL ? initialIntents : null,
rList,
filterLastUsed,
- /* userHandle */ getPersonalProfileUserHandle());
+ /* userHandle */ getPersonalProfileUserHandle(),
+ targetDataLoader);
ChooserGridAdapter workAdapter = createChooserGridAdapter(
/* context */ this,
/* payloadIntents */ mIntents,
selectedProfile == PROFILE_WORK ? initialIntents : null,
rList,
filterLastUsed,
- /* userHandle */ getWorkProfileUserHandle());
+ /* userHandle */ getWorkProfileUserHandle(),
+ targetDataLoader);
return new ChooserMultiProfilePagerAdapter(
/* context */ this,
personalAdapter,
@@ -545,13 +531,14 @@ public class ChooserActivity extends ResolverActivity implements
() -> mWorkProfileAvailability.isQuietModeEnabled(),
selectedProfile,
getWorkProfileUserHandle(),
+ getCloneProfileUserHandle(),
mMaxTargetsPerRow);
}
private int findSelectedProfile() {
int selectedProfile = getSelectedProfileExtra();
if (selectedProfile == -1) {
- selectedProfile = getProfileForUser(getUser());
+ selectedProfile = getProfileForUser(getTabOwnerUserHandleForLaunch());
}
return selectedProfile;
}
@@ -604,21 +591,32 @@ public class ChooserActivity extends ResolverActivity implements
// Refresh pinned items
mPinnedSharedPrefs = getPinnedSharedPrefs(this);
if (listAdapter == null) {
- mChooserMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
+ handlePackageChangePerProfile(mChooserMultiProfilePagerAdapter.getActiveListAdapter());
if (mChooserMultiProfilePagerAdapter.getCount() > 1) {
- mChooserMultiProfilePagerAdapter.getInactiveListAdapter().handlePackagesChanged();
+ handlePackageChangePerProfile(
+ mChooserMultiProfilePagerAdapter.getInactiveListAdapter());
}
} else {
- listAdapter.handlePackagesChanged();
+ handlePackageChangePerProfile(listAdapter);
}
updateProfileViewButton();
}
+ private void handlePackageChangePerProfile(ResolverListAdapter adapter) {
+ ProfileRecord record = getProfileRecord(adapter.getUserHandle());
+ if (record != null && record.shortcutLoader != null) {
+ record.shortcutLoader.reset();
+ }
+ adapter.handlePackagesChanged();
+ }
+
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume: " + getComponentName().flattenToShortString());
maybeCancelFinishAnimation();
+
+ mRefinementManager.onActivityResume();
}
@Override
@@ -652,8 +650,6 @@ public class ChooserActivity extends ResolverActivity implements
parent = parent == null ? getWindow().getDecorView() : parent;
- updateLayoutWidth(com.android.internal.R.id.content_preview_text_layout, width, parent);
- updateLayoutWidth(com.android.internal.R.id.content_preview_title_layout, width, parent);
updateLayoutWidth(com.android.internal.R.id.content_preview_file_layout, width, parent);
}
@@ -700,8 +696,10 @@ public class ChooserActivity extends ResolverActivity implements
@Nullable
private View getFirstVisibleImgPreviewView() {
- View firstImage = findViewById(com.android.internal.R.id.content_preview_image_1_large);
- return firstImage != null && firstImage.isVisibleToUser() ? firstImage : null;
+ View imagePreview = findViewById(R.id.scrollable_image_preview);
+ return imagePreview instanceof ImagePreviewView
+ ? ((ImagePreviewView) imagePreview).getTransitionView()
+ : null;
}
/**
@@ -713,23 +711,11 @@ public class ChooserActivity extends ResolverActivity implements
return resolver.query(uri, null, null, null, null);
}
- @VisibleForTesting
- protected boolean isImageType(String mimeType) {
- return mimeType != null && mimeType.startsWith("image/");
- }
-
- private int getNumSheetExpansions() {
- return getPreferences(Context.MODE_PRIVATE).getInt(PREF_NUM_SHEET_EXPANSIONS, 0);
- }
-
- private void incrementNumSheetExpansions() {
- getPreferences(Context.MODE_PRIVATE).edit().putInt(PREF_NUM_SHEET_EXPANSIONS,
- getNumSheetExpansions() + 1).apply();
- }
-
@Override
protected void onStop() {
super.onStop();
+ mRefinementManager.onActivityStop(isChangingConfigurations());
+
if (maybeCancelFinishAnimation()) {
finish();
}
@@ -743,11 +729,6 @@ public class ChooserActivity extends ResolverActivity implements
mLatencyTracker.onActionCancel(ACTION_LOAD_SHARE_SHEET);
}
- if (mRefinementManager != null) { // TODO: null-checked in case of early-destroy, or skip?
- mRefinementManager.destroy();
- mRefinementManager = null;
- }
-
mBackgroundThreadPoolExecutor.shutdownNow();
destroyProfileRecords();
@@ -805,15 +786,20 @@ public class ChooserActivity extends ResolverActivity implements
}
}
- @Override
- public void addUseDifferentAppLabelIfNecessary(ResolverListAdapter adapter) {
- if (mChooserRequest.getCallerChooserTargets().size() > 0) {
- mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults(
- /* origTarget */ null,
- new ArrayList<>(mChooserRequest.getCallerChooserTargets()),
- TARGET_TYPE_DEFAULT,
- /* directShareShortcutInfoCache */ Collections.emptyMap(),
- /* directShareAppTargetCache */ Collections.emptyMap());
+ private void addCallerChooserTargets() {
+ if (!mChooserRequest.getCallerChooserTargets().isEmpty()) {
+ // Send the caller's chooser targets only to the default profile.
+ UserHandle defaultUser = (findSelectedProfile() == PROFILE_WORK)
+ ? getAnnotatedUserHandles().workProfileUserHandle
+ : getAnnotatedUserHandles().personalProfileUserHandle;
+ if (mChooserMultiProfilePagerAdapter.getCurrentUserHandle() == defaultUser) {
+ mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults(
+ /* origTarget */ null,
+ new ArrayList<>(mChooserRequest.getCallerChooserTargets()),
+ TARGET_TYPE_DEFAULT,
+ /* directShareShortcutInfoCache */ Collections.emptyMap(),
+ /* directShareAppTargetCache */ Collections.emptyMap());
+ }
}
}
@@ -860,7 +846,11 @@ public class ChooserActivity extends ResolverActivity implements
ChooserTargetActionsDialogFragment.show(
getSupportFragmentManager(),
targetList,
- mChooserMultiProfilePagerAdapter.getCurrentUserHandle(),
+ // Adding userHandle from ResolveInfo allows the app icon in Dialog Box to be
+ // resolved correctly within the same tab.
+ getResolveInfoUserHandle(
+ targetInfo.getResolveInfo(),
+ mChooserMultiProfilePagerAdapter.getCurrentUserHandle()),
shortcutIdKey,
shortcutTitle,
isShortcutPinned,
@@ -869,7 +859,11 @@ public class ChooserActivity extends ResolverActivity implements
@Override
protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
- if (mRefinementManager.maybeHandleSelection(target)) {
+ if (mRefinementManager.maybeHandleSelection(
+ target,
+ mChooserRequest.getRefinementIntentSender(),
+ getApplication(),
+ getMainThreadHandler())) {
return false;
}
updateModelAndChooserCounts(target);
@@ -892,11 +886,14 @@ public class ChooserActivity extends ResolverActivity implements
if (targetInfo.isMultiDisplayResolveInfo()) {
MultiDisplayResolveInfo mti = (MultiDisplayResolveInfo) targetInfo;
if (!mti.hasSelected()) {
+ // Add userHandle based badge to the stackedAppDialogBox.
ChooserStackedAppDialogFragment.show(
getSupportFragmentManager(),
mti,
which,
- mChooserMultiProfilePagerAdapter.getCurrentUserHandle());
+ getResolveInfoUserHandle(
+ targetInfo.getResolveInfo(),
+ mChooserMultiProfilePagerAdapter.getCurrentUserHandle()));
return;
}
}
@@ -1008,9 +1005,11 @@ public class ChooserActivity extends ResolverActivity implements
mChooserMultiProfilePagerAdapter.getActiveListAdapter();
if (currentListAdapter != null) {
sendImpressionToAppPredictor(info, currentListAdapter);
- currentListAdapter.updateModel(info.getResolvedComponentName());
- currentListAdapter.updateChooserCounts(ri.activityInfo.packageName,
- targetIntent.getAction());
+ currentListAdapter.updateModel(info);
+ currentListAdapter.updateChooserCounts(
+ ri.activityInfo.packageName,
+ targetIntent.getAction(),
+ ri.userHandle);
}
if (DEBUG) {
Log.d(TAG, "ResolveInfo Package is " + ri.activityInfo.packageName);
@@ -1096,22 +1095,33 @@ public class ChooserActivity extends ResolverActivity implements
@Nullable
private AppPredictor getAppPredictor(UserHandle userHandle) {
ProfileRecord record = getProfileRecord(userHandle);
- return (record == null) ? null : record.appPredictor;
+ // We cannot use APS service when clone profile is present as APS service cannot sort
+ // cross profile targets as of now.
+ return (record == null || getCloneProfileUserHandle() != null) ? null : record.appPredictor;
}
/**
* Sort intents alphabetically based on display label.
*/
static class AzInfoComparator implements Comparator<DisplayResolveInfo> {
- Collator mCollator;
+ Comparator<DisplayResolveInfo> mComparator;
AzInfoComparator(Context context) {
- mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
+ Collator collator = Collator
+ .getInstance(context.getResources().getConfiguration().locale);
+ // Adding two stage comparator, first stage compares using displayLabel, next stage
+ // compares using resolveInfo.userHandle
+ mComparator = Comparator.comparing(DisplayResolveInfo::getDisplayLabel, collator)
+ .thenComparingInt(displayResolveInfo ->
+ getResolveInfoUserHandle(
+ displayResolveInfo.getResolveInfo(),
+ // TODO: User resolveInfo.userHandle, once its available.
+ UserHandle.SYSTEM).getIdentifier());
}
@Override
public int compare(
DisplayResolveInfo lhsp, DisplayResolveInfo rhsp) {
- return mCollator.compare(lhsp.getDisplayLabel(), rhsp.getDisplayLabel());
+ return mComparator.compare(lhsp, rhsp);
}
}
@@ -1129,14 +1139,16 @@ public class ChooserActivity extends ResolverActivity implements
Intent targetIntent,
String referrerPackageName,
int launchedFromUid,
- AbstractResolverComparator resolverComparator) {
+ AbstractResolverComparator resolverComparator,
+ UserHandle queryIntentsAsUser) {
super(
context,
pm,
targetIntent,
referrerPackageName,
launchedFromUid,
- resolverComparator);
+ resolverComparator,
+ queryIntentsAsUser);
}
@Override
@@ -1157,7 +1169,8 @@ public class ChooserActivity extends ResolverActivity implements
Intent[] initialIntents,
List<ResolveInfo> rList,
boolean filterLastUsed,
- UserHandle userHandle) {
+ UserHandle userHandle,
+ TargetDataLoader targetDataLoader) {
ChooserListAdapter chooserListAdapter = createChooserListAdapter(
context,
payloadIntents,
@@ -1168,7 +1181,8 @@ public class ChooserActivity extends ResolverActivity implements
userHandle,
getTargetIntent(),
mChooserRequest,
- mMaxTargetsPerRow);
+ mMaxTargetsPerRow,
+ targetDataLoader);
return new ChooserGridAdapter(
context,
@@ -1208,39 +1222,10 @@ public class ChooserActivity extends ResolverActivity implements
mProfileView.setOnClickListener(ChooserActivity.this::onProfileClick);
ChooserActivity.this.updateProfileViewButton();
}
-
- @Override
- public int getValidTargetCount() {
- return mChooserMultiProfilePagerAdapter
- .getActiveListAdapter()
- .getSelectableServiceTargetCount();
- }
-
- @Override
- public void updateDirectShareExpansion(DirectShareViewHolder directShareGroup) {
- RecyclerView activeAdapterView =
- mChooserMultiProfilePagerAdapter.getActiveAdapterView();
- if (mResolverDrawerLayout.isCollapsed()) {
- directShareGroup.collapse(activeAdapterView);
- } else {
- directShareGroup.expand(activeAdapterView);
- }
- }
-
- @Override
- public void handleScrollToExpandDirectShare(
- DirectShareViewHolder directShareGroup, int y, int oldy) {
- directShareGroup.handleScroll(
- mChooserMultiProfilePagerAdapter.getActiveAdapterView(),
- y,
- oldy,
- mMaxTargetsPerRow);
- }
},
chooserListAdapter,
shouldShowContentPreview(),
- mMaxTargetsPerRow,
- getNumSheetExpansions());
+ mMaxTargetsPerRow);
}
@VisibleForTesting
@@ -1254,21 +1239,37 @@ public class ChooserActivity extends ResolverActivity implements
UserHandle userHandle,
Intent targetIntent,
ChooserRequestParameters chooserRequest,
- int maxTargetsPerRow) {
+ int maxTargetsPerRow,
+ TargetDataLoader targetDataLoader) {
+ UserHandle initialIntentsUserSpace = isLaunchedAsCloneProfile()
+ && userHandle.equals(getPersonalProfileUserHandle())
+ ? getCloneProfileUserHandle() : userHandle;
return new ChooserListAdapter(
context,
payloadIntents,
initialIntents,
rList,
filterLastUsed,
- resolverListController,
+ createListController(userHandle),
userHandle,
targetIntent,
this,
context.getPackageManager(),
getChooserActivityLogger(),
chooserRequest,
- maxTargetsPerRow);
+ maxTargetsPerRow,
+ initialIntentsUserSpace,
+ targetDataLoader);
+ }
+
+ @Override
+ protected void onWorkProfileStatusUpdated() {
+ UserHandle workUser = getWorkProfileUserHandle();
+ ProfileRecord record = workUser == null ? null : getProfileRecord(workUser);
+ if (record != null && record.shortcutLoader != null) {
+ record.shortcutLoader.reset();
+ }
+ super.onWorkProfileStatusUpdated();
}
@Override
@@ -1278,11 +1279,18 @@ public class ChooserActivity extends ResolverActivity implements
AbstractResolverComparator resolverComparator;
if (appPredictor != null) {
resolverComparator = new AppPredictionServiceResolverComparator(this, getTargetIntent(),
- getReferrerPackageName(), appPredictor, userHandle, getChooserActivityLogger());
+ getReferrerPackageName(), appPredictor, userHandle, getChooserActivityLogger(),
+ getIntegratedDeviceComponents().getNearbySharingComponent());
} else {
resolverComparator =
- new ResolverRankerServiceResolverComparator(this, getTargetIntent(),
- getReferrerPackageName(), null, getChooserActivityLogger());
+ new ResolverRankerServiceResolverComparator(
+ this,
+ getTargetIntent(),
+ getReferrerPackageName(),
+ null,
+ getChooserActivityLogger(),
+ getResolverRankerServiceUserHandleList(userHandle),
+ getIntegratedDeviceComponents().getNearbySharingComponent());
}
return new ChooserListController(
@@ -1291,27 +1299,19 @@ public class ChooserActivity extends ResolverActivity implements
getTargetIntent(),
getReferrerPackageName(),
getAnnotatedUserHandles().userIdOfCallingApp,
- resolverComparator);
+ resolverComparator,
+ getQueryIntentsUser(userHandle));
}
@VisibleForTesting
- protected ImageLoader createPreviewImageLoader() {
- final int cacheSize;
- if (mFeatureFlagRepository.isEnabled(Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW)) {
- float chooserWidth = getResources().getDimension(R.dimen.chooser_width);
- float imageWidth = getResources().getDimension(R.dimen.chooser_preview_image_width);
- cacheSize = (int) (Math.ceil(chooserWidth / imageWidth) + 2);
- } else {
- cacheSize = 3;
- }
- return new ImagePreviewImageLoader(this, getLifecycle(), cacheSize);
+ protected ViewModelProvider.Factory createPreviewViewModelFactory() {
+ return PreviewViewModel.Companion.getFactory();
}
private ChooserActionFactory createChooserActionFactory() {
return new ChooserActionFactory(
this,
mChooserRequest,
- mFeatureFlagRepository,
mIntegratedDeviceComponents,
getChooserActivityLogger(),
(isExcluded) -> mExcludeSharedText = isExcluded,
@@ -1341,12 +1341,6 @@ public class ChooserActivity extends ResolverActivity implements
});
}
- private void handleScroll(View view, int x, int y, int oldx, int oldy) {
- if (mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() != null) {
- mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().handleScroll(view, y, oldy);
- }
- }
-
/*
* Need to dynamically adjust how many icons can fit per row before we add them,
* which also means setting the correct offset to initially show the content
@@ -1415,9 +1409,7 @@ public class ChooserActivity extends ResolverActivity implements
private int calculateDrawerOffset(
int top, int bottom, RecyclerView recyclerView, ChooserGridAdapter gridAdapter) {
- final int bottomInset = mSystemWindowInsets != null
- ? mSystemWindowInsets.bottom : 0;
- int offset = bottomInset;
+ int offset = mSystemWindowInsets != null ? mSystemWindowInsets.bottom : 0;
int rowsToShow = gridAdapter.getSystemRowCount()
+ gridAdapter.getProfileRowCount()
+ gridAdapter.getServiceTargetRowCount()
@@ -1447,7 +1439,6 @@ public class ChooserActivity extends ResolverActivity implements
}
if (recyclerView.getVisibility() == View.VISIBLE) {
- int directShareHeight = 0;
rowsToShow = Math.min(4, rowsToShow);
boolean shouldShowExtraRow = shouldShowExtraRow(rowsToShow);
mLastNumberOfChildren = recyclerView.getChildCount();
@@ -1463,28 +1454,8 @@ public class ChooserActivity extends ResolverActivity implements
if (shouldShowExtraRow) {
offset += height;
}
-
- if (gridAdapter.getTargetType(
- recyclerView.getChildAdapterPosition(child))
- == ChooserListAdapter.TARGET_SERVICE) {
- directShareHeight = height;
- }
rowsToShow--;
}
-
- boolean isExpandable = getResources().getConfiguration().orientation
- == Configuration.ORIENTATION_PORTRAIT && !isInMultiWindowMode();
- if (directShareHeight != 0 && shouldShowContentPreview()
- && isExpandable) {
- // make sure to leave room for direct share 4->8 expansion
- int requiredExpansionHeight =
- (int) (directShareHeight / DIRECT_SHARE_EXPANSION_RATE);
- int topInset = mSystemWindowInsets != null ? mSystemWindowInsets.top : 0;
- int minHeight = bottom - top - mResolverDrawerLayout.getAlwaysShowHeight()
- - requiredExpansionHeight - topInset - bottomInset;
-
- offset = Math.min(offset, minHeight);
- }
} else {
ViewGroup currentEmptyStateView = getActiveEmptyStateView();
if (currentEmptyStateView.getVisibility() == View.VISIBLE) {
@@ -1508,17 +1479,16 @@ public class ChooserActivity extends ResolverActivity implements
}
/**
- * Returns {@link #PROFILE_PERSONAL}, {@link #PROFILE_WORK}, or -1 if the given user handle
- * does not match either the personal or work user handle.
+ * Returns {@link #PROFILE_WORK}, if the given user handle matches work user handle.
+ * Returns {@link #PROFILE_PERSONAL}, otherwise.
**/
private int getProfileForUser(UserHandle currentUserHandle) {
- if (currentUserHandle.equals(getPersonalProfileUserHandle())) {
- return PROFILE_PERSONAL;
- } else if (currentUserHandle.equals(getWorkProfileUserHandle())) {
+ if (currentUserHandle.equals(getWorkProfileUserHandle())) {
return PROFILE_WORK;
}
- Log.e(TAG, "User " + currentUserHandle + " does not belong to a personal or work profile.");
- return -1;
+ // We return personal profile, as it is the default when there is no work profile, personal
+ // profile represents rootUser, clonedUser & secondaryUser, covering all use cases.
+ return PROFILE_PERSONAL;
}
private ViewGroup getActiveEmptyStateView() {
@@ -1553,6 +1523,11 @@ public class ChooserActivity extends ResolverActivity implements
}
if (rebuildComplete) {
+ long duration = Tracer.INSTANCE.endAppTargetLoadingSection(listAdapter.getUserHandle());
+ if (duration >= 0) {
+ Log.d(TAG, "app target loading time " + duration + " ms");
+ }
+ addCallerChooserTargets();
getChooserActivityLogger().logSharesheetAppLoadComplete();
maybeQueryAdditionalPostProcessingTargets(chooserListAdapter);
mLatencyTracker.onActionEnd(ACTION_LOAD_SHARE_SHEET);
@@ -1562,14 +1537,11 @@ public class ChooserActivity extends ResolverActivity implements
private void maybeQueryAdditionalPostProcessingTargets(ChooserListAdapter chooserListAdapter) {
UserHandle userHandle = chooserListAdapter.getUserHandle();
ProfileRecord record = getProfileRecord(userHandle);
- if (record == null) {
- return;
- }
- if (record.shortcutLoader == null) {
+ if (record == null || record.shortcutLoader == null) {
return;
}
record.loadingStartTime = SystemClock.elapsedRealtime();
- record.shortcutLoader.queryShortcuts(chooserListAdapter.getDisplayResolveInfos());
+ record.shortcutLoader.updateAppTargets(chooserListAdapter.getDisplayResolveInfos());
}
@MainThread
@@ -1595,6 +1567,12 @@ public class ChooserActivity extends ResolverActivity implements
adapter.completeServiceTargetLoading();
}
+ if (mMultiProfilePagerAdapter.getActiveListAdapter() == adapter) {
+ long duration = Tracer.INSTANCE.endLaunchToShortcutTrace();
+ if (duration >= 0) {
+ Log.d(TAG, "stat to first shortcut time: " + duration + " ms");
+ }
+ }
logDirectShareTargetReceived(userHandle);
sendVoiceChoicesIfNeeded();
getChooserActivityLogger().logSharesheetDirectLoadComplete();
@@ -1667,8 +1645,7 @@ public class ChooserActivity extends ResolverActivity implements
* we instead show the content preview as a regular list item.
*/
private boolean shouldShowStickyContentPreview() {
- return shouldShowStickyContentPreviewNoOrientationCheck()
- && !getResources().getBoolean(R.bool.resolver_landscape_phone);
+ return shouldShowStickyContentPreviewNoOrientationCheck();
}
private boolean shouldShowStickyContentPreviewNoOrientationCheck() {
@@ -1785,9 +1762,6 @@ public class ChooserActivity extends ResolverActivity implements
@Override
protected void onProfileTabSelected() {
- ChooserGridAdapter currentRootAdapter =
- mChooserMultiProfilePagerAdapter.getCurrentRootAdapter();
- currentRootAdapter.updateDirectShareExpansion();
// This fixes an edge case where after performing a variety of gestures, vertical scrolling
// ends up disabled. That's because at some point the old tab's vertical scrolling is
// disabled and the new tab's is enabled. For context, see b/159997845
@@ -1929,9 +1903,6 @@ public class ChooserActivity extends ResolverActivity implements
}
public void destroy() {
- if (shortcutLoader != null) {
- shortcutLoader.destroy();
- }
if (appPredictor != null) {
appPredictor.destroy();
}
diff --git a/java/src/com/android/intentresolver/ChooserActivityReEnabler.kt b/java/src/com/android/intentresolver/ChooserActivityReEnabler.kt
new file mode 100644
index 00000000..3236c1be
--- /dev/null
+++ b/java/src/com/android/intentresolver/ChooserActivityReEnabler.kt
@@ -0,0 +1,39 @@
+package com.android.intentresolver
+
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+
+/**
+ * Ensures that the unbundled version of [ChooserActivity] does not get stuck in a disabled state.
+ */
+class ChooserActivityReEnabler : BroadcastReceiver() {
+
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
+ context.packageManager.setComponentEnabledSetting(
+ CHOOSER_COMPONENT,
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+ /* flags = */ 0,
+ )
+
+ // This only needs to be run once, so we disable ourself to avoid additional startup
+ // process on future boots
+ context.packageManager.setComponentEnabledSetting(
+ SELF_COMPONENT,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ /* flags = */ 0,
+ )
+ }
+ }
+
+ companion object {
+ private const val CHOOSER_PACKAGE = "com.android.intentresolver"
+ private val CHOOSER_COMPONENT =
+ ComponentName(CHOOSER_PACKAGE, "$CHOOSER_PACKAGE.ChooserActivity")
+ private val SELF_COMPONENT =
+ ComponentName(CHOOSER_PACKAGE, "$CHOOSER_PACKAGE.ChooserActivityReEnabler")
+ }
+}
diff --git a/java/src/com/android/intentresolver/ChooserListAdapter.java b/java/src/com/android/intentresolver/ChooserListAdapter.java
index f0651360..b1fa16b0 100644
--- a/java/src/com/android/intentresolver/ChooserListAdapter.java
+++ b/java/src/com/android/intentresolver/ChooserListAdapter.java
@@ -27,14 +27,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.LabeledIntent;
-import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
import android.os.AsyncTask;
import android.os.Trace;
import android.os.UserHandle;
@@ -47,20 +43,20 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-import androidx.annotation.WorkerThread;
-
import com.android.intentresolver.chooser.DisplayResolveInfo;
import com.android.intentresolver.chooser.MultiDisplayResolveInfo;
import com.android.intentresolver.chooser.NotSelectableTargetInfo;
import com.android.intentresolver.chooser.SelectableTargetInfo;
import com.android.intentresolver.chooser.TargetInfo;
+import com.android.intentresolver.icons.TargetDataLoader;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
public class ChooserListAdapter extends ResolverListAdapter {
@@ -86,10 +82,11 @@ public class ChooserListAdapter extends ResolverListAdapter {
private final ChooserActivityLogger mChooserActivityLogger;
- private final Map<TargetInfo, AsyncTask> mIconLoaders = new HashMap<>();
+ private final Set<TargetInfo> mRequestedIcons = new HashSet<>();
// Reserve spots for incoming direct share targets by adding placeholders
private final TargetInfo mPlaceHolderTargetInfo;
+ private final TargetDataLoader mTargetDataLoader;
private final List<TargetInfo> mServiceTargets = new ArrayList<>();
private final List<DisplayResolveInfo> mCallerTargets = new ArrayList<>();
@@ -98,6 +95,8 @@ public class ChooserListAdapter extends ResolverListAdapter {
// Sorted list of DisplayResolveInfos for the alphabetical app section.
private List<DisplayResolveInfo> mSortedList = new ArrayList<>();
+ private final ItemRevealAnimationTracker mAnimationTracker = new ItemRevealAnimationTracker();
+
// For pinned direct share labels, if the text spans multiple lines, the TextView will consume
// the full width, even if the characters actually take up less than that. Measure the actual
// line widths and constrain the View's width based upon that so that the pin doesn't end up
@@ -142,7 +141,9 @@ public class ChooserListAdapter extends ResolverListAdapter {
PackageManager packageManager,
ChooserActivityLogger chooserActivityLogger,
ChooserRequestParameters chooserRequest,
- int maxRankedTargets) {
+ int maxRankedTargets,
+ UserHandle initialIntentsUserSpace,
+ TargetDataLoader targetDataLoader) {
// Don't send the initial intents through the shared ResolverActivity path,
// we want to separate them into a different section.
super(
@@ -155,12 +156,14 @@ public class ChooserListAdapter extends ResolverListAdapter {
userHandle,
targetIntent,
resolverListCommunicator,
- false);
+ initialIntentsUserSpace,
+ targetDataLoader);
mChooserRequest = chooserRequest;
mMaxRankedTargets = maxRankedTargets;
mPlaceHolderTargetInfo = NotSelectableTargetInfo.newPlaceHolderTargetInfo(context);
+ mTargetDataLoader = targetDataLoader;
createPlaceHolders();
mChooserActivityLogger = chooserActivityLogger;
mShortcutSelectionLogic = new ShortcutSelectionLogic(
@@ -222,8 +225,10 @@ public class ChooserListAdapter extends ResolverListAdapter {
ri.noResourceId = true;
ri.icon = 0;
}
+ ri.userHandle = initialIntentsUserSpace;
+ // TODO: remove DisplayResolveInfo dependency on presentation getter
DisplayResolveInfo displayResolveInfo = DisplayResolveInfo.newDisplayResolveInfo(
- ii, ri, ii, mPresentationFactory.makePresentationGetter(ri));
+ ii, ri, ii, mTargetDataLoader.createPresentationGetter(ri));
mCallerTargets.add(displayResolveInfo);
if (mCallerTargets.size() == MAX_SUGGESTED_APP_TARGETS) break;
}
@@ -240,6 +245,15 @@ public class ChooserListAdapter extends ResolverListAdapter {
}
+ @Override
+ protected boolean rebuildList(boolean doPostProcessing) {
+ mAnimationTracker.reset();
+ mSortedList.clear();
+ boolean result = super.rebuildList(doPostProcessing);
+ notifyDataSetChanged();
+ return result;
+ }
+
private void createPlaceHolders() {
mServiceTargets.clear();
for (int i = 0; i < mMaxRankedTargets; ++i) {
@@ -262,8 +276,18 @@ public class ChooserListAdapter extends ResolverListAdapter {
return;
}
- holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo(), alwaysShowSubLabel());
- holder.bindIcon(info, /*animate =*/ true);
+ holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo());
+ mAnimationTracker.animateLabel(holder.text, info);
+ if (holder.text2.getVisibility() == View.VISIBLE) {
+ mAnimationTracker.animateLabel(holder.text2, info);
+ }
+ holder.bindIcon(info);
+ if (info.getDisplayIconHolder().getDisplayIcon() != null) {
+ mAnimationTracker.animateIcon(holder.icon, info);
+ } else {
+ holder.icon.clearAnimation();
+ }
+
if (info.isSelectableTargetInfo()) {
// direct share targets should append the application name for a better readout
DisplayResolveInfo rInfo = info.getDisplayResolveInfo();
@@ -320,19 +344,19 @@ public class ChooserListAdapter extends ResolverListAdapter {
}
private void loadDirectShareIcon(SelectableTargetInfo info) {
- LoadDirectShareIconTask task = (LoadDirectShareIconTask) mIconLoaders.get(info);
- if (task == null) {
- task = createLoadDirectShareIconTask(info);
- mIconLoaders.put(info, task);
- task.loadIcon();
+ if (mRequestedIcons.add(info)) {
+ mTargetDataLoader.loadDirectShareIcon(
+ info,
+ getUserHandle(),
+ (drawable) -> onDirectShareIconLoaded(info, drawable));
}
}
- @VisibleForTesting
- protected LoadDirectShareIconTask createLoadDirectShareIconTask(SelectableTargetInfo info) {
- return new LoadDirectShareIconTask(
- mContext.createContextAsUser(getUserHandle(), 0),
- info);
+ private void onDirectShareIconLoaded(SelectableTargetInfo mTargetInfo, Drawable icon) {
+ if (icon != null && !mTargetInfo.hasDisplayIcon()) {
+ mTargetInfo.getDisplayIconHolder().setDisplayIcon(icon);
+ notifyDataSetChanged();
+ }
}
void updateAlphabeticalList() {
@@ -341,6 +365,15 @@ public class ChooserListAdapter extends ResolverListAdapter {
new AsyncTask<Void, Void, List<DisplayResolveInfo>>() {
@Override
protected List<DisplayResolveInfo> doInBackground(Void... voids) {
+ try {
+ Trace.beginSection("update-alphabetical-list");
+ return updateList();
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ private List<DisplayResolveInfo> updateList() {
List<DisplayResolveInfo> allTargets = new ArrayList<>();
allTargets.addAll(getTargetsInCurrentDisplayList());
allTargets.addAll(mCallerTargets);
@@ -351,6 +384,8 @@ public class ChooserListAdapter extends ResolverListAdapter {
.collect(Collectors.groupingBy(target ->
target.getResolvedComponentName().getPackageName()
+ "#" + target.getDisplayLabel()
+ + '#' + ResolverActivity.getResolveInfoUserHandle(
+ target.getResolveInfo(), getUserHandle()).getIdentifier()
))
.values()
.stream()
@@ -604,12 +639,6 @@ public class ChooserListAdapter extends ResolverListAdapter {
notifyDataSetChanged();
}
- protected boolean alwaysShowSubLabel() {
- // Always show a subLabel for visual consistency across list items. Show an empty
- // subLabel if the subLabel is the same as the label
- return true;
- }
-
/**
* Rather than fully sorting the input list, this sorting task will put the top k elements
* in the head of input list and fill the tail with other elements in undetermined order.
@@ -640,95 +669,4 @@ public class ChooserListAdapter extends ResolverListAdapter {
};
}
- /**
- * Loads direct share targets icons.
- */
- @VisibleForTesting
- public class LoadDirectShareIconTask extends AsyncTask<Void, Void, Drawable> {
- private final Context mContext;
- private final SelectableTargetInfo mTargetInfo;
-
- private LoadDirectShareIconTask(Context context, SelectableTargetInfo targetInfo) {
- mContext = context;
- mTargetInfo = targetInfo;
- }
-
- @Override
- protected Drawable doInBackground(Void... voids) {
- Drawable drawable;
- try {
- drawable = getChooserTargetIconDrawable(
- mContext,
- mTargetInfo.getChooserTargetIcon(),
- mTargetInfo.getChooserTargetComponentName(),
- mTargetInfo.getDirectShareShortcutInfo());
- } catch (Exception e) {
- Log.e(TAG,
- "Failed to load shortcut icon for "
- + mTargetInfo.getChooserTargetComponentName(),
- e);
- drawable = loadIconPlaceholder();
- }
- return drawable;
- }
-
- @Override
- protected void onPostExecute(@Nullable Drawable icon) {
- if (icon != null && !mTargetInfo.hasDisplayIcon()) {
- mTargetInfo.getDisplayIconHolder().setDisplayIcon(icon);
- notifyDataSetChanged();
- }
- }
-
- @WorkerThread
- private Drawable getChooserTargetIconDrawable(
- Context context,
- @Nullable Icon icon,
- ComponentName targetComponentName,
- @Nullable ShortcutInfo shortcutInfo) {
- Drawable directShareIcon = null;
-
- // First get the target drawable and associated activity info
- if (icon != null) {
- directShareIcon = icon.loadDrawable(context);
- } else if (shortcutInfo != null) {
- LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
- if (launcherApps != null) {
- directShareIcon = launcherApps.getShortcutIconDrawable(shortcutInfo, 0);
- }
- }
-
- if (directShareIcon == null) {
- return null;
- }
-
- ActivityInfo info = null;
- try {
- info = context.getPackageManager().getActivityInfo(targetComponentName, 0);
- } catch (PackageManager.NameNotFoundException error) {
- Log.e(TAG, "Could not find activity associated with ChooserTarget");
- }
-
- if (info == null) {
- return null;
- }
-
- // Now fetch app icon and raster with no badging even in work profile
- Bitmap appIcon = mPresentationFactory.makePresentationGetter(info).getIconBitmap(null);
-
- // Raster target drawable with appIcon as a badge
- SimpleIconFactory sif = SimpleIconFactory.obtain(context);
- Bitmap directShareBadgedIcon = sif.createAppBadgedIconBitmap(directShareIcon, appIcon);
- sif.recycle();
-
- return new BitmapDrawable(context.getResources(), directShareBadgedIcon);
- }
-
- /**
- * An alias for execute to use with unit tests.
- */
- public void loadIcon() {
- execute();
- }
- }
}
diff --git a/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java
index 3e2ea473..c159243e 100644
--- a/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java
@@ -26,6 +26,7 @@ import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.PagerAdapter;
import com.android.intentresolver.grid.ChooserGridAdapter;
+import com.android.intentresolver.measurements.Tracer;
import com.android.internal.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
@@ -50,6 +51,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
EmptyStateProvider emptyStateProvider,
Supplier<Boolean> workProfileQuietModeChecker,
UserHandle workProfileUserHandle,
+ UserHandle cloneProfileUserHandle,
int maxTargetsPerRow) {
this(
context,
@@ -59,6 +61,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
workProfileQuietModeChecker,
/* defaultProfile= */ 0,
workProfileUserHandle,
+ cloneProfileUserHandle,
new BottomPaddingOverrideSupplier(context));
}
@@ -70,6 +73,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
Supplier<Boolean> workProfileQuietModeChecker,
@Profile int defaultProfile,
UserHandle workProfileUserHandle,
+ UserHandle cloneProfileUserHandle,
int maxTargetsPerRow) {
this(
context,
@@ -79,6 +83,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
workProfileQuietModeChecker,
defaultProfile,
workProfileUserHandle,
+ cloneProfileUserHandle,
new BottomPaddingOverrideSupplier(context));
}
@@ -90,6 +95,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
Supplier<Boolean> workProfileQuietModeChecker,
@Profile int defaultProfile,
UserHandle workProfileUserHandle,
+ UserHandle cloneProfileUserHandle,
BottomPaddingOverrideSupplier bottomPaddingOverrideSupplier) {
super(
context,
@@ -100,6 +106,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
workProfileQuietModeChecker,
defaultProfile,
workProfileUserHandle,
+ cloneProfileUserHandle,
() -> makeProfileView(context),
bottomPaddingOverrideSupplier);
mAdapterBinder = adapterBinder;
@@ -114,6 +121,16 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
mBottomPaddingOverrideSupplier.setEmptyStateBottomOffset(bottomOffset);
}
+ /**
+ * Notify adapter about the drawer's collapse state. This will affect the app divider's
+ * visibility.
+ */
+ public void setIsCollapsed(boolean isCollapsed) {
+ for (int i = 0, size = getItemCount(); i < size; i++) {
+ getAdapterForIndex(i).setAzLabelVisibility(!isCollapsed);
+ }
+ }
+
private static ViewGroup makeProfileView(Context context) {
LayoutInflater inflater = LayoutInflater.from(context);
ViewGroup rootView = (ViewGroup) inflater.inflate(
@@ -124,6 +141,22 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
return rootView;
}
+ @Override
+ boolean rebuildActiveTab(boolean doPostProcessing) {
+ if (doPostProcessing) {
+ Tracer.INSTANCE.beginAppTargetLoadingSection(getActiveListAdapter().getUserHandle());
+ }
+ return super.rebuildActiveTab(doPostProcessing);
+ }
+
+ @Override
+ boolean rebuildInactiveTab(boolean doPostProcessing) {
+ if (getItemCount() != 1 && doPostProcessing) {
+ Tracer.INSTANCE.beginAppTargetLoadingSection(getInactiveListAdapter().getUserHandle());
+ }
+ return super.rebuildInactiveTab(doPostProcessing);
+ }
+
private static class BottomPaddingOverrideSupplier implements Supplier<Optional<Integer>> {
private final Context mContext;
private int mBottomOffset;
diff --git a/java/src/com/android/intentresolver/ChooserRefinementManager.java b/java/src/com/android/intentresolver/ChooserRefinementManager.java
index 3ddc1c7c..2ebe48a6 100644
--- a/java/src/com/android/intentresolver/ChooserRefinementManager.java
+++ b/java/src/com/android/intentresolver/ChooserRefinementManager.java
@@ -17,18 +17,21 @@
package com.android.intentresolver;
import android.annotation.Nullable;
+import android.annotation.UiThread;
import android.app.Activity;
-import android.content.Context;
+import android.app.Application;
import android.content.Intent;
import android.content.IntentSender;
-import android.content.IntentSender.SendIntentException;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcel;
-import android.os.Parcelable;
import android.os.ResultReceiver;
import android.util.Log;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
import com.android.intentresolver.chooser.TargetInfo;
import java.util.List;
@@ -41,28 +44,52 @@ import java.util.function.Consumer;
* convert the format of the payload, or lazy-download some data that was deferred in the original
* call).
*/
-public final class ChooserRefinementManager {
+@UiThread
+public final class ChooserRefinementManager extends ViewModel {
private static final String TAG = "ChooserRefinement";
- @Nullable
- private final IntentSender mRefinementIntentSender;
+ @Nullable // Non-null only during an active refinement session.
+ private RefinementResultReceiver mRefinementResultReceiver;
- private final Context mContext;
- private final Consumer<TargetInfo> mOnSelectionRefined;
- private final Runnable mOnRefinementCancelled;
+ private boolean mConfigurationChangeInProgress = false;
- @Nullable
- private RefinementResultReceiver mRefinementResultReceiver;
+ /**
+ * A token for the completion of a refinement process that can be consumed exactly once.
+ */
+ public static class RefinementCompletion {
+ private TargetInfo mTargetInfo;
+ private boolean mConsumed;
+
+ RefinementCompletion(TargetInfo targetInfo) {
+ mTargetInfo = targetInfo;
+ }
+
+ /**
+ * @return The output of the completed refinement process. Null if the process was aborted
+ * or failed.
+ */
+ public TargetInfo getTargetInfo() {
+ return mTargetInfo;
+ }
- public ChooserRefinementManager(
- Context context,
- @Nullable IntentSender refinementIntentSender,
- Consumer<TargetInfo> onSelectionRefined,
- Runnable onRefinementCancelled) {
- mContext = context;
- mRefinementIntentSender = refinementIntentSender;
- mOnSelectionRefined = onSelectionRefined;
- mOnRefinementCancelled = onRefinementCancelled;
+ /**
+ * Mark this event as consumed if it wasn't already.
+ *
+ * @return true if this had not already been consumed.
+ */
+ public boolean consume() {
+ if (!mConsumed) {
+ mConsumed = true;
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private MutableLiveData<RefinementCompletion> mRefinementCompletion = new MutableLiveData<>();
+
+ public LiveData<RefinementCompletion> getRefinementCompletion() {
+ return mRefinementCompletion;
}
/**
@@ -70,44 +97,83 @@ public final class ChooserRefinementManager {
* @return true if the selection should wait for a now-started refinement flow, or false if it
* can proceed by the default (non-refinement) logic.
*/
- public boolean maybeHandleSelection(TargetInfo selectedTarget) {
- if (mRefinementIntentSender == null) {
+ public boolean maybeHandleSelection(TargetInfo selectedTarget,
+ IntentSender refinementIntentSender, Application application, Handler mainHandler) {
+ if (refinementIntentSender == null) {
return false;
}
if (selectedTarget.getAllSourceIntents().isEmpty()) {
return false;
}
+ if (selectedTarget.isSuspended()) {
+ // We expect all launches to fail for this target, so don't make the user go through the
+ // refinement flow first. Besides, the default (non-refinement) handling displays a
+ // warning in this case and recovers the session; we won't be equipped to recover if
+ // problems only come up after refinement.
+ return false;
+ }
destroy(); // Terminate any prior sessions.
mRefinementResultReceiver = new RefinementResultReceiver(
refinedIntent -> {
destroy();
+
TargetInfo refinedTarget =
selectedTarget.tryToCloneWithAppliedRefinement(refinedIntent);
if (refinedTarget != null) {
- mOnSelectionRefined.accept(refinedTarget);
+ mRefinementCompletion.setValue(new RefinementCompletion(refinedTarget));
} else {
Log.e(TAG, "Failed to apply refinement to any matching source intent");
- mOnRefinementCancelled.run();
+ mRefinementCompletion.setValue(new RefinementCompletion(null));
}
},
- mOnRefinementCancelled,
- mContext.getMainThreadHandler());
+ () -> {
+ destroy();
+ mRefinementCompletion.setValue(new RefinementCompletion(null));
+ },
+ mainHandler);
Intent refinementRequest = makeRefinementRequest(mRefinementResultReceiver, selectedTarget);
try {
- mRefinementIntentSender.sendIntent(mContext, 0, refinementRequest, null, null);
+ refinementIntentSender.sendIntent(application, 0, refinementRequest, null, null);
return true;
- } catch (SendIntentException e) {
+ } catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Refinement IntentSender failed to send", e);
}
- return false;
+ return true;
+ }
+
+ /** ChooserActivity has stopped */
+ public void onActivityStop(boolean configurationChanging) {
+ mConfigurationChangeInProgress = configurationChanging;
+ }
+
+ /** ChooserActivity has resumed */
+ public void onActivityResume() {
+ if (mConfigurationChangeInProgress) {
+ mConfigurationChangeInProgress = false;
+ } else {
+ if (mRefinementResultReceiver != null) {
+ // This can happen if the refinement activity terminates without ever sending a
+ // response to our `ResultReceiver`. We're probably not prepared to return the user
+ // into a valid Chooser session, so we'll treat it as a cancellation instead.
+ Log.w(TAG, "Chooser resumed while awaiting refinement result; aborting");
+ destroy();
+ mRefinementCompletion.setValue(new RefinementCompletion(null));
+ }
+ }
+ }
+
+ @Override
+ protected void onCleared() {
+ // App lifecycle over, time to clean up.
+ destroy();
}
/** Clean up any ongoing refinement session. */
- public void destroy() {
+ private void destroy() {
if (mRefinementResultReceiver != null) {
- mRefinementResultReceiver.destroy();
+ mRefinementResultReceiver.destroyReceiver();
mRefinementResultReceiver = null;
}
}
@@ -144,7 +210,7 @@ public final class ChooserRefinementManager {
mOnRefinementCancelled = onRefinementCancelled;
}
- public void destroy() {
+ public void destroyReceiver() {
mDestroyed = true;
}
@@ -154,27 +220,14 @@ public final class ChooserRefinementManager {
Log.e(TAG, "Destroyed RefinementResultReceiver received a result");
return;
}
- if (resultData == null) {
- Log.e(TAG, "RefinementResultReceiver received null resultData");
- // TODO: treat as cancellation?
- return;
- }
- switch (resultCode) {
- case Activity.RESULT_CANCELED:
- mOnRefinementCancelled.run();
- break;
- case Activity.RESULT_OK:
- Parcelable intentParcelable = resultData.getParcelable(Intent.EXTRA_INTENT);
- if (intentParcelable instanceof Intent) {
- mOnSelectionRefined.accept((Intent) intentParcelable);
- } else {
- Log.e(TAG, "No valid Intent.EXTRA_INTENT in 'OK' refinement result data");
- }
- break;
- default:
- Log.w(TAG, "Received unknown refinement result " + resultCode);
- break;
+ destroyReceiver(); // This is the single callback we'll accept from this session.
+
+ Intent refinedResult = tryToExtractRefinedResult(resultCode, resultData);
+ if (refinedResult == null) {
+ mOnRefinementCancelled.run();
+ } else {
+ mOnSelectionRefined.accept(refinedResult);
}
}
@@ -190,5 +243,24 @@ public final class ChooserRefinementManager {
parcel.recycle();
return receiverForSending;
}
+
+ /**
+ * Get the refinement from the result data, if possible, or log diagnostics and return null.
+ */
+ @Nullable
+ private static Intent tryToExtractRefinedResult(int resultCode, Bundle resultData) {
+ if (Activity.RESULT_CANCELED == resultCode) {
+ Log.i(TAG, "Refinement canceled by caller");
+ } else if (Activity.RESULT_OK != resultCode) {
+ Log.w(TAG, "Canceling refinement on unrecognized result code " + resultCode);
+ } else if (resultData == null) {
+ Log.e(TAG, "RefinementResultReceiver received null resultData; canceling");
+ } else if (!(resultData.getParcelable(Intent.EXTRA_INTENT) instanceof Intent)) {
+ Log.e(TAG, "No valid Intent.EXTRA_INTENT in 'OK' refinement result data");
+ } else {
+ return resultData.getParcelable(Intent.EXTRA_INTENT, Intent.class);
+ }
+ return null;
+ }
}
}
diff --git a/java/src/com/android/intentresolver/ChooserRequestParameters.java b/java/src/com/android/intentresolver/ChooserRequestParameters.java
index 3d99e475..5157986b 100644
--- a/java/src/com/android/intentresolver/ChooserRequestParameters.java
+++ b/java/src/com/android/intentresolver/ChooserRequestParameters.java
@@ -18,7 +18,6 @@ package com.android.intentresolver;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -34,7 +33,7 @@ import android.util.Log;
import android.util.Pair;
import com.android.intentresolver.flags.FeatureFlagRepository;
-import com.android.intentresolver.flags.Flags;
+import com.android.intentresolver.util.UriFilters;
import com.google.common.collect.ImmutableList;
@@ -69,16 +68,16 @@ public class ChooserRequestParameters {
private static final int LAUNCH_FLAGS_FOR_SEND_ACTION =
Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+ private static final int MAX_CHOOSER_ACTIONS = 5;
private final Intent mTarget;
- private final ChooserIntegratedDeviceComponents mIntegratedDeviceComponents;
private final String mReferrerPackageName;
private final Pair<CharSequence, Integer> mTitleSpec;
private final Intent mReferrerFillInIntent;
private final ImmutableList<ComponentName> mFilteredComponentNames;
private final ImmutableList<ChooserTarget> mCallerChooserTargets;
private final @NonNull ImmutableList<ChooserAction> mChooserActions;
- private final PendingIntent mModifyShareAction;
+ private final ChooserAction mModifyShareAction;
private final boolean mRetainInOnStop;
@Nullable
@@ -106,14 +105,11 @@ public class ChooserRequestParameters {
final Intent clientIntent,
String referrerPackageName,
final Uri referrer,
- ChooserIntegratedDeviceComponents integratedDeviceComponents,
FeatureFlagRepository featureFlags) {
final Intent requestedTarget = parseTargetIntentExtra(
clientIntent.getParcelableExtra(Intent.EXTRA_INTENT));
mTarget = intentWithModifiedLaunchFlags(requestedTarget);
- mIntegratedDeviceComponents = integratedDeviceComponents;
-
mReferrerPackageName = referrerPackageName;
mAdditionalTargets = intentsWithModifiedLaunchFlagsFromExtraIfPresent(
@@ -135,8 +131,11 @@ public class ChooserRequestParameters {
mRefinementIntentSender = clientIntent.getParcelableExtra(
Intent.EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER);
- mFilteredComponentNames = getFilteredComponentNames(
- clientIntent, mIntegratedDeviceComponents.getNearbySharingComponent());
+ ComponentName[] filteredComponents = clientIntent.getParcelableArrayExtra(
+ Intent.EXTRA_EXCLUDE_COMPONENTS, ComponentName.class);
+ mFilteredComponentNames = filteredComponents != null
+ ? ImmutableList.copyOf(filteredComponents)
+ : ImmutableList.of();
mCallerChooserTargets = parseCallerTargetsFromClientIntent(clientIntent);
@@ -147,12 +146,8 @@ public class ChooserRequestParameters {
mTargetIntentFilter = getTargetIntentFilter(mTarget);
- mChooserActions = featureFlags.isEnabled(Flags.SHARESHEET_CUSTOM_ACTIONS)
- ? getChooserActions(clientIntent)
- : ImmutableList.of();
- mModifyShareAction = featureFlags.isEnabled(Flags.SHARESHEET_RESELECTION_ACTION)
- ? getModifyShareAction(clientIntent)
- : null;
+ mChooserActions = getChooserActions(clientIntent);
+ mModifyShareAction = getModifyShareAction(clientIntent);
}
public Intent getTargetIntent() {
@@ -204,7 +199,7 @@ public class ChooserRequestParameters {
}
@Nullable
- public PendingIntent getModifyShareAction() {
+ public ChooserAction getModifyShareAction() {
return mModifyShareAction;
}
@@ -258,10 +253,6 @@ public class ChooserRequestParameters {
return mTargetIntentFilter;
}
- public ChooserIntegratedDeviceComponents getIntegratedDeviceComponents() {
- return mIntegratedDeviceComponents;
- }
-
private static boolean isSendAction(@Nullable String action) {
return (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action));
}
@@ -310,29 +301,11 @@ public class ChooserRequestParameters {
requestedTitle = null;
}
- int defaultTitleRes =
- (requestedTitle == null) ? com.android.internal.R.string.chooseActivity : 0;
+ int defaultTitleRes = (requestedTitle == null) ? R.string.chooseActivity : 0;
return Pair.create(requestedTitle, defaultTitleRes);
}
- private static ImmutableList<ComponentName> getFilteredComponentNames(
- Intent clientIntent, @Nullable ComponentName nearbySharingComponent) {
- Stream<ComponentName> filteredComponents = streamParcelableArrayExtra(
- clientIntent, Intent.EXTRA_EXCLUDE_COMPONENTS, ComponentName.class, true, true);
-
- if (nearbySharingComponent != null) {
- // Exclude Nearby from main list if chip is present, to avoid duplication.
- // TODO: we don't have an explicit guarantee that the chip will be displayed just
- // because we have a non-null component; that's ultimately determined by the preview
- // layout. Maybe we can make that decision further upstream?
- filteredComponents = Stream.concat(
- filteredComponents, Stream.of(nearbySharingComponent));
- }
-
- return filteredComponents.collect(toImmutableList());
- }
-
private static ImmutableList<ChooserTarget> parseCallerTargetsFromClientIntent(
Intent clientIntent) {
return
@@ -349,15 +322,17 @@ public class ChooserRequestParameters {
ChooserAction.class,
true,
true)
- .collect(toImmutableList());
+ .filter(UriFilters::hasValidIcon)
+ .limit(MAX_CHOOSER_ACTIONS)
+ .collect(toImmutableList());
}
@Nullable
- private static PendingIntent getModifyShareAction(Intent intent) {
+ private static ChooserAction getModifyShareAction(Intent intent) {
try {
return intent.getParcelableExtra(
Intent.EXTRA_CHOOSER_MODIFY_SHARE_ACTION,
- PendingIntent.class);
+ ChooserAction.class);
} catch (Throwable t) {
Log.w(
TAG,
diff --git a/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java b/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java
index 0aa32505..4bfb21aa 100644
--- a/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java
+++ b/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java
@@ -142,6 +142,12 @@ public class ChooserTargetActionsDialogFragment extends DialogFragment
return v;
}
+ @Override
+ public void onStop() {
+ super.onStop();
+ dismissAllowingStateLoss();
+ }
+
class VHAdapter extends RecyclerView.Adapter<VH> {
List<Pair<Drawable, CharSequence>> mItems;
diff --git a/java/src/com/android/intentresolver/GenericMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/GenericMultiProfilePagerAdapter.java
index 7613f35f..a1c53402 100644
--- a/java/src/com/android/intentresolver/GenericMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/GenericMultiProfilePagerAdapter.java
@@ -19,6 +19,7 @@ package com.android.intentresolver;
import android.annotation.Nullable;
import android.content.Context;
import android.os.UserHandle;
+import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -84,6 +85,7 @@ class GenericMultiProfilePagerAdapter<
Supplier<Boolean> workProfileQuietModeChecker,
@Profile int defaultProfile,
UserHandle workProfileUserHandle,
+ UserHandle cloneProfileUserHandle,
Supplier<ViewGroup> pageViewInflater,
Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) {
super(
@@ -91,7 +93,8 @@ class GenericMultiProfilePagerAdapter<
/* currentPage= */ defaultProfile,
emptyStateProvider,
workProfileQuietModeChecker,
- workProfileUserHandle);
+ workProfileUserHandle,
+ cloneProfileUserHandle);
mListAdapterExtractor = listAdapterExtractor;
mAdapterBinder = adapterBinder;
@@ -145,12 +148,12 @@ class GenericMultiProfilePagerAdapter<
@Override
@Nullable
protected ListAdapterT getListAdapterForUserHandle(UserHandle userHandle) {
- if (getActiveListAdapter().getUserHandle().equals(userHandle)) {
- return getActiveListAdapter();
- }
- if ((getInactiveListAdapter() != null) && getInactiveListAdapter().getUserHandle().equals(
- userHandle)) {
- return getInactiveListAdapter();
+ if (getPersonalListAdapter().getUserHandle().equals(userHandle)
+ || userHandle.equals(getCloneUserHandle())) {
+ return getPersonalListAdapter();
+ } else if (getWorkListAdapter() != null
+ && getWorkListAdapter().getUserHandle().equals(userHandle)) {
+ return getWorkListAdapter();
}
return null;
}
@@ -177,6 +180,9 @@ class GenericMultiProfilePagerAdapter<
@Override
public ListAdapterT getWorkListAdapter() {
+ if (!hasAdapterForIndex(PROFILE_WORK)) {
+ return null;
+ }
return mListAdapterExtractor.apply(getAdapterForIndex(PROFILE_WORK));
}
@@ -209,6 +215,10 @@ class GenericMultiProfilePagerAdapter<
paddingBottom));
}
+ private boolean hasAdapterForIndex(int pageIndex) {
+ return (pageIndex < getCount());
+ }
+
// TODO: `ChooserActivity` also has a per-profile record type. Maybe the "multi-profile pager"
// should be the owner of all per-profile data (especially now that the API is generic)?
private static class GenericProfileDescriptor<PageViewT, SinglePageAdapterT> extends
diff --git a/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt b/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt
deleted file mode 100644
index 7b6651a2..00000000
--- a/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.intentresolver
-
-import android.content.Context
-import android.graphics.Bitmap
-import android.net.Uri
-import android.util.Size
-import androidx.annotation.GuardedBy
-import androidx.annotation.VisibleForTesting
-import androidx.collection.LruCache
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.coroutineScope
-import kotlinx.coroutines.CompletableDeferred
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import java.util.function.Consumer
-
-@VisibleForTesting
-class ImagePreviewImageLoader @JvmOverloads constructor(
- private val context: Context,
- private val lifecycle: Lifecycle,
- cacheSize: Int,
- private val dispatcher: CoroutineDispatcher = Dispatchers.IO
-) : ImageLoader {
-
- private val thumbnailSize: Size =
- context.resources.getDimensionPixelSize(R.dimen.chooser_preview_image_max_dimen).let {
- Size(it, it)
- }
-
- @GuardedBy("self")
- private val cache = LruCache<Uri, CompletableDeferred<Bitmap?>>(cacheSize)
-
- override suspend fun invoke(uri: Uri): Bitmap? = loadImageAsync(uri)
-
- override fun loadImage(uri: Uri, callback: Consumer<Bitmap?>) {
- lifecycle.coroutineScope.launch {
- val image = loadImageAsync(uri)
- if (isActive) {
- callback.accept(image)
- }
- }
- }
-
- override fun prePopulate(uris: List<Uri>) {
- uris.asSequence().take(cache.maxSize()).forEach { uri ->
- lifecycle.coroutineScope.launch {
- loadImageAsync(uri)
- }
- }
- }
-
- private suspend fun loadImageAsync(uri: Uri): Bitmap? {
- return synchronized(cache) {
- cache.get(uri) ?: CompletableDeferred<Bitmap?>().also { result ->
- cache.put(uri, result)
- lifecycle.coroutineScope.launch(dispatcher) {
- result.loadBitmap(uri)
- }
- }
- }.await()
- }
-
- private fun CompletableDeferred<Bitmap?>.loadBitmap(uri: Uri) {
- val bitmap = runCatching {
- context.contentResolver.loadThumbnail(uri, thumbnailSize, null)
- }.getOrNull()
- complete(bitmap)
- }
-}
diff --git a/java/src/com/android/intentresolver/IntentForwarderActivity.java b/java/src/com/android/intentresolver/IntentForwarderActivity.java
index 78240250..5e8945f1 100644
--- a/java/src/com/android/intentresolver/IntentForwarderActivity.java
+++ b/java/src/com/android/intentresolver/IntentForwarderActivity.java
@@ -162,13 +162,13 @@ public class IntentForwarderActivity extends Activity {
private String getForwardToPersonalMessage() {
return getSystemService(DevicePolicyManager.class).getResources().getString(
FORWARD_INTENT_TO_PERSONAL,
- () -> getString(com.android.internal.R.string.forward_intent_to_owner));
+ () -> getString(R.string.forward_intent_to_owner));
}
private String getForwardToWorkMessage() {
return getSystemService(DevicePolicyManager.class).getResources().getString(
FORWARD_INTENT_TO_WORK,
- () -> getString(com.android.internal.R.string.forward_intent_to_work));
+ () -> getString(R.string.forward_intent_to_work));
}
private boolean isIntentForwarderResolveInfo(ResolveInfo resolveInfo) {
diff --git a/java/src/com/android/intentresolver/ItemRevealAnimationTracker.kt b/java/src/com/android/intentresolver/ItemRevealAnimationTracker.kt
new file mode 100644
index 00000000..d3e07c6b
--- /dev/null
+++ b/java/src/com/android/intentresolver/ItemRevealAnimationTracker.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver
+
+import android.view.View
+import android.view.animation.AlphaAnimation
+import android.view.animation.LinearInterpolator
+import android.view.animation.Transformation
+import com.android.intentresolver.chooser.TargetInfo
+
+private const val IMAGE_FADE_IN_MILLIS = 150L
+
+internal class ItemRevealAnimationTracker {
+ private val iconProgress = HashMap<TargetInfo, Record>()
+ private val labelProgress = HashMap<TargetInfo, Record>()
+
+ fun reset() {
+ iconProgress.clear()
+ labelProgress.clear()
+ }
+
+ fun animateIcon(view: View, info: TargetInfo) = animateView(view, info, iconProgress)
+ fun animateLabel(view: View, info: TargetInfo) = animateView(view, info, labelProgress)
+
+ private fun animateView(view: View, info: TargetInfo, map: MutableMap<TargetInfo, Record>) {
+ val record = map.getOrPut(info) {
+ Record()
+ }
+ if ((view.animation as? RevealAnimation)?.record === record) return
+
+ view.clearAnimation()
+ if (record.alpha >= 1f) {
+ view.alpha = 1f
+ return
+ }
+
+ view.startAnimation(RevealAnimation(record))
+ }
+
+ private class Record(var alpha: Float = 0f)
+
+ private class RevealAnimation(val record: Record) : AlphaAnimation(record.alpha, 1f) {
+ init {
+ duration = (IMAGE_FADE_IN_MILLIS * (1f - record.alpha)).toLong()
+ interpolator = LinearInterpolator()
+ }
+
+ override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
+ super.applyTransformation(interpolatedTime, t)
+ // One TargetInfo can be simultaneously bou into multiple UI grid items; make sure
+ // that the alpha value only increases. This should not affect running animations, only
+ // a starting point for a new animation when a different view is bound to this target.
+ record.alpha = minOf(1f, maxOf(record.alpha, t.alpha))
+ }
+ }
+}
diff --git a/java/src/com/android/intentresolver/NoAppsAvailableEmptyStateProvider.java b/java/src/com/android/intentresolver/NoAppsAvailableEmptyStateProvider.java
index c1373f4b..a7b50f38 100644
--- a/java/src/com/android/intentresolver/NoAppsAvailableEmptyStateProvider.java
+++ b/java/src/com/android/intentresolver/NoAppsAvailableEmptyStateProvider.java
@@ -30,7 +30,6 @@ import android.stats.devicepolicy.nano.DevicePolicyEnums;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyState;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStateProvider;
-import com.android.intentresolver.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
import com.android.internal.R;
import java.util.List;
@@ -50,16 +49,16 @@ public class NoAppsAvailableEmptyStateProvider implements EmptyStateProvider {
@NonNull
private final String mMetricsCategory;
@NonNull
- private final MyUserIdProvider mMyUserIdProvider;
+ private final UserHandle mTabOwnerUserHandleForLaunch;
public NoAppsAvailableEmptyStateProvider(Context context, UserHandle workProfileUserHandle,
UserHandle personalProfileUserHandle, String metricsCategory,
- MyUserIdProvider myUserIdProvider) {
+ UserHandle tabOwnerUserHandleForLaunch) {
mContext = context;
mWorkProfileUserHandle = workProfileUserHandle;
mPersonalProfileUserHandle = personalProfileUserHandle;
mMetricsCategory = metricsCategory;
- mMyUserIdProvider = myUserIdProvider;
+ mTabOwnerUserHandleForLaunch = tabOwnerUserHandleForLaunch;
}
@Nullable
@@ -69,7 +68,7 @@ public class NoAppsAvailableEmptyStateProvider implements EmptyStateProvider {
UserHandle listUserHandle = resolverListAdapter.getUserHandle();
if (mWorkProfileUserHandle != null
- && (mMyUserIdProvider.getMyUserId() == listUserHandle.getIdentifier()
+ && (mTabOwnerUserHandleForLaunch.equals(listUserHandle)
|| !hasAppsInOtherProfile(resolverListAdapter))) {
String title;
@@ -102,7 +101,7 @@ public class NoAppsAvailableEmptyStateProvider implements EmptyStateProvider {
return false;
}
List<ResolvedComponentInfo> resolversForIntent =
- adapter.getResolversForUser(UserHandle.of(mMyUserIdProvider.getMyUserId()));
+ adapter.getResolversForUser(mTabOwnerUserHandleForLaunch);
for (ResolvedComponentInfo info : resolversForIntent) {
ResolveInfo resolveInfo = info.getResolveInfoAt(0);
if (resolveInfo.targetUserId != UserHandle.USER_CURRENT) {
diff --git a/java/src/com/android/intentresolver/NoCrossProfileEmptyStateProvider.java b/java/src/com/android/intentresolver/NoCrossProfileEmptyStateProvider.java
index 420d26c5..6f72bb00 100644
--- a/java/src/com/android/intentresolver/NoCrossProfileEmptyStateProvider.java
+++ b/java/src/com/android/intentresolver/NoCrossProfileEmptyStateProvider.java
@@ -27,7 +27,6 @@ import android.os.UserHandle;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.CrossProfileIntentsChecker;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyState;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStateProvider;
-import com.android.intentresolver.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
/**
* Empty state provider that does not allow cross profile sharing, it will return a blocker
@@ -39,28 +38,28 @@ public class NoCrossProfileEmptyStateProvider implements EmptyStateProvider {
private final EmptyState mNoWorkToPersonalEmptyState;
private final EmptyState mNoPersonalToWorkEmptyState;
private final CrossProfileIntentsChecker mCrossProfileIntentsChecker;
- private final MyUserIdProvider mUserIdProvider;
+ private final UserHandle mTabOwnerUserHandleForLaunch;
public NoCrossProfileEmptyStateProvider(UserHandle personalUserHandle,
EmptyState noWorkToPersonalEmptyState,
EmptyState noPersonalToWorkEmptyState,
CrossProfileIntentsChecker crossProfileIntentsChecker,
- MyUserIdProvider myUserIdProvider) {
+ UserHandle tabOwnerUserHandleForLaunch) {
mPersonalProfileUserHandle = personalUserHandle;
mNoWorkToPersonalEmptyState = noWorkToPersonalEmptyState;
mNoPersonalToWorkEmptyState = noPersonalToWorkEmptyState;
mCrossProfileIntentsChecker = crossProfileIntentsChecker;
- mUserIdProvider = myUserIdProvider;
+ mTabOwnerUserHandleForLaunch = tabOwnerUserHandleForLaunch;
}
@Nullable
@Override
public EmptyState getEmptyState(ResolverListAdapter resolverListAdapter) {
boolean shouldShowBlocker =
- mUserIdProvider.getMyUserId() != resolverListAdapter.getUserHandle().getIdentifier()
+ !mTabOwnerUserHandleForLaunch.equals(resolverListAdapter.getUserHandle())
&& !mCrossProfileIntentsChecker
.hasCrossProfileIntents(resolverListAdapter.getIntents(),
- mUserIdProvider.getMyUserId(),
+ mTabOwnerUserHandleForLaunch.getIdentifier(),
resolverListAdapter.getUserHandle().getIdentifier());
if (!shouldShowBlocker) {
diff --git a/java/src/com/android/intentresolver/ResolverActivity.java b/java/src/com/android/intentresolver/ResolverActivity.java
index d224299e..57871532 100644
--- a/java/src/com/android/intentresolver/ResolverActivity.java
+++ b/java/src/com/android/intentresolver/ResolverActivity.java
@@ -33,6 +33,8 @@ import static android.stats.devicepolicy.nano.DevicePolicyEnums.RESOLVER_EMPTY_S
import static android.stats.devicepolicy.nano.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
+
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UiThread;
@@ -58,7 +60,6 @@ import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Insets;
-import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -106,6 +107,9 @@ import com.android.intentresolver.AbstractMultiProfilePagerAdapter.Profile;
import com.android.intentresolver.NoCrossProfileEmptyStateProvider.DevicePolicyBlockerEmptyState;
import com.android.intentresolver.chooser.DisplayResolveInfo;
import com.android.intentresolver.chooser.TargetInfo;
+import com.android.intentresolver.icons.DefaultTargetDataLoader;
+import com.android.intentresolver.icons.TargetDataLoader;
+import com.android.intentresolver.model.ResolverRankerServiceResolverComparator;
import com.android.intentresolver.widget.ResolverDrawerLayout;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
@@ -122,9 +126,10 @@ import java.util.Set;
import java.util.function.Supplier;
/**
- * This activity is displayed when the system attempts to start an Intent for
- * which there is more than one matching activity, allowing the user to decide
- * which to go to. It is not normally used directly by application developers.
+ * This is a copy of ResolverActivity to support IntentResolver's ChooserActivity. This code is
+ * *not* the resolver that is actually triggered by the system right now (you want
+ * frameworks/base/core/java/com/android/internal/app/ResolverActivity.java for that), the full
+ * migration is not complete.
*/
@UiThread
public class ResolverActivity extends FragmentActivity implements
@@ -225,7 +230,7 @@ public class ResolverActivity extends FragmentActivity implements
// new component whose lifecycle is limited to the "created" Activity (so that we can just hold
// the annotations as a `final` ivar, which is a better way to show immutability).
private Supplier<AnnotatedUserHandles> mLazyAnnotatedUserHandles = () -> {
- final AnnotatedUserHandles result = new AnnotatedUserHandles(this);
+ final AnnotatedUserHandles result = AnnotatedUserHandles.forShareActivity(this);
mLazyAnnotatedUserHandles = () -> result;
return result;
};
@@ -237,47 +242,43 @@ public class ResolverActivity extends FragmentActivity implements
private enum ActionTitle {
VIEW(Intent.ACTION_VIEW,
- com.android.internal.R.string.whichViewApplication,
- com.android.internal.R.string.whichViewApplicationNamed,
- com.android.internal.R.string.whichViewApplicationLabel),
+ R.string.whichViewApplication,
+ R.string.whichViewApplicationNamed,
+ R.string.whichViewApplicationLabel),
EDIT(Intent.ACTION_EDIT,
- com.android.internal.R.string.whichEditApplication,
- com.android.internal.R.string.whichEditApplicationNamed,
- com.android.internal.R.string.whichEditApplicationLabel),
+ R.string.whichEditApplication,
+ R.string.whichEditApplicationNamed,
+ R.string.whichEditApplicationLabel),
SEND(Intent.ACTION_SEND,
- com.android.internal.R.string.whichSendApplication,
- com.android.internal.R.string.whichSendApplicationNamed,
- com.android.internal.R.string.whichSendApplicationLabel),
+ R.string.whichSendApplication,
+ R.string.whichSendApplicationNamed,
+ R.string.whichSendApplicationLabel),
SENDTO(Intent.ACTION_SENDTO,
- com.android.internal.R.string.whichSendToApplication,
- com.android.internal.R.string.whichSendToApplicationNamed,
- com.android.internal.R.string.whichSendToApplicationLabel),
+ R.string.whichSendToApplication,
+ R.string.whichSendToApplicationNamed,
+ R.string.whichSendToApplicationLabel),
SEND_MULTIPLE(Intent.ACTION_SEND_MULTIPLE,
- com.android.internal.R.string.whichSendApplication,
- com.android.internal.R.string.whichSendApplicationNamed,
- com.android.internal.R.string.whichSendApplicationLabel),
+ R.string.whichSendApplication,
+ R.string.whichSendApplicationNamed,
+ R.string.whichSendApplicationLabel),
CAPTURE_IMAGE(MediaStore.ACTION_IMAGE_CAPTURE,
- com.android.internal.R.string.whichImageCaptureApplication,
- com.android.internal.R.string.whichImageCaptureApplicationNamed,
- com.android.internal.R.string.whichImageCaptureApplicationLabel),
+ R.string.whichImageCaptureApplication,
+ R.string.whichImageCaptureApplicationNamed,
+ R.string.whichImageCaptureApplicationLabel),
DEFAULT(null,
- com.android.internal.R.string.whichApplication,
- com.android.internal.R.string.whichApplicationNamed,
- com.android.internal.R.string.whichApplicationLabel),
+ R.string.whichApplication,
+ R.string.whichApplicationNamed,
+ R.string.whichApplicationLabel),
HOME(Intent.ACTION_MAIN,
- com.android.internal.R.string.whichHomeApplication,
- com.android.internal.R.string.whichHomeApplicationNamed,
- com.android.internal.R.string.whichHomeApplicationLabel);
+ R.string.whichHomeApplication,
+ R.string.whichHomeApplicationNamed,
+ R.string.whichHomeApplicationLabel);
// titles for layout that deals with http(s) intents
- public static final int BROWSABLE_TITLE_RES =
- com.android.internal.R.string.whichOpenLinksWith;
- public static final int BROWSABLE_HOST_TITLE_RES =
- com.android.internal.R.string.whichOpenHostLinksWith;
- public static final int BROWSABLE_HOST_APP_TITLE_RES =
- com.android.internal.R.string.whichOpenHostLinksWithApp;
- public static final int BROWSABLE_APP_TITLE_RES =
- com.android.internal.R.string.whichOpenLinksWithApp;
+ public static final int BROWSABLE_TITLE_RES = R.string.whichOpenLinksWith;
+ public static final int BROWSABLE_HOST_TITLE_RES = R.string.whichOpenHostLinksWith;
+ public static final int BROWSABLE_HOST_APP_TITLE_RES = R.string.whichOpenHostLinksWithApp;
+ public static final int BROWSABLE_APP_TITLE_RES = R.string.whichOpenLinksWithApp;
public final String action;
public final int titleRes;
@@ -333,7 +334,7 @@ public class ResolverActivity extends FragmentActivity implements
setSafeForwardingMode(true);
- onCreate(savedInstanceState, intent, null, 0, null, null, true);
+ onCreate(savedInstanceState, intent, null, 0, null, null, true, createIconLoader());
}
/**
@@ -343,13 +344,26 @@ public class ResolverActivity extends FragmentActivity implements
protected void onCreate(Bundle savedInstanceState, Intent intent,
CharSequence title, Intent[] initialIntents,
List<ResolveInfo> rList, boolean supportsAlwaysUseOption) {
- onCreate(savedInstanceState, intent, title, 0, initialIntents, rList,
- supportsAlwaysUseOption);
+ onCreate(
+ savedInstanceState,
+ intent,
+ title,
+ 0,
+ initialIntents,
+ rList,
+ supportsAlwaysUseOption,
+ createIconLoader());
}
- protected void onCreate(Bundle savedInstanceState, Intent intent,
- CharSequence title, int defaultTitleRes, Intent[] initialIntents,
- List<ResolveInfo> rList, boolean supportsAlwaysUseOption) {
+ protected void onCreate(
+ Bundle savedInstanceState,
+ Intent intent,
+ CharSequence title,
+ int defaultTitleRes,
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean supportsAlwaysUseOption,
+ TargetDataLoader targetDataLoader) {
setTheme(appliedThemeResId());
super.onCreate(savedInstanceState);
@@ -379,10 +393,14 @@ public class ResolverActivity extends FragmentActivity implements
// turn this off when running under voice interaction, since it results in
// a more complicated UI that the current voice interaction flow is not able
// to handle. We also turn it off when the work tab is shown to simplify the UX.
+ // We also turn it off when clonedProfile is present on the device, because we might have
+ // different "last chosen" activities in the different profiles, and PackageManager doesn't
+ // provide any more information to help us select between them.
boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction()
- && !shouldShowTabs();
- mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed);
- if (configureContentView()) {
+ && !shouldShowTabs() && !hasCloneProfile();
+ mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(
+ initialIntents, rList, filterLastUsed, targetDataLoader);
+ if (configureContentView(targetDataLoader)) {
return;
}
@@ -438,15 +456,16 @@ public class ResolverActivity extends FragmentActivity implements
protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter(
Intent[] initialIntents,
List<ResolveInfo> rList,
- boolean filterLastUsed) {
+ boolean filterLastUsed,
+ TargetDataLoader targetDataLoader) {
AbstractMultiProfilePagerAdapter resolverMultiProfilePagerAdapter = null;
if (shouldShowTabs()) {
resolverMultiProfilePagerAdapter =
createResolverMultiProfilePagerAdapterForTwoProfiles(
- initialIntents, rList, filterLastUsed);
+ initialIntents, rList, filterLastUsed, targetDataLoader);
} else {
resolverMultiProfilePagerAdapter = createResolverMultiProfilePagerAdapterForOneProfile(
- initialIntents, rList, filterLastUsed);
+ initialIntents, rList, filterLastUsed, targetDataLoader);
}
return resolverMultiProfilePagerAdapter;
}
@@ -484,7 +503,7 @@ public class ResolverActivity extends FragmentActivity implements
return new NoCrossProfileEmptyStateProvider(getPersonalProfileUserHandle(),
noWorkToPersonalEmptyState, noPersonalToWorkEmptyState,
- createCrossProfileIntentsChecker(), createMyUserIdProvider());
+ createCrossProfileIntentsChecker(), getTabOwnerUserHandleForLaunch());
}
protected int appliedThemeResId() {
@@ -861,13 +880,24 @@ public class ResolverActivity extends FragmentActivity implements
// the future if resolver *were* to make any (non-overridden) calls to a version that used a
// different signature (and thus didn't return the subclass type).
@VisibleForTesting
- protected ResolverListController createListController(UserHandle unused) {
+ protected ResolverListController createListController(UserHandle userHandle) {
+ ResolverRankerServiceResolverComparator resolverComparator =
+ new ResolverRankerServiceResolverComparator(
+ this,
+ getTargetIntent(),
+ getReferrerPackageName(),
+ null,
+ null,
+ getResolverRankerServiceUserHandleList(userHandle),
+ null);
return new ResolverListController(
this,
mPm,
getTargetIntent(),
getReferrerPackageName(),
- getAnnotatedUserHandles().userIdOfCallingApp);
+ getAnnotatedUserHandles().userIdOfCallingApp,
+ resolverComparator,
+ getQueryIntentsUser(userHandle));
}
/**
@@ -990,52 +1020,36 @@ public class ResolverActivity extends FragmentActivity implements
return new CrossProfileIntentsChecker(getContentResolver());
}
- // @NonFinalForTesting
- @VisibleForTesting
protected WorkProfileAvailabilityManager createWorkProfileAvailabilityManager() {
final UserHandle workUser = getWorkProfileUserHandle();
return new WorkProfileAvailabilityManager(
getSystemService(UserManager.class),
workUser,
- () -> {
- if (mMultiProfilePagerAdapter.getCurrentUserHandle().equals(workUser)) {
- mMultiProfilePagerAdapter.rebuildActiveTab(true);
- } else {
- mMultiProfilePagerAdapter.clearInactiveProfileCache();
- }
- });
- }
-
- // TODO: have tests override `getAnnotatedUserHandles()`, and make this method `final`.
- // @NonFinalForTesting
- @Nullable
- protected UserHandle getWorkProfileUserHandle() {
- return getAnnotatedUserHandles().workProfileUserHandle;
+ this::onWorkProfileStatusUpdated);
}
- // @NonFinalForTesting
- @VisibleForTesting
- public void safelyStartActivity(TargetInfo cti) {
- // We're dispatching intents that might be coming from legacy apps, so
- // don't kill ourselves.
- StrictMode.disableDeathOnFileUriExposure();
- try {
- UserHandle currentUserHandle = mMultiProfilePagerAdapter.getCurrentUserHandle();
- safelyStartActivityInternal(cti, currentUserHandle, null);
- } finally {
- StrictMode.enableDeathOnFileUriExposure();
+ protected void onWorkProfileStatusUpdated() {
+ if (mMultiProfilePagerAdapter.getCurrentUserHandle().equals(getWorkProfileUserHandle())) {
+ mMultiProfilePagerAdapter.rebuildActiveTab(true);
+ } else {
+ mMultiProfilePagerAdapter.clearInactiveProfileCache();
}
}
// @NonFinalForTesting
@VisibleForTesting
- protected ResolverListAdapter createResolverListAdapter(Context context,
- List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
- boolean filterLastUsed, UserHandle userHandle) {
- Intent startIntent = getIntent();
- boolean isAudioCaptureDevice =
- startIntent.getBooleanExtra(EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
+ protected ResolverListAdapter createResolverListAdapter(
+ Context context,
+ List<Intent> payloadIntents,
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed,
+ UserHandle userHandle,
+ TargetDataLoader targetDataLoader) {
+ UserHandle initialIntentsUserSpace = isLaunchedAsCloneProfile()
+ && userHandle.equals(getPersonalProfileUserHandle())
+ ? getCloneProfileUserHandle() : userHandle;
return new ResolverListAdapter(
context,
payloadIntents,
@@ -1046,7 +1060,15 @@ public class ResolverActivity extends FragmentActivity implements
userHandle,
getTargetIntent(),
this,
- isAudioCaptureDevice);
+ initialIntentsUserSpace,
+ targetDataLoader);
+ }
+
+ private TargetDataLoader createIconLoader() {
+ Intent startIntent = getIntent();
+ boolean isAudioCaptureDevice =
+ startIntent.getBooleanExtra(EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
+ return new DefaultTargetDataLoader(this, getLifecycle(), isAudioCaptureDevice);
}
private LatencyTracker getLatencyTracker() {
@@ -1085,7 +1107,7 @@ public class ResolverActivity extends FragmentActivity implements
workProfileUserHandle,
getPersonalProfileUserHandle(),
getMetricsCategory(),
- createMyUserIdProvider()
+ getTabOwnerUserHandleForLaunch()
);
// Return composite provider, the order matters (the higher, the more priority)
@@ -1121,38 +1143,42 @@ public class ResolverActivity extends FragmentActivity implements
createResolverMultiProfilePagerAdapterForOneProfile(
Intent[] initialIntents,
List<ResolveInfo> rList,
- boolean filterLastUsed) {
+ boolean filterLastUsed,
+ TargetDataLoader targetDataLoader) {
ResolverListAdapter adapter = createResolverListAdapter(
/* context */ this,
/* payloadIntents */ mIntents,
initialIntents,
rList,
filterLastUsed,
- /* userHandle */ UserHandle.of(UserHandle.myUserId()));
+ /* userHandle */ getPersonalProfileUserHandle(),
+ targetDataLoader);
return new ResolverMultiProfilePagerAdapter(
/* context */ this,
adapter,
createEmptyStateProvider(/* workProfileUserHandle= */ null),
/* workProfileQuietModeChecker= */ () -> false,
- /* workProfileUserHandle= */ null);
+ /* workProfileUserHandle= */ null,
+ getCloneProfileUserHandle());
}
private UserHandle getIntentUser() {
return getIntent().hasExtra(EXTRA_CALLING_USER)
? getIntent().getParcelableExtra(EXTRA_CALLING_USER)
- : getUser();
+ : getTabOwnerUserHandleForLaunch();
}
private ResolverMultiProfilePagerAdapter createResolverMultiProfilePagerAdapterForTwoProfiles(
Intent[] initialIntents,
List<ResolveInfo> rList,
- boolean filterLastUsed) {
+ boolean filterLastUsed,
+ TargetDataLoader targetDataLoader) {
// In the edge case when we have 0 apps in the current profile and >1 apps in the other,
// the intent resolver is started in the other profile. Since this is the only case when
// this happens, we check for it here and set the current profile's tab.
int selectedProfile = getCurrentProfile();
UserHandle intentUser = getIntentUser();
- if (!getUser().equals(intentUser)) {
+ if (!getTabOwnerUserHandleForLaunch().equals(intentUser)) {
if (getPersonalProfileUserHandle().equals(intentUser)) {
selectedProfile = PROFILE_PERSONAL;
} else if (getWorkProfileUserHandle().equals(intentUser)) {
@@ -1174,7 +1200,8 @@ public class ResolverActivity extends FragmentActivity implements
rList,
(filterLastUsed && UserHandle.myUserId()
== getPersonalProfileUserHandle().getIdentifier()),
- /* userHandle */ getPersonalProfileUserHandle());
+ /* userHandle */ getPersonalProfileUserHandle(),
+ targetDataLoader);
UserHandle workProfileUserHandle = getWorkProfileUserHandle();
ResolverListAdapter workAdapter = createResolverListAdapter(
/* context */ this,
@@ -1183,7 +1210,8 @@ public class ResolverActivity extends FragmentActivity implements
rList,
(filterLastUsed && UserHandle.myUserId()
== workProfileUserHandle.getIdentifier()),
- /* userHandle */ workProfileUserHandle);
+ /* userHandle */ workProfileUserHandle,
+ targetDataLoader);
return new ResolverMultiProfilePagerAdapter(
/* context */ this,
personalAdapter,
@@ -1191,7 +1219,8 @@ public class ResolverActivity extends FragmentActivity implements
createEmptyStateProvider(getWorkProfileUserHandle()),
() -> mWorkProfileAvailability.isQuietModeEnabled(),
selectedProfile,
- getWorkProfileUserHandle());
+ getWorkProfileUserHandle(),
+ getCloneProfileUserHandle());
}
/**
@@ -1214,7 +1243,8 @@ public class ResolverActivity extends FragmentActivity implements
}
protected final @Profile int getCurrentProfile() {
- return (UserHandle.myUserId() == UserHandle.USER_SYSTEM ? PROFILE_PERSONAL : PROFILE_WORK);
+ return (getTabOwnerUserHandleForLaunch().equals(getPersonalProfileUserHandle())
+ ? PROFILE_PERSONAL : PROFILE_WORK);
}
protected final AnnotatedUserHandles getAnnotatedUserHandles() {
@@ -1225,10 +1255,43 @@ public class ResolverActivity extends FragmentActivity implements
return getAnnotatedUserHandles().personalProfileUserHandle;
}
+ // TODO: have tests override `getAnnotatedUserHandles()`, and make this method `final`.
+ // @NonFinalForTesting
+ @Nullable
+ protected UserHandle getWorkProfileUserHandle() {
+ return getAnnotatedUserHandles().workProfileUserHandle;
+ }
+
+ // TODO: have tests override `getAnnotatedUserHandles()`, and make this method `final`.
+ @Nullable
+ protected UserHandle getCloneProfileUserHandle() {
+ return getAnnotatedUserHandles().cloneProfileUserHandle;
+ }
+
+ // TODO: have tests override `getAnnotatedUserHandles()`, and make this method `final`.
+ protected UserHandle getTabOwnerUserHandleForLaunch() {
+ return getAnnotatedUserHandles().tabOwnerUserHandleForLaunch;
+ }
+
+ protected UserHandle getUserHandleSharesheetLaunchedAs() {
+ return getAnnotatedUserHandles().userHandleSharesheetLaunchedAs;
+ }
+
+
private boolean hasWorkProfile() {
return getWorkProfileUserHandle() != null;
}
+ private boolean hasCloneProfile() {
+ return getCloneProfileUserHandle() != null;
+ }
+
+ protected final boolean isLaunchedAsCloneProfile() {
+ return hasCloneProfile()
+ && getUserHandleSharesheetLaunchedAs().equals(getCloneProfileUserHandle());
+ }
+
+
protected final boolean shouldShowTabs() {
return hasWorkProfile();
}
@@ -1361,13 +1424,13 @@ public class ResolverActivity extends FragmentActivity implements
private String getForwardToPersonalMsg() {
return getSystemService(DevicePolicyManager.class).getResources().getString(
FORWARD_INTENT_TO_PERSONAL,
- () -> getString(com.android.internal.R.string.forward_intent_to_owner));
+ () -> getString(R.string.forward_intent_to_owner));
}
private String getForwardToWorkMsg() {
return getSystemService(DevicePolicyManager.class).getResources().getString(
FORWARD_INTENT_TO_WORK,
- () -> getString(com.android.internal.R.string.forward_intent_to_work));
+ () -> getString(R.string.forward_intent_to_work));
}
/**
@@ -1502,6 +1565,13 @@ public class ResolverActivity extends FragmentActivity implements
mAlwaysButton.setEnabled(false);
return;
}
+ // In case of clonedProfile being active, we do not allow the 'Always' option in the
+ // disambiguation dialog of Personal Profile as the package manager cannot distinguish
+ // between cross-profile preferred activities.
+ if (hasCloneProfile() && (mMultiProfilePagerAdapter.getCurrentPage() == PROFILE_PERSONAL)) {
+ mAlwaysButton.setEnabled(false);
+ return;
+ }
boolean enabled = false;
ResolveInfo ri = null;
if (hasValidSelection) {
@@ -1544,7 +1614,7 @@ public class ResolverActivity extends FragmentActivity implements
return getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_WORK_PROFILE_NOT_SUPPORTED,
() -> getString(
- com.android.internal.R.string.activity_resolver_work_profiles_support,
+ R.string.activity_resolver_work_profiles_support,
launcherName),
launcherName);
}
@@ -1576,6 +1646,16 @@ public class ResolverActivity extends FragmentActivity implements
}
}
+ /** Start the activity specified by the {@link TargetInfo}.*/
+ public final void safelyStartActivity(TargetInfo cti) {
+ // In case cloned apps are present, we would want to start those apps in cloned user
+ // space, which will not be same as adaptor's userHandle. resolveInfo.userHandle
+ // identifies the correct user space in such cases.
+ UserHandle activityUserHandle = getResolveInfoUserHandle(
+ cti.getResolveInfo(), mMultiProfilePagerAdapter.getCurrentUserHandle());
+ safelyStartActivityAsUser(cti, activityUserHandle, null);
+ }
+
/**
* Start activity as a fixed user handle.
* @param cti TargetInfo to be launched.
@@ -1598,7 +1678,8 @@ public class ResolverActivity extends FragmentActivity implements
}
}
- private void safelyStartActivityInternal(
+ @VisibleForTesting
+ protected void safelyStartActivityInternal(
TargetInfo cti, UserHandle user, @Nullable Bundle options) {
// If the target is suspended, the activity will not be successfully launched.
// Do not unregister from package manager updates in this case
@@ -1647,7 +1728,7 @@ public class ResolverActivity extends FragmentActivity implements
* Sets up the content view.
* @return <code>true</code> if the activity is finishing and creation should halt.
*/
- private boolean configureContentView() {
+ private boolean configureContentView(TargetDataLoader targetDataLoader) {
if (mMultiProfilePagerAdapter.getActiveListAdapter() == null) {
throw new IllegalStateException("mMultiProfilePagerAdapter.getCurrentListAdapter() "
+ "cannot be null.");
@@ -1664,7 +1745,7 @@ public class ResolverActivity extends FragmentActivity implements
}
if (shouldUseMiniResolver()) {
- configureMiniResolverContent();
+ configureMiniResolverContent(targetDataLoader);
Trace.endSection();
return false;
}
@@ -1687,7 +1768,7 @@ public class ResolverActivity extends FragmentActivity implements
* and asks the user if they'd like to open that cross-profile app or use the in-profile
* browser.
*/
- private void configureMiniResolverContent() {
+ private void configureMiniResolverContent(TargetDataLoader targetDataLoader) {
mLayoutId = R.layout.miniresolver;
setContentView(mLayoutId);
@@ -1702,15 +1783,15 @@ public class ResolverActivity extends FragmentActivity implements
// Load the icon asynchronously
ImageView icon = findViewById(com.android.internal.R.id.icon);
- inactiveAdapter.new LoadIconTask(otherProfileResolveInfo) {
- @Override
- protected void onPostExecute(Drawable drawable) {
- if (!isDestroyed()) {
- otherProfileResolveInfo.getDisplayIconHolder().setDisplayIcon(drawable);
- new ResolverListAdapter.ViewHolder(icon).bindIcon(otherProfileResolveInfo);
- }
- }
- }.execute();
+ targetDataLoader.loadAppTargetIcon(
+ otherProfileResolveInfo,
+ inactiveAdapter.getUserHandle(),
+ (drawable) -> {
+ if (!isDestroyed()) {
+ otherProfileResolveInfo.getDisplayIconHolder().setDisplayIcon(drawable);
+ new ResolverListAdapter.ViewHolder(icon).bindIcon(otherProfileResolveInfo);
+ }
+ });
((TextView) findViewById(com.android.internal.R.id.open_cross_profile)).setText(
getResources().getString(
@@ -1814,8 +1895,10 @@ public class ResolverActivity extends FragmentActivity implements
} else if (numberOfProfiles == 2
&& mMultiProfilePagerAdapter.getActiveListAdapter().isTabLoaded()
&& mMultiProfilePagerAdapter.getInactiveListAdapter().isTabLoaded()
- && (maybeAutolaunchIfNoAppsOnInactiveTab()
- || maybeAutolaunchIfCrossProfileSupported())) {
+ && maybeAutolaunchIfCrossProfileSupported()) {
+ // TODO(b/280988288): If the ChooserActivity is shown we should consider showing the
+ // correct intent-picker UIs (e.g., mini-resolver) if it was launched without
+ // ACTION_SEND.
return true;
}
return false;
@@ -1842,23 +1925,6 @@ public class ResolverActivity extends FragmentActivity implements
return false;
}
- private boolean maybeAutolaunchIfNoAppsOnInactiveTab() {
- int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount();
- if (count != 1) {
- return false;
- }
- ResolverListAdapter inactiveListAdapter =
- mMultiProfilePagerAdapter.getInactiveListAdapter();
- if (inactiveListAdapter.getUnfilteredCount() != 0) {
- return false;
- }
- TargetInfo target = mMultiProfilePagerAdapter.getActiveListAdapter()
- .targetInfoForPosition(0, false);
- safelyStartActivity(target);
- finish();
- return true;
- }
-
/**
* When we have a personal and a work profile, we auto launch in the following scenario:
* - There is 1 resolved target on each profile
@@ -2176,16 +2242,10 @@ public class ResolverActivity extends FragmentActivity implements
public final boolean useLayoutWithDefault() {
// We only use the default app layout when the profile of the active user has a
// filtered item. We always show the same default app even in the inactive user profile.
- boolean currentUserAdapterHasFilteredItem;
- if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
- == UserHandle.myUserId()) {
- currentUserAdapterHasFilteredItem =
- mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem();
- } else {
- currentUserAdapterHasFilteredItem =
- mMultiProfilePagerAdapter.getInactiveListAdapter().hasFilteredItem();
- }
- return mSupportsAlwaysUseOption && currentUserAdapterHasFilteredItem;
+ boolean adapterForCurrentUserHasFilteredItem =
+ mMultiProfilePagerAdapter.getListAdapterForUserHandle(
+ getTabOwnerUserHandleForLaunch()).hasFilteredItem();
+ return mSupportsAlwaysUseOption && adapterForCurrentUserHasFilteredItem;
}
/**
@@ -2204,7 +2264,14 @@ public class ResolverActivity extends FragmentActivity implements
return lhs == null ? rhs == null
: lhs.activityInfo == null ? rhs.activityInfo == null
: Objects.equals(lhs.activityInfo.name, rhs.activityInfo.name)
- && Objects.equals(lhs.activityInfo.packageName, rhs.activityInfo.packageName);
+ && Objects.equals(lhs.activityInfo.packageName, rhs.activityInfo.packageName)
+ // Comparing against resolveInfo.userHandle in case cloned apps are present,
+ // as they will have the same activityInfo.
+ && Objects.equals(
+ getResolveInfoUserHandle(lhs,
+ mMultiProfilePagerAdapter.getActiveListAdapter().getUserHandle()),
+ getResolveInfoUserHandle(rhs,
+ mMultiProfilePagerAdapter.getActiveListAdapter().getUserHandle()));
}
private boolean inactiveListAdapterHasItems() {
@@ -2311,4 +2378,44 @@ public class ResolverActivity extends FragmentActivity implements
}
}
}
+ /**
+ * Returns the {@link UserHandle} to use when querying resolutions for intents in a
+ * {@link ResolverListController} configured for the provided {@code userHandle}.
+ */
+ protected final UserHandle getQueryIntentsUser(UserHandle userHandle) {
+ return mLazyAnnotatedUserHandles.get().getQueryIntentsUser(userHandle);
+ }
+
+ /**
+ * Returns the {@link List} of {@link UserHandle} to pass on to the
+ * {@link ResolverRankerServiceResolverComparator} as per the provided {@code userHandle}.
+ */
+ @VisibleForTesting(visibility = PROTECTED)
+ public final List<UserHandle> getResolverRankerServiceUserHandleList(UserHandle userHandle) {
+ return getResolverRankerServiceUserHandleListInternal(userHandle);
+ }
+
+ @VisibleForTesting
+ protected List<UserHandle> getResolverRankerServiceUserHandleListInternal(
+ UserHandle userHandle) {
+ List<UserHandle> userList = new ArrayList<>();
+ userList.add(userHandle);
+ // Add clonedProfileUserHandle to the list only if we are:
+ // a. Building the Personal Tab.
+ // b. CloneProfile exists on the device.
+ if (userHandle.equals(getPersonalProfileUserHandle())
+ && getCloneProfileUserHandle() != null) {
+ userList.add(getCloneProfileUserHandle());
+ }
+ return userList;
+ }
+
+ /**
+ * This function is temporary in nature, and its usages will be replaced with just
+ * resolveInfo.userHandle, once it is available, once sharesheet is stable.
+ */
+ public static UserHandle getResolveInfoUserHandle(ResolveInfo resolveInfo,
+ UserHandle predictedHandle) {
+ return resolveInfo.userHandle;
+ }
}
diff --git a/java/src/com/android/intentresolver/ResolverListAdapter.java b/java/src/com/android/intentresolver/ResolverListAdapter.java
index eac275cc..282a672f 100644
--- a/java/src/com/android/intentresolver/ResolverListAdapter.java
+++ b/java/src/com/android/intentresolver/ResolverListAdapter.java
@@ -16,16 +16,10 @@
package com.android.intentresolver;
-import static android.content.Context.ACTIVITY_SERVICE;
-
-import android.animation.ObjectAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.PermissionChecker;
import android.content.pm.ActivityInfo;
import android.content.pm.LabeledIntent;
import android.content.pm.PackageManager;
@@ -43,7 +37,6 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.DecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
@@ -51,15 +44,15 @@ import android.widget.TextView;
import com.android.intentresolver.chooser.DisplayResolveInfo;
import com.android.intentresolver.chooser.TargetInfo;
+import com.android.intentresolver.icons.TargetDataLoader;
import com.android.internal.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
-import java.util.Map;
+import java.util.Set;
public class ResolverListAdapter extends BaseAdapter {
private static final String TAG = "ResolverListAdapter";
@@ -71,32 +64,32 @@ public class ResolverListAdapter extends BaseAdapter {
protected final LayoutInflater mInflater;
protected final ResolverListCommunicator mResolverListCommunicator;
protected final ResolverListController mResolverListController;
- protected final TargetPresentationGetter.Factory mPresentationFactory;
private final List<Intent> mIntents;
private final Intent[] mInitialIntents;
private final List<ResolveInfo> mBaseResolveList;
private final PackageManager mPm;
- private final int mIconDpi;
- private final boolean mIsAudioCaptureDevice;
+ private final TargetDataLoader mTargetDataLoader;
private final UserHandle mUserHandle;
private final Intent mTargetIntent;
- private final Map<DisplayResolveInfo, LoadIconTask> mIconLoaders = new HashMap<>();
- private final Map<DisplayResolveInfo, LoadLabelTask> mLabelLoaders = new HashMap<>();
+ private final Set<DisplayResolveInfo> mRequestedIcons = new HashSet<>();
+ private final Set<DisplayResolveInfo> mRequestedLabels = new HashSet<>();
private ResolveInfo mLastChosen;
private DisplayResolveInfo mOtherProfile;
private int mPlaceholderCount;
// This one is the list that the Adapter will actually present.
- private List<DisplayResolveInfo> mDisplayList;
+ private final List<DisplayResolveInfo> mDisplayList;
private List<ResolvedComponentInfo> mUnfilteredResolveList;
private int mLastChosenPosition = -1;
- private boolean mFilterLastUsed;
+ private final boolean mFilterLastUsed;
private Runnable mPostListReadyRunnable;
private boolean mIsTabLoaded;
+ // Represents the UserSpace in which the Initial Intents should be resolved.
+ private final UserHandle mInitialIntentsUserSpace;
public ResolverListAdapter(
Context context,
@@ -108,23 +101,22 @@ public class ResolverListAdapter extends BaseAdapter {
UserHandle userHandle,
Intent targetIntent,
ResolverListCommunicator resolverListCommunicator,
- boolean isAudioCaptureDevice) {
+ UserHandle initialIntentsUserSpace,
+ TargetDataLoader targetDataLoader) {
mContext = context;
mIntents = payloadIntents;
mInitialIntents = initialIntents;
mBaseResolveList = rList;
mInflater = LayoutInflater.from(context);
mPm = context.getPackageManager();
+ mTargetDataLoader = targetDataLoader;
mDisplayList = new ArrayList<>();
mFilterLastUsed = filterLastUsed;
mResolverListController = resolverListController;
mUserHandle = userHandle;
mTargetIntent = targetIntent;
mResolverListCommunicator = resolverListCommunicator;
- mIsAudioCaptureDevice = isAudioCaptureDevice;
- final ActivityManager am = (ActivityManager) mContext.getSystemService(ACTIVITY_SERVICE);
- mIconDpi = am.getLauncherLargeIconDensity();
- mPresentationFactory = new TargetPresentationGetter.Factory(mContext, mIconDpi);
+ mInitialIntentsUserSpace = initialIntentsUserSpace;
}
public final DisplayResolveInfo getFirstDisplayResolveInfo() {
@@ -176,19 +168,25 @@ public class ResolverListAdapter extends BaseAdapter {
}
/**
- * Returns the app share score of the given {@code componentName}.
+ * Returns the app share score of the given {@code targetInfo}.
*/
- public float getScore(ComponentName componentName) {
- return mResolverListController.getScore(componentName);
+ public float getScore(TargetInfo targetInfo) {
+ return mResolverListController.getScore(targetInfo);
}
- public void updateModel(ComponentName componentName) {
- mResolverListController.updateModel(componentName);
+ /**
+ * Updates the model about the chosen {@code targetInfo}.
+ */
+ public void updateModel(TargetInfo targetInfo) {
+ mResolverListController.updateModel(targetInfo);
}
- public void updateChooserCounts(String packageName, String action) {
+ /**
+ * Updates the model about Chooser Activity selection.
+ */
+ public void updateChooserCounts(String packageName, String action, UserHandle userHandle) {
mResolverListController.updateChooserCounts(
- packageName, getUserHandle().getIdentifier(), action);
+ packageName, userHandle, action);
}
List<ResolvedComponentInfo> getUnfilteredResolveList() {
@@ -356,12 +354,11 @@ public class ResolverListAdapter extends BaseAdapter {
if (otherProfileInfo != null) {
mOtherProfile = makeOtherProfileDisplayResolveInfo(
- mContext,
otherProfileInfo,
mPm,
mTargetIntent,
mResolverListCommunicator,
- mIconDpi);
+ mTargetDataLoader);
} else {
mOtherProfile = null;
try {
@@ -468,13 +465,14 @@ public class ResolverListAdapter extends BaseAdapter {
ri.icon = 0;
}
+ ri.userHandle = mInitialIntentsUserSpace;
addResolveInfo(DisplayResolveInfo.newDisplayResolveInfo(
ii,
ri,
ri.loadLabel(mPm),
null,
ii,
- mPresentationFactory.makePresentationGetter(ri)));
+ mTargetDataLoader.createPresentationGetter(ri)));
}
}
@@ -527,7 +525,7 @@ public class ResolverListAdapter extends BaseAdapter {
intent,
add,
(replaceIntent != null) ? replaceIntent : defaultIntent,
- mPresentationFactory.makePresentationGetter(add));
+ mTargetDataLoader.createPresentationGetter(add));
dri.setPinned(rci.isPinned());
if (rci.isPinned()) {
Log.i(TAG, "Pinned item: " + rci.name);
@@ -673,7 +671,7 @@ public class ResolverListAdapter extends BaseAdapter {
final ViewHolder holder = (ViewHolder) view.getTag();
if (info == null) {
holder.icon.setImageDrawable(loadIconPlaceholder());
- holder.bindLabel("", "", false);
+ holder.bindLabel("", "");
return;
}
@@ -682,10 +680,9 @@ public class ResolverListAdapter extends BaseAdapter {
if (dri.hasDisplayLabel()) {
holder.bindLabel(
dri.getDisplayLabel(),
- dri.getExtendedInfo(),
- alwaysShowSubLabel());
+ dri.getExtendedInfo());
} else {
- holder.bindLabel("", "", false);
+ holder.bindLabel("", "");
loadLabel(dri);
}
holder.bindIcon(info);
@@ -696,25 +693,37 @@ public class ResolverListAdapter extends BaseAdapter {
}
protected final void loadIcon(DisplayResolveInfo info) {
- LoadIconTask task = mIconLoaders.get(info);
- if (task == null) {
- task = new LoadIconTask(info);
- mIconLoaders.put(info, task);
- task.execute();
+ if (mRequestedIcons.add(info)) {
+ mTargetDataLoader.loadAppTargetIcon(
+ info,
+ getUserHandle(),
+ (drawable) -> onIconLoaded(info, drawable));
+ }
+ }
+
+ private void onIconLoaded(DisplayResolveInfo displayResolveInfo, Drawable drawable) {
+ if (getOtherProfile() == displayResolveInfo) {
+ mResolverListCommunicator.updateProfileViewButton();
+ } else if (!displayResolveInfo.hasDisplayIcon()) {
+ displayResolveInfo.getDisplayIconHolder().setDisplayIcon(drawable);
+ notifyDataSetChanged();
}
}
private void loadLabel(DisplayResolveInfo info) {
- LoadLabelTask task = mLabelLoaders.get(info);
- if (task == null) {
- task = createLoadLabelTask(info);
- mLabelLoaders.put(info, task);
- task.execute();
+ if (mRequestedLabels.add(info)) {
+ mTargetDataLoader.loadLabel(info, (result) -> onLabelLoaded(info, result));
}
}
- protected LoadLabelTask createLoadLabelTask(DisplayResolveInfo info) {
- return new LoadLabelTask(info);
+ protected final void onLabelLoaded(
+ DisplayResolveInfo displayResolveInfo, CharSequence[] result) {
+ if (displayResolveInfo.hasDisplayLabel()) {
+ return;
+ }
+ displayResolveInfo.setDisplayLabel(result[0]);
+ displayResolveInfo.setExtendedInfo(result[1]);
+ notifyDataSetChanged();
}
public void onDestroy() {
@@ -725,16 +734,8 @@ public class ResolverListAdapter extends BaseAdapter {
if (mResolverListController != null) {
mResolverListController.destroy();
}
- cancelTasks(mIconLoaders.values());
- cancelTasks(mLabelLoaders.values());
- mIconLoaders.clear();
- mLabelLoaders.clear();
- }
-
- private <T extends AsyncTask> void cancelTasks(Collection<T> tasks) {
- for (T task: tasks) {
- task.cancel(false);
- }
+ mRequestedIcons.clear();
+ mRequestedLabels.clear();
}
private static ColorMatrixColorFilter getSuspendedColorMatrix() {
@@ -760,37 +761,15 @@ public class ResolverListAdapter extends BaseAdapter {
return sSuspendedMatrixColorFilter;
}
- Drawable loadIconForResolveInfo(ResolveInfo ri) {
- // Load icons based on the current process. If in work profile icons should be badged.
- return mPresentationFactory.makePresentationGetter(ri).getIcon(getUserHandle());
- }
-
protected final Drawable loadIconPlaceholder() {
return mContext.getDrawable(R.drawable.resolver_icon_placeholder);
}
void loadFilteredItemIconTaskAsync(@NonNull ImageView iconView) {
final DisplayResolveInfo iconInfo = getFilteredItem();
- if (iconView != null && iconInfo != null) {
- new AsyncTask<Void, Void, Drawable>() {
- @Override
- protected Drawable doInBackground(Void... params) {
- Drawable drawable;
- try {
- drawable = loadIconForResolveInfo(iconInfo.getResolveInfo());
- } catch (Exception e) {
- ComponentName componentName = iconInfo.getResolvedComponentName();
- Log.e(TAG, "Failed to load app icon for " + componentName, e);
- drawable = loadIconPlaceholder();
- }
- return drawable;
- }
-
- @Override
- protected void onPostExecute(Drawable d) {
- iconView.setImageDrawable(d);
- }
- }.execute();
+ if (iconInfo != null) {
+ mTargetDataLoader.loadAppTargetIcon(
+ iconInfo, getUserHandle(), iconView::setImageDrawable);
}
}
@@ -819,10 +798,6 @@ public class ResolverListAdapter extends BaseAdapter {
mIsTabLoaded = true;
}
- protected boolean alwaysShowSubLabel() {
- return false;
- }
-
/**
* Find the first element in a list of {@code ResolvedComponentInfo} objects whose
* {@code ResolveInfo} specifies a {@code targetUserId} other than the current user.
@@ -850,12 +825,11 @@ public class ResolverListAdapter extends BaseAdapter {
* of an element in the resolve list).
*/
private static DisplayResolveInfo makeOtherProfileDisplayResolveInfo(
- Context context,
ResolvedComponentInfo resolvedComponentInfo,
PackageManager pm,
Intent targetIntent,
ResolverListCommunicator resolverListCommunicator,
- int iconDpi) {
+ TargetDataLoader targetDataLoader) {
ResolveInfo resolveInfo = resolvedComponentInfo.getResolveInfoAt(0);
Intent pOrigIntent = resolverListCommunicator.getReplacementIntent(
@@ -865,8 +839,7 @@ public class ResolverListAdapter extends BaseAdapter {
resolveInfo.activityInfo, targetIntent);
TargetPresentationGetter presentationGetter =
- new TargetPresentationGetter.Factory(context, iconDpi)
- .makePresentationGetter(resolveInfo);
+ targetDataLoader.createPresentationGetter(resolveInfo);
return DisplayResolveInfo.newDisplayResolveInfo(
resolvedComponentInfo.getIntentAt(0),
@@ -913,7 +886,6 @@ public class ResolverListAdapter extends BaseAdapter {
*/
@VisibleForTesting
public static class ViewHolder {
- private static final long IMAGE_FADE_IN_MILLIS = 150;
public View itemView;
public Drawable defaultItemViewBackground;
@@ -930,17 +902,19 @@ public class ResolverListAdapter extends BaseAdapter {
icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
}
- public void bindLabel(CharSequence label, CharSequence subLabel, boolean showSubLabel) {
+ public void bindLabel(CharSequence label, CharSequence subLabel) {
text.setText(label);
if (TextUtils.equals(label, subLabel)) {
subLabel = null;
}
- text2.setText(subLabel);
- if (showSubLabel || subLabel != null) {
+ if (!TextUtils.isEmpty(subLabel)) {
+ text.setMaxLines(1);
+ text2.setText(subLabel);
text2.setVisibility(View.VISIBLE);
} else {
+ text.setMaxLines(2);
text2.setVisibility(View.GONE);
}
@@ -951,23 +925,12 @@ public class ResolverListAdapter extends BaseAdapter {
itemView.setContentDescription(description);
}
- public void bindIcon(TargetInfo info) {
- bindIcon(info, false);
- }
-
/**
- * Bind view holder to a TargetInfo, run icon reveal animation, if required.
+ * Bind view holder to a TargetInfo.
*/
- public void bindIcon(TargetInfo info, boolean animate) {
+ public void bindIcon(TargetInfo info) {
Drawable displayIcon = info.getDisplayIconHolder().getDisplayIcon();
- boolean runAnimation = animate && (icon.getDrawable() == null) && (displayIcon != null);
icon.setImageDrawable(displayIcon);
- if (runAnimation) {
- ObjectAnimator animator = ObjectAnimator.ofFloat(icon, "alpha", 0.0f, 1.0f);
- animator.setInterpolator(new DecelerateInterpolator(1.0f));
- animator.setDuration(IMAGE_FADE_IN_MILLIS);
- animator.start();
- }
if (info.isSuspended()) {
icon.setColorFilter(getSuspendedColorMatrix());
} else {
@@ -975,86 +938,4 @@ public class ResolverListAdapter extends BaseAdapter {
}
}
}
-
- protected class LoadLabelTask extends AsyncTask<Void, Void, CharSequence[]> {
- private final DisplayResolveInfo mDisplayResolveInfo;
-
- protected LoadLabelTask(DisplayResolveInfo dri) {
- mDisplayResolveInfo = dri;
- }
-
- @Override
- protected CharSequence[] doInBackground(Void... voids) {
- TargetPresentationGetter pg = mPresentationFactory.makePresentationGetter(
- mDisplayResolveInfo.getResolveInfo());
-
- if (mIsAudioCaptureDevice) {
- // This is an audio capture device, so check record permissions
- ActivityInfo activityInfo = mDisplayResolveInfo.getResolveInfo().activityInfo;
- String packageName = activityInfo.packageName;
-
- int uid = activityInfo.applicationInfo.uid;
- boolean hasRecordPermission =
- PermissionChecker.checkPermissionForPreflight(
- mContext,
- android.Manifest.permission.RECORD_AUDIO, -1, uid,
- packageName)
- == android.content.pm.PackageManager.PERMISSION_GRANTED;
-
- if (!hasRecordPermission) {
- // Doesn't have record permission, so warn the user
- return new CharSequence[] {
- pg.getLabel(),
- mContext.getString(R.string.usb_device_resolve_prompt_warn)
- };
- }
- }
-
- return new CharSequence[] {
- pg.getLabel(),
- pg.getSubLabel()
- };
- }
-
- @Override
- protected void onPostExecute(CharSequence[] result) {
- if (mDisplayResolveInfo.hasDisplayLabel()) {
- return;
- }
- mDisplayResolveInfo.setDisplayLabel(result[0]);
- mDisplayResolveInfo.setExtendedInfo(result[1]);
- notifyDataSetChanged();
- }
- }
-
- class LoadIconTask extends AsyncTask<Void, Void, Drawable> {
- protected final DisplayResolveInfo mDisplayResolveInfo;
- private final ResolveInfo mResolveInfo;
-
- LoadIconTask(DisplayResolveInfo dri) {
- mDisplayResolveInfo = dri;
- mResolveInfo = dri.getResolveInfo();
- }
-
- @Override
- protected Drawable doInBackground(Void... params) {
- try {
- return loadIconForResolveInfo(mResolveInfo);
- } catch (Exception e) {
- ComponentName componentName = mDisplayResolveInfo.getResolvedComponentName();
- Log.e(TAG, "Failed to load app icon for " + componentName, e);
- return loadIconPlaceholder();
- }
- }
-
- @Override
- protected void onPostExecute(Drawable d) {
- if (getOtherProfile() == mDisplayResolveInfo) {
- mResolverListCommunicator.updateProfileViewButton();
- } else if (!mDisplayResolveInfo.hasDisplayIcon()) {
- mDisplayResolveInfo.getDisplayIconHolder().setDisplayIcon(d);
- notifyDataSetChanged();
- }
- }
- }
}
diff --git a/java/src/com/android/intentresolver/ResolverListController.java b/java/src/com/android/intentresolver/ResolverListController.java
index b4544c43..d5a5fedf 100644
--- a/java/src/com/android/intentresolver/ResolverListController.java
+++ b/java/src/com/android/intentresolver/ResolverListController.java
@@ -32,8 +32,8 @@ import android.os.UserHandle;
import android.util.Log;
import com.android.intentresolver.chooser.DisplayResolveInfo;
+import com.android.intentresolver.chooser.TargetInfo;
import com.android.intentresolver.model.AbstractResolverComparator;
-import com.android.intentresolver.model.ResolverRankerServiceResolverComparator;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
@@ -58,6 +58,7 @@ public class ResolverListController {
private static final String TAG = "ResolverListController";
private static final boolean DEBUG = false;
+ private final UserHandle mQueryIntentsAsUser;
private AbstractResolverComparator mResolverComparator;
private boolean isComputed = false;
@@ -67,25 +68,16 @@ public class ResolverListController {
PackageManager pm,
Intent targetIntent,
String referrerPackage,
- int launchedFromUid) {
- this(context, pm, targetIntent, referrerPackage, launchedFromUid,
- new ResolverRankerServiceResolverComparator(
- context, targetIntent, referrerPackage, null, null));
- }
-
- public ResolverListController(
- Context context,
- PackageManager pm,
- Intent targetIntent,
- String referrerPackage,
int launchedFromUid,
- AbstractResolverComparator resolverComparator) {
+ AbstractResolverComparator resolverComparator,
+ UserHandle queryIntentsAsUser) {
mContext = context;
mpm = pm;
mLaunchedFromUid = launchedFromUid;
mTargetIntent = targetIntent;
mReferrerPackage = referrerPackage;
mResolverComparator = resolverComparator;
+ mQueryIntentsAsUser = queryIntentsAsUser;
}
@VisibleForTesting
@@ -118,7 +110,8 @@ public class ResolverListController {
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
- | (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0);
+ | (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0)
+ | PackageManager.MATCH_CLONE_PROFILE;
return getResolversForIntentAsUserInternal(intents, userHandle, baseFlags);
}
@@ -154,6 +147,10 @@ public class ResolverListController {
final int intoCount = into.size();
for (int i = 0; i < fromCount; i++) {
final ResolveInfo newInfo = from.get(i);
+ if (newInfo.userHandle == null) {
+ Log.w(TAG, "Skipping ResolveInfo with no userHandle: " + newInfo);
+ continue;
+ }
boolean found = false;
// Only loop to the end of into as it was before we started; no dupes in from.
for (int j = 0; j < intoCount; j++) {
@@ -344,22 +341,28 @@ public class ResolverListController {
@VisibleForTesting
public float getScore(DisplayResolveInfo target) {
- return mResolverComparator.getScore(target.getResolvedComponentName());
+ return mResolverComparator.getScore(target);
}
/**
* Returns the app share score of the given {@code componentName}.
*/
- public float getScore(ComponentName componentName) {
- return mResolverComparator.getScore(componentName);
+ public float getScore(TargetInfo targetInfo) {
+ return mResolverComparator.getScore(targetInfo);
}
- public void updateModel(ComponentName componentName) {
- mResolverComparator.updateModel(componentName);
+ /**
+ * Updates the model about the chosen {@code targetInfo}.
+ */
+ public void updateModel(TargetInfo targetInfo) {
+ mResolverComparator.updateModel(targetInfo);
}
- public void updateChooserCounts(String packageName, int userId, String action) {
- mResolverComparator.updateChooserCounts(packageName, userId, action);
+ /**
+ * Updates the model about Chooser Activity selection.
+ */
+ public void updateChooserCounts(String packageName, UserHandle user, String action) {
+ mResolverComparator.updateChooserCounts(packageName, user, action);
}
public void destroy() {
diff --git a/java/src/com/android/intentresolver/ResolverMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/ResolverMultiProfilePagerAdapter.java
index 48e3b62d..85d97ad5 100644
--- a/java/src/com/android/intentresolver/ResolverMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/ResolverMultiProfilePagerAdapter.java
@@ -44,7 +44,8 @@ public class ResolverMultiProfilePagerAdapter extends
ResolverListAdapter adapter,
EmptyStateProvider emptyStateProvider,
Supplier<Boolean> workProfileQuietModeChecker,
- UserHandle workProfileUserHandle) {
+ UserHandle workProfileUserHandle,
+ UserHandle cloneProfileUserHandle) {
this(
context,
ImmutableList.of(adapter),
@@ -52,6 +53,7 @@ public class ResolverMultiProfilePagerAdapter extends
workProfileQuietModeChecker,
/* defaultProfile= */ 0,
workProfileUserHandle,
+ cloneProfileUserHandle,
new BottomPaddingOverrideSupplier());
}
@@ -61,7 +63,8 @@ public class ResolverMultiProfilePagerAdapter extends
EmptyStateProvider emptyStateProvider,
Supplier<Boolean> workProfileQuietModeChecker,
@Profile int defaultProfile,
- UserHandle workProfileUserHandle) {
+ UserHandle workProfileUserHandle,
+ UserHandle cloneProfileUserHandle) {
this(
context,
ImmutableList.of(personalAdapter, workAdapter),
@@ -69,6 +72,7 @@ public class ResolverMultiProfilePagerAdapter extends
workProfileQuietModeChecker,
defaultProfile,
workProfileUserHandle,
+ cloneProfileUserHandle,
new BottomPaddingOverrideSupplier());
}
@@ -79,6 +83,7 @@ public class ResolverMultiProfilePagerAdapter extends
Supplier<Boolean> workProfileQuietModeChecker,
@Profile int defaultProfile,
UserHandle workProfileUserHandle,
+ UserHandle cloneProfileUserHandle,
BottomPaddingOverrideSupplier bottomPaddingOverrideSupplier) {
super(
context,
@@ -89,6 +94,7 @@ public class ResolverMultiProfilePagerAdapter extends
workProfileQuietModeChecker,
defaultProfile,
workProfileUserHandle,
+ cloneProfileUserHandle,
() -> (ViewGroup) LayoutInflater.from(context).inflate(
R.layout.resolver_list_per_profile, null, false),
bottomPaddingOverrideSupplier);
diff --git a/java/src/com/android/intentresolver/WorkProfilePausedEmptyStateProvider.java b/java/src/com/android/intentresolver/WorkProfilePausedEmptyStateProvider.java
index 0333039b..2f3dfbd5 100644
--- a/java/src/com/android/intentresolver/WorkProfilePausedEmptyStateProvider.java
+++ b/java/src/com/android/intentresolver/WorkProfilePausedEmptyStateProvider.java
@@ -29,7 +29,6 @@ import android.stats.devicepolicy.nano.DevicePolicyEnums;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyState;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStateProvider;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.OnSwitchOnWorkSelectedListener;
-import com.android.internal.R;
/**
* Chooser/ResolverActivity empty state provider that returns empty state which is shown when
diff --git a/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java b/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java
index 29be6dc6..09cf319f 100644
--- a/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java
+++ b/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java
@@ -184,9 +184,10 @@ public class DisplayResolveInfo implements TargetInfo {
return null;
}
- Intent merged = new Intent(matchingBase);
- merged.fillIn(proposedRefinement, 0);
- return new DisplayResolveInfo(this, merged, mPresentationGetter);
+ return new DisplayResolveInfo(
+ this,
+ TargetInfo.mergeRefinementIntoMatchingBaseIntent(matchingBase, proposedRefinement),
+ mPresentationGetter);
}
@Override
diff --git a/java/src/com/android/intentresolver/chooser/ImmutableTargetInfo.java b/java/src/com/android/intentresolver/chooser/ImmutableTargetInfo.java
index 2d9683e1..10d4415a 100644
--- a/java/src/com/android/intentresolver/chooser/ImmutableTargetInfo.java
+++ b/java/src/com/android/intentresolver/chooser/ImmutableTargetInfo.java
@@ -427,8 +427,8 @@ public final class ImmutableTargetInfo implements TargetInfo {
return null;
}
- Intent merged = new Intent(matchingBase);
- merged.fillIn(proposedRefinement, 0);
+ Intent merged = TargetInfo.mergeRefinementIntoMatchingBaseIntent(
+ matchingBase, proposedRefinement);
return toBuilder().setBaseIntentToSend(merged).build();
}
diff --git a/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java b/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java
index 1fbe2da7..5766db0e 100644
--- a/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java
+++ b/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java
@@ -195,13 +195,13 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
mResolvedComponentName = getResolvedComponentName(mSourceInfo, mBackupResolveInfo);
- mAllSourceIntents = getAllSourceIntents(sourceInfo);
-
mBaseIntentToSend = getBaseIntentToSend(
baseIntentToSend,
mResolvedIntent,
mReferrerFillInIntent);
+ mAllSourceIntents = getAllSourceIntents(sourceInfo, mBaseIntentToSend);
+
mHashProvider = context -> {
final String plaintext =
getChooserTargetComponentName().getPackageName()
@@ -279,9 +279,9 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
return null;
}
- Intent merged = new Intent(matchingBase);
- merged.fillIn(proposedRefinement, 0);
- return new SelectableTargetInfo(this, merged);
+ return new SelectableTargetInfo(
+ this,
+ TargetInfo.mergeRefinementIntoMatchingBaseIntent(matchingBase, proposedRefinement));
}
@Override
@@ -395,11 +395,22 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
return sb.toString();
}
- private static List<Intent> getAllSourceIntents(@Nullable DisplayResolveInfo sourceInfo) {
+ private static List<Intent> getAllSourceIntents(
+ @Nullable DisplayResolveInfo sourceInfo, Intent fallbackSourceIntent) {
final List<Intent> results = new ArrayList<>();
if (sourceInfo != null) {
- // We only queried the service for the first one in our sourceinfo.
- results.add(sourceInfo.getAllSourceIntents().get(0));
+ results.addAll(sourceInfo.getAllSourceIntents());
+ } else {
+ // This target wasn't joined to a `DisplayResolveInfo` result from our intent-resolution
+ // step, so it was provided directly by the caller. We don't support alternate intents
+ // in this case, but we still permit refinement of the intent we'll dispatch; e.g.,
+ // clients may use this hook to defer the computation of "lazy" extras in their share
+ // payload. Note this accommodation isn't strictly "necessary" because clients could
+ // always implement equivalent behavior by pointing custom targets back at their own app
+ // for any amount of further refinement/modification outside of the Sharesheet flow;
+ // nevertheless, it's offered as a convenience for clients who may expect their normal
+ // refinement logic to apply equally in the case of these "special targets."
+ results.add(fallbackSourceIntent);
}
return results;
}
diff --git a/java/src/com/android/intentresolver/chooser/TargetInfo.java b/java/src/com/android/intentresolver/chooser/TargetInfo.java
index 2f48704c..9d793994 100644
--- a/java/src/com/android/intentresolver/chooser/TargetInfo.java
+++ b/java/src/com/android/intentresolver/chooser/TargetInfo.java
@@ -454,4 +454,49 @@ public interface TargetInfo {
intent.fixUris(currentUserId);
}
}
+
+ /**
+ * Derive a "complete" intent from a proposed `refinement` intent by merging it into a matching
+ * `base` intent, without modifying the filter-equality properties of the `base` intent, while
+ * still allowing the `refinement` to replace Share "payload" fields.
+ * Note! Callers are responsible for ensuring that the `base` is a suitable match for the given
+ * `refinement`, such that the two can be merged without modifying filter-equality properties.
+ */
+ static Intent mergeRefinementIntoMatchingBaseIntent(Intent base, Intent refinement) {
+ Intent mergedIntent = new Intent(base);
+
+ /* Copy over any fields from the `refinement` that weren't already specified by the `base`,
+ * along with the refined ClipData (if present, even if that overwrites data given in the
+ * `base` intent).
+ *
+ * Refinement may have modified the payload content stored in the ClipData; such changes
+ * are permitted in refinement since ClipData isn't a factor in the determination of
+ * `Intent.filterEquals()` (which must be preserved as an invariant of refinement). */
+ mergedIntent.fillIn(refinement, Intent.FILL_IN_CLIP_DATA);
+
+ /* Refinement may also modify payload content held in the 'extras' representation, as again
+ * those attributes aren't a factor in determining filter-equality. There is no `FILL_IN_*`
+ * flag that would allow the refinement to overwrite existing keys in the `base` extras, so
+ * here we have to implement the logic ourselves.
+ *
+ * Note this still doesn't imply that the refined intent is the final authority on extras;
+ * in particular, `SelectableTargetInfo.mActivityStarter` uses `Intent.putExtras(Bundle)` to
+ * merge in the `mChooserTargetIntentExtras` (i.e., the `EXTRA_SHORTCUT_ID`), which will
+ * overwrite any existing value.
+ *
+ * TODO: formalize the precedence and make sure extras are set in the appropriate stages,
+ * instead of relying on maintainers to know that (e.g.) authoritative changes belong in the
+ * `TargetActivityStarter`. Otherwise, any extras-based data that Sharesheet adds internally
+ * might be susceptible to "spoofing" from the refinement activity. */
+ mergedIntent.putExtras(refinement); // Re-merge extras to favor refinement.
+
+ // TODO(b/279067078): consider how to populate the "merged" ClipData. The `base`
+ // already has non-null ClipData due to the implicit migration in Intent, so if the
+ // refinement modified any of the payload extras, they *must* also provide a modified
+ // ClipData, or else the updated "extras" payload will be inconsistent with the
+ // pre-refinement ClipData when they're merged together. We may be able to do better,
+ // but there are complicated tradeoffs.
+
+ return mergedIntent;
+ }
}
diff --git a/java/src/com/android/intentresolver/contentpreview/BasePreviewViewModel.kt b/java/src/com/android/intentresolver/contentpreview/BasePreviewViewModel.kt
new file mode 100644
index 00000000..103e8bf4
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/BasePreviewViewModel.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import androidx.annotation.MainThread
+import androidx.lifecycle.ViewModel
+import com.android.intentresolver.ChooserRequestParameters
+
+/** A contract for the preview view model. Added for testing. */
+abstract class BasePreviewViewModel : ViewModel() {
+ @MainThread
+ abstract fun createOrReuseProvider(
+ chooserRequest: ChooserRequestParameters
+ ): PreviewDataProvider
+
+ @MainThread abstract fun createOrReuseImageLoader(): ImageLoader
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
index 205be444..e8367c4e 100644
--- a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
@@ -21,51 +21,49 @@ import static com.android.intentresolver.contentpreview.ContentPreviewType.CONTE
import static com.android.intentresolver.contentpreview.ContentPreviewType.CONTENT_PREVIEW_TEXT;
import android.content.ClipData;
-import android.content.ClipDescription;
-import android.content.ContentInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
-import android.os.RemoteException;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.Lifecycle;
-import com.android.intentresolver.ImageLoader;
-import com.android.intentresolver.flags.FeatureFlagRepository;
import com.android.intentresolver.widget.ActionRow;
-import com.android.intentresolver.widget.ImagePreviewView;
import com.android.intentresolver.widget.ImagePreviewView.TransitionElementStatusCallback;
-import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
/**
* Collection of helpers for building the content preview UI displayed in
* {@link com.android.intentresolver.ChooserActivity}.
- *
* A content preview façade.
*/
public final class ChooserContentPreviewUi {
+
+ private final Lifecycle mLifecycle;
+
/**
* Delegate to build the default system action buttons to display in the preview layout, if/when
* they're determined to be appropriate for the particular preview we display.
* TODO: clarify why action buttons are part of preview logic.
*/
public interface ActionFactory {
- /** Create an action that copies the share content to the clipboard. */
- ActionRow.Action createCopyButton();
-
- /** Create an action that opens the share content in a system-default editor. */
+ /**
+ * @return Runnable to be run when an edit button is clicked (if available).
+ */
@Nullable
- ActionRow.Action createEditButton();
+ Runnable getEditButtonRunnable();
- /** Create an "Share to Nearby" action. */
+ /**
+ * @return Runnable to be run when a copy button is clicked (if available).
+ */
@Nullable
- ActionRow.Action createNearbyButton();
+ Runnable getCopyButtonRunnable();
/** Create custom actions */
List<ActionRow.Action> createCustomActions();
@@ -74,7 +72,7 @@ public final class ChooserContentPreviewUi {
* Provides a share modification action, if any.
*/
@Nullable
- Runnable getModifyShareAction();
+ ActionRow.Action getModifyShareAction();
/**
* <p>
@@ -88,76 +86,90 @@ public final class ChooserContentPreviewUi {
Consumer<Boolean> getExcludeSharedTextAction();
}
- /**
- * Testing shim to specify whether a given mime type is considered to be an "image."
- *
- * TODO: move away from {@link ChooserActivityOverrideData} as a model to configure our tests,
- * then migrate {@link com.android.intentresolver.ChooserActivity#isImageType(String)} into this
- * class.
- */
- public interface ImageMimeTypeClassifier {
- /** @return whether the specified {@code mimeType} is classified as an "image" type. */
- boolean isImageType(String mimeType);
- }
-
- private final ContentPreviewUi mContentPreviewUi;
+ @VisibleForTesting
+ final ContentPreviewUi mContentPreviewUi;
public ChooserContentPreviewUi(
+ Lifecycle lifecycle,
+ PreviewDataProvider previewData,
Intent targetIntent,
- ContentInterface contentResolver,
- ImageMimeTypeClassifier imageClassifier,
ImageLoader imageLoader,
ActionFactory actionFactory,
TransitionElementStatusCallback transitionElementStatusCallback,
- FeatureFlagRepository featureFlagRepository) {
-
+ HeadlineGenerator headlineGenerator) {
+ mLifecycle = lifecycle;
mContentPreviewUi = createContentPreview(
+ previewData,
targetIntent,
- contentResolver,
- imageClassifier,
+ DefaultMimeTypeClassifier.INSTANCE,
imageLoader,
actionFactory,
transitionElementStatusCallback,
- featureFlagRepository);
+ headlineGenerator);
if (mContentPreviewUi.getType() != CONTENT_PREVIEW_IMAGE) {
transitionElementStatusCallback.onAllTransitionElementsReady();
}
}
private ContentPreviewUi createContentPreview(
+ PreviewDataProvider previewData,
Intent targetIntent,
- ContentInterface contentResolver,
- ImageMimeTypeClassifier imageClassifier,
+ MimeTypeClassifier typeClassifier,
ImageLoader imageLoader,
ActionFactory actionFactory,
TransitionElementStatusCallback transitionElementStatusCallback,
- FeatureFlagRepository featureFlagRepository) {
- int type = findPreferredContentPreview(targetIntent, contentResolver, imageClassifier);
- switch (type) {
- case CONTENT_PREVIEW_TEXT:
- return createTextPreview(
- targetIntent, actionFactory, imageLoader, featureFlagRepository);
-
- case CONTENT_PREVIEW_FILE:
- return new FileContentPreviewUi(
- extractContentUris(targetIntent),
- actionFactory,
- imageLoader,
- contentResolver,
- featureFlagRepository);
-
- case CONTENT_PREVIEW_IMAGE:
- return createImagePreview(
- targetIntent,
- actionFactory,
- contentResolver,
- imageClassifier,
- imageLoader,
- transitionElementStatusCallback,
- featureFlagRepository);
+ HeadlineGenerator headlineGenerator) {
+
+ int previewType = previewData.getPreviewType();
+ if (previewType == CONTENT_PREVIEW_TEXT) {
+ return createTextPreview(
+ mLifecycle,
+ targetIntent,
+ actionFactory,
+ imageLoader,
+ headlineGenerator);
+ }
+ if (previewType == CONTENT_PREVIEW_FILE) {
+ FileContentPreviewUi fileContentPreviewUi = new FileContentPreviewUi(
+ previewData.getUriCount(),
+ actionFactory,
+ headlineGenerator);
+ if (previewData.getUriCount() > 0) {
+ previewData.getFirstFileName(
+ mLifecycle, fileContentPreviewUi::setFirstFileName);
+ }
+ return fileContentPreviewUi;
+ }
+ boolean isSingleImageShare = previewData.getUriCount() == 1
+ && typeClassifier.isImageType(previewData.getFirstFileInfo().getMimeType());
+ CharSequence text = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT);
+ if (!TextUtils.isEmpty(text)) {
+ FilesPlusTextContentPreviewUi previewUi =
+ new FilesPlusTextContentPreviewUi(
+ mLifecycle,
+ isSingleImageShare,
+ previewData.getUriCount(),
+ targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT),
+ actionFactory,
+ imageLoader,
+ typeClassifier,
+ headlineGenerator);
+ if (previewData.getUriCount() > 0) {
+ previewData.getFileMetadataForImagePreview(
+ mLifecycle, previewUi::updatePreviewMetadata);
+ }
+ return previewUi;
}
- return new NoContextPreviewUi(type);
+ UnifiedContentPreviewUi unifiedContentPreviewUi = new UnifiedContentPreviewUi(
+ isSingleImageShare,
+ actionFactory,
+ imageLoader,
+ typeClassifier,
+ transitionElementStatusCallback,
+ headlineGenerator);
+ previewData.getFileMetadataForImagePreview(mLifecycle, unifiedContentPreviewUi::setFiles);
+ return unifiedContentPreviewUi;
}
public int getPreferredContentPreview() {
@@ -174,68 +186,12 @@ public final class ChooserContentPreviewUi {
return mContentPreviewUi.display(resources, layoutInflater, parent);
}
- /** Determine the most appropriate type of preview to show for the provided {@link Intent}. */
- @ContentPreviewType
- private static int findPreferredContentPreview(
- Intent targetIntent,
- ContentInterface resolver,
- ImageMimeTypeClassifier imageClassifier) {
- /* In {@link android.content.Intent#getType}, the app may specify a very general mime type
- * that broadly covers all data being shared, such as {@literal *}/* when sending an image
- * and text. We therefore should inspect each item for the preferred type, in order: IMAGE,
- * FILE, TEXT. */
- final String action = targetIntent.getAction();
- final String type = targetIntent.getType();
- final boolean isSend = Intent.ACTION_SEND.equals(action);
- final boolean isSendMultiple = Intent.ACTION_SEND_MULTIPLE.equals(action);
-
- if (!(isSend || isSendMultiple)
- || (type != null && ClipDescription.compareMimeTypes(type, "text/*"))) {
- return CONTENT_PREVIEW_TEXT;
- }
-
- if (isSend) {
- Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
- return findPreferredContentPreview(uri, resolver, imageClassifier);
- }
-
- List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
- if (uris == null || uris.isEmpty()) {
- return CONTENT_PREVIEW_TEXT;
- }
-
- for (Uri uri : uris) {
- // Defaulting to file preview when there are mixed image/file types is
- // preferable, as it shows the user the correct number of items being shared
- int uriPreviewType = findPreferredContentPreview(uri, resolver, imageClassifier);
- if (uriPreviewType == CONTENT_PREVIEW_FILE) {
- return CONTENT_PREVIEW_FILE;
- }
- }
-
- return CONTENT_PREVIEW_IMAGE;
- }
-
- @ContentPreviewType
- private static int findPreferredContentPreview(
- Uri uri, ContentInterface resolver, ImageMimeTypeClassifier imageClassifier) {
- if (uri == null) {
- return CONTENT_PREVIEW_TEXT;
- }
-
- String mimeType = null;
- try {
- mimeType = resolver.getType(uri);
- } catch (RemoteException ignored) {
- }
- return imageClassifier.isImageType(mimeType) ? CONTENT_PREVIEW_IMAGE : CONTENT_PREVIEW_FILE;
- }
-
private static TextContentPreviewUi createTextPreview(
+ Lifecycle lifecycle,
Intent targetIntent,
ChooserContentPreviewUi.ActionFactory actionFactory,
ImageLoader imageLoader,
- FeatureFlagRepository featureFlagRepository) {
+ HeadlineGenerator headlineGenerator) {
CharSequence sharingText = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT);
String previewTitle = targetIntent.getStringExtra(Intent.EXTRA_TITLE);
ClipData previewData = targetIntent.getClipData();
@@ -247,64 +203,12 @@ public final class ChooserContentPreviewUi {
}
}
return new TextContentPreviewUi(
+ lifecycle,
sharingText,
previewTitle,
previewThumbnail,
actionFactory,
imageLoader,
- featureFlagRepository);
- }
-
- static ImageContentPreviewUi createImagePreview(
- Intent targetIntent,
- ChooserContentPreviewUi.ActionFactory actionFactory,
- ContentInterface contentResolver,
- ChooserContentPreviewUi.ImageMimeTypeClassifier imageClassifier,
- ImageLoader imageLoader,
- ImagePreviewView.TransitionElementStatusCallback transitionElementStatusCallback,
- FeatureFlagRepository featureFlagRepository) {
- CharSequence text = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT);
- String action = targetIntent.getAction();
- // TODO: why don't we use image classifier for single-element ACTION_SEND?
- final List<Uri> imageUris = Intent.ACTION_SEND.equals(action)
- ? extractContentUris(targetIntent)
- : extractContentUris(targetIntent)
- .stream()
- .filter(uri -> {
- String type = null;
- try {
- type = contentResolver.getType(uri);
- } catch (RemoteException ignored) {
- }
- return imageClassifier.isImageType(type);
- })
- .collect(Collectors.toList());
- return new ImageContentPreviewUi(
- imageUris,
- text,
- actionFactory,
- imageLoader,
- transitionElementStatusCallback,
- featureFlagRepository);
- }
-
- private static List<Uri> extractContentUris(Intent targetIntent) {
- List<Uri> uris = new ArrayList<>();
- if (Intent.ACTION_SEND.equals(targetIntent.getAction())) {
- Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
- if (ContentPreviewUi.validForContentPreview(uri)) {
- uris.add(uri);
- }
- } else {
- List<Uri> receivedUris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
- if (receivedUris != null) {
- for (Uri uri : receivedUris) {
- if (ContentPreviewUi.validForContentPreview(uri)) {
- uris.add(uri);
- }
- }
- }
- }
- return uris;
+ headlineGenerator);
}
}
diff --git a/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java
index 39856e66..07071236 100644
--- a/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java
@@ -16,31 +16,21 @@
package com.android.intentresolver.contentpreview;
-import static android.content.ContentProvider.getUserIdFromUri;
-
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.net.Uri;
-import android.os.UserHandle;
-import android.util.Log;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewStub;
import android.view.animation.DecelerateInterpolator;
-
-import androidx.annotation.LayoutRes;
+import android.widget.ImageView;
+import android.widget.TextView;
import com.android.intentresolver.R;
-import com.android.intentresolver.flags.FeatureFlagRepository;
-import com.android.intentresolver.flags.Flags;
import com.android.intentresolver.widget.ActionRow;
-import com.android.intentresolver.widget.RoundedRectImageView;
-
-import java.util.ArrayList;
-import java.util.List;
+import com.android.intentresolver.widget.ScrollableImagePreviewView;
abstract class ContentPreviewUi {
private static final int IMAGE_FADE_IN_MILLIS = 150;
@@ -52,53 +42,7 @@ abstract class ContentPreviewUi {
public abstract ViewGroup display(
Resources resources, LayoutInflater layoutInflater, ViewGroup parent);
- protected static int getActionRowLayout(FeatureFlagRepository featureFlagRepository) {
- return featureFlagRepository.isEnabled(Flags.SHARESHEET_CUSTOM_ACTIONS)
- ? R.layout.scrollable_chooser_action_row
- : R.layout.chooser_action_row;
- }
-
- protected static ActionRow inflateActionRow(ViewGroup parent, @LayoutRes int actionRowLayout) {
- final ViewStub stub = parent.findViewById(com.android.intentresolver.R.id.action_row_stub);
- if (stub != null) {
- stub.setLayoutResource(actionRowLayout);
- stub.inflate();
- }
- return parent.findViewById(com.android.internal.R.id.chooser_action_row);
- }
-
- protected static List<ActionRow.Action> createActions(
- List<ActionRow.Action> systemActions,
- List<ActionRow.Action> customActions,
- FeatureFlagRepository featureFlagRepository) {
- ArrayList<ActionRow.Action> actions =
- new ArrayList<>(systemActions.size() + customActions.size());
- actions.addAll(systemActions);
- if (featureFlagRepository.isEnabled(Flags.SHARESHEET_CUSTOM_ACTIONS)) {
- actions.addAll(customActions);
- }
- return actions;
- }
-
- /**
- * Indicate if the incoming content URI should be allowed.
- *
- * @param uri the uri to test
- * @return true if the URI is allowed for content preview
- */
- protected static boolean validForContentPreview(Uri uri) throws SecurityException {
- if (uri == null) {
- return false;
- }
- int userId = getUserIdFromUri(uri, UserHandle.USER_CURRENT);
- if (userId != UserHandle.USER_CURRENT && userId != UserHandle.myUserId()) {
- Log.e(ContentPreviewUi.TAG, "dropped invalid content URI belonging to user " + userId);
- return false;
- }
- return true;
- }
-
- protected static void updateViewWithImage(RoundedRectImageView imageView, Bitmap image) {
+ protected static void updateViewWithImage(ImageView imageView, Bitmap image) {
if (image == null) {
imageView.setVisibility(View.GONE);
return;
@@ -113,18 +57,45 @@ abstract class ContentPreviewUi {
fadeAnim.start();
}
- protected static void displayPayloadReselectionAction(
+ protected static void displayHeadline(ViewGroup layout, String headline) {
+ if (layout != null) {
+ TextView titleView = layout.findViewById(R.id.headline);
+ if (titleView != null) {
+ if (!TextUtils.isEmpty(headline)) {
+ titleView.setText(headline);
+ titleView.setVisibility(View.VISIBLE);
+ } else {
+ titleView.setVisibility(View.GONE);
+ }
+ }
+ }
+ }
+
+ protected static void displayModifyShareAction(
ViewGroup layout,
- ChooserContentPreviewUi.ActionFactory actionFactory,
- FeatureFlagRepository featureFlagRepository) {
- Runnable modifyShareAction = actionFactory.getModifyShareAction();
- if (modifyShareAction != null && layout != null
- && featureFlagRepository.isEnabled(Flags.SHARESHEET_RESELECTION_ACTION)) {
- View modifyShareView = layout.findViewById(R.id.reselection_action);
+ ChooserContentPreviewUi.ActionFactory actionFactory) {
+ ActionRow.Action modifyShareAction = actionFactory.getModifyShareAction();
+ if (modifyShareAction != null && layout != null) {
+ TextView modifyShareView = layout.findViewById(R.id.reselection_action);
if (modifyShareView != null) {
+ modifyShareView.setText(modifyShareAction.getLabel());
modifyShareView.setVisibility(View.VISIBLE);
- modifyShareView.setOnClickListener(view -> modifyShareAction.run());
+ modifyShareView.setOnClickListener(view -> modifyShareAction.getOnClicked().run());
}
}
}
+
+ protected static ScrollableImagePreviewView.PreviewType getPreviewType(
+ MimeTypeClassifier typeClassifier, String mimeType) {
+ if (mimeType == null) {
+ return ScrollableImagePreviewView.PreviewType.File;
+ }
+ if (typeClassifier.isImageType(mimeType)) {
+ return ScrollableImagePreviewView.PreviewType.Image;
+ }
+ if (typeClassifier.isVideoType(mimeType)) {
+ return ScrollableImagePreviewView.PreviewType.Video;
+ }
+ return ScrollableImagePreviewView.PreviewType.File;
+ }
}
diff --git a/java/src/com/android/intentresolver/ImageLoader.kt b/java/src/com/android/intentresolver/contentpreview/DefaultMimeTypeClassifier.kt
index 0ed8b122..b9215709 100644
--- a/java/src/com/android/intentresolver/ImageLoader.kt
+++ b/java/src/com/android/intentresolver/contentpreview/DefaultMimeTypeClassifier.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,13 +14,6 @@
* limitations under the License.
*/
-package com.android.intentresolver
+package com.android.intentresolver.contentpreview
-import android.graphics.Bitmap
-import android.net.Uri
-import java.util.function.Consumer
-
-interface ImageLoader : suspend (Uri) -> Bitmap? {
- fun loadImage(uri: Uri, callback: Consumer<Bitmap?>)
- fun prePopulate(uris: List<Uri>)
-}
+object DefaultMimeTypeClassifier : MimeTypeClassifier
diff --git a/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java
index 7cd71475..20758189 100644
--- a/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java
@@ -16,15 +16,7 @@
package com.android.intentresolver.contentpreview;
-import android.content.ContentInterface;
import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.RemoteException;
-import android.provider.DocumentsContract;
-import android.provider.Downloads;
-import android.provider.OpenableColumns;
-import android.text.TextUtils;
import android.util.Log;
import android.util.PluralsMessageFormatter;
import android.view.LayoutInflater;
@@ -33,38 +25,33 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
-import androidx.annotation.LayoutRes;
+import androidx.annotation.Nullable;
-import com.android.intentresolver.ImageLoader;
import com.android.intentresolver.R;
-import com.android.intentresolver.flags.FeatureFlagRepository;
import com.android.intentresolver.widget.ActionRow;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class FileContentPreviewUi extends ContentPreviewUi {
private static final String PLURALS_COUNT = "count";
- private static final String PLURALS_FILE_NAME = "file_name";
- private final List<Uri> mUris;
+ @Nullable
+ private String mFirstFileName = null;
+ private final int mFileCount;
private final ChooserContentPreviewUi.ActionFactory mActionFactory;
- private final ImageLoader mImageLoader;
- private final ContentInterface mContentResolver;
- private final FeatureFlagRepository mFeatureFlagRepository;
+ private final HeadlineGenerator mHeadlineGenerator;
+ @Nullable
+ private ViewGroup mContentPreview = null;
- FileContentPreviewUi(List<Uri> uris,
+ FileContentPreviewUi(
+ int fileCount,
ChooserContentPreviewUi.ActionFactory actionFactory,
- ImageLoader imageLoader,
- ContentInterface contentResolver,
- FeatureFlagRepository featureFlagRepository) {
- mUris = uris;
+ HeadlineGenerator headlineGenerator) {
+ mFileCount = fileCount;
mActionFactory = actionFactory;
- mImageLoader = imageLoader;
- mContentResolver = contentResolver;
- mFeatureFlagRepository = featureFlagRepository;
+ mHeadlineGenerator = headlineGenerator;
}
@Override
@@ -72,165 +59,62 @@ class FileContentPreviewUi extends ContentPreviewUi {
return ContentPreviewType.CONTENT_PREVIEW_FILE;
}
+ public void setFirstFileName(String fileName) {
+ mFirstFileName = fileName;
+ if (mContentPreview != null) {
+ showFileName(mContentPreview, fileName);
+ }
+ }
+
@Override
public ViewGroup display(Resources resources, LayoutInflater layoutInflater, ViewGroup parent) {
ViewGroup layout = displayInternal(resources, layoutInflater, parent);
- displayPayloadReselectionAction(layout, mActionFactory, mFeatureFlagRepository);
+ displayModifyShareAction(layout, mActionFactory);
return layout;
}
private ViewGroup displayInternal(
Resources resources, LayoutInflater layoutInflater, ViewGroup parent) {
- @LayoutRes int actionRowLayout = getActionRowLayout(mFeatureFlagRepository);
- ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate(
+ mContentPreview = (ViewGroup) layoutInflater.inflate(
R.layout.chooser_grid_preview_file, parent, false);
- final int uriCount = mUris.size();
+ displayHeadline(mContentPreview, mHeadlineGenerator.getFilesHeadline(mFileCount));
- if (uriCount == 0) {
- contentPreviewLayout.setVisibility(View.GONE);
+ if (mFileCount == 0) {
+ mContentPreview.setVisibility(View.GONE);
Log.i(TAG, "Appears to be no uris available in EXTRA_STREAM,"
+ " removing preview area");
- return contentPreviewLayout;
- }
-
- if (uriCount == 1) {
- loadFileUriIntoView(mUris.get(0), contentPreviewLayout, mImageLoader, mContentResolver);
- } else {
- FileInfo fileInfo = extractFileInfo(mUris.get(0), mContentResolver);
- int remUriCount = uriCount - 1;
- Map<String, Object> arguments = new HashMap<>();
- arguments.put(PLURALS_COUNT, remUriCount);
- arguments.put(PLURALS_FILE_NAME, fileInfo.name);
- String fileName =
- PluralsMessageFormatter.format(resources, arguments, R.string.file_count);
-
- TextView fileNameView = contentPreviewLayout.findViewById(
- com.android.internal.R.id.content_preview_filename);
- fileNameView.setText(fileName);
-
- View thumbnailView = contentPreviewLayout.findViewById(
- com.android.internal.R.id.content_preview_file_thumbnail);
- thumbnailView.setVisibility(View.GONE);
-
- ImageView fileIconView = contentPreviewLayout.findViewById(
- com.android.internal.R.id.content_preview_file_icon);
- fileIconView.setVisibility(View.VISIBLE);
- fileIconView.setImageResource(R.drawable.ic_file_copy);
- }
-
- final ActionRow actionRow = inflateActionRow(contentPreviewLayout, actionRowLayout);
- if (actionRow != null) {
- actionRow.setActions(
- createActions(
- createFilePreviewActions(),
- mActionFactory.createCustomActions(),
- mFeatureFlagRepository));
+ return mContentPreview;
}
- return contentPreviewLayout;
- }
-
- private List<ActionRow.Action> createFilePreviewActions() {
- List<ActionRow.Action> actions = new ArrayList<>(1);
- //TODO(b/120417119):
- // add action buttonFactory.createCopyButton()
- ActionRow.Action action = mActionFactory.createNearbyButton();
- if (action != null) {
- actions.add(action);
+ if (mFirstFileName != null) {
+ showFileName(mContentPreview, mFirstFileName);
}
- return actions;
- }
- private static void loadFileUriIntoView(
- final Uri uri,
- final View parent,
- final ImageLoader imageLoader,
- final ContentInterface contentResolver) {
- FileInfo fileInfo = extractFileInfo(uri, contentResolver);
-
- TextView fileNameView = parent.findViewById(
- com.android.internal.R.id.content_preview_filename);
- fileNameView.setText(fileInfo.name);
-
- if (fileInfo.hasThumbnail) {
- imageLoader.loadImage(
- uri,
- (bitmap) -> updateViewWithImage(
- parent.findViewById(
- com.android.internal.R.id.content_preview_file_thumbnail),
- bitmap));
+ TextView secondLine = mContentPreview.findViewById(
+ R.id.content_preview_more_files);
+ if (mFileCount > 1) {
+ int remUriCount = mFileCount - 1;
+ Map<String, Object> arguments = new HashMap<>();
+ arguments.put(PLURALS_COUNT, remUriCount);
+ secondLine.setText(
+ PluralsMessageFormatter.format(resources, arguments, R.string.more_files));
} else {
- View thumbnailView = parent.findViewById(
- com.android.internal.R.id.content_preview_file_thumbnail);
- thumbnailView.setVisibility(View.GONE);
-
- ImageView fileIconView = parent.findViewById(
- com.android.internal.R.id.content_preview_file_icon);
- fileIconView.setVisibility(View.VISIBLE);
- fileIconView.setImageResource(R.drawable.chooser_file_generic);
- }
- }
-
- private static FileInfo extractFileInfo(Uri uri, ContentInterface resolver) {
- String fileName = null;
- boolean hasThumbnail = false;
-
- try (Cursor cursor = queryResolver(resolver, uri)) {
- if (cursor != null && cursor.getCount() > 0) {
- int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
- int titleIndex = cursor.getColumnIndex(Downloads.Impl.COLUMN_TITLE);
- int flagsIndex = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_FLAGS);
-
- cursor.moveToFirst();
- if (nameIndex != -1) {
- fileName = cursor.getString(nameIndex);
- } else if (titleIndex != -1) {
- fileName = cursor.getString(titleIndex);
- }
-
- if (flagsIndex != -1) {
- hasThumbnail = (cursor.getInt(flagsIndex)
- & DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
- }
- }
- } catch (SecurityException | NullPointerException e) {
- // The ContentResolver already logs the exception. Log something more informative.
- Log.w(
- TAG,
- "Could not load (" + uri.toString() + ") thumbnail/name for preview. If "
- + "desired, consider using Intent#createChooser to launch the ChooserActivity, "
- + "and set your Intent's clipData and flags in accordance with that method's "
- + "documentation");
+ ImageView icon = mContentPreview.findViewById(R.id.content_preview_file_icon);
+ icon.setImageResource(R.drawable.single_file);
+ secondLine.setVisibility(View.GONE);
}
- if (TextUtils.isEmpty(fileName)) {
- fileName = uri.getPath();
- fileName = fileName == null ? "" : fileName;
- int index = fileName.lastIndexOf('/');
- if (index != -1) {
- fileName = fileName.substring(index + 1);
- }
- }
-
- return new FileInfo(fileName, hasThumbnail);
- }
+ final ActionRow actionRow =
+ mContentPreview.findViewById(com.android.internal.R.id.chooser_action_row);
+ List<ActionRow.Action> actions = mActionFactory.createCustomActions();
+ actionRow.setActions(actions);
- private static Cursor queryResolver(ContentInterface resolver, Uri uri) {
- try {
- return resolver.query(uri, null, null, null);
- } catch (RemoteException e) {
- return null;
- }
+ return mContentPreview;
}
- private static class FileInfo {
- public final String name;
- public final boolean hasThumbnail;
-
- FileInfo(String name, boolean hasThumbnail) {
- this.name = name;
- this.hasThumbnail = hasThumbnail;
- }
+ private void showFileName(ViewGroup contentPreview, String name) {
+ TextView fileNameView = contentPreview.requireViewById(R.id.content_preview_filename);
+ fileNameView.setText(name);
}
}
diff --git a/java/src/com/android/intentresolver/contentpreview/FileInfo.kt b/java/src/com/android/intentresolver/contentpreview/FileInfo.kt
new file mode 100644
index 00000000..fe35365b
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/FileInfo.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.intentresolver.contentpreview
+
+import android.net.Uri
+import androidx.annotation.VisibleForTesting
+
+class FileInfo private constructor(val uri: Uri, val previewUri: Uri?, val mimeType: String?) {
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ class Builder(val uri: Uri) {
+ var previewUri: Uri? = null
+ private set
+ var mimeType: String? = null
+ private set
+
+ @Synchronized fun withPreviewUri(uri: Uri?): Builder = apply { previewUri = uri }
+
+ @Synchronized
+ fun withMimeType(mimeType: String?): Builder = apply { this.mimeType = mimeType }
+
+ @Synchronized fun build(): FileInfo = FileInfo(uri, previewUri, mimeType)
+ }
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java
new file mode 100644
index 00000000..35990990
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview;
+
+import static com.android.intentresolver.contentpreview.ContentPreviewType.CONTENT_PREVIEW_FILE;
+import static com.android.intentresolver.contentpreview.ContentPreviewType.CONTENT_PREVIEW_IMAGE;
+
+import android.content.res.Resources;
+import android.net.Uri;
+import android.text.util.Linkify;
+import android.util.PluralsMessageFormatter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+import androidx.lifecycle.Lifecycle;
+
+import com.android.intentresolver.R;
+import com.android.intentresolver.widget.ActionRow;
+import com.android.intentresolver.widget.ScrollableImagePreviewView;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * FilesPlusTextContentPreviewUi is shown when the user is sending 1 or more files along with
+ * non-empty EXTRA_TEXT. The text can be toggled with a checkbox. If a single image file is being
+ * shared, it is shown in a preview (otherwise the headline summary is the sole indication of the
+ * file content).
+ */
+class FilesPlusTextContentPreviewUi extends ContentPreviewUi {
+ private final Lifecycle mLifecycle;
+ private final CharSequence mText;
+ private final ChooserContentPreviewUi.ActionFactory mActionFactory;
+ private final ImageLoader mImageLoader;
+ private final MimeTypeClassifier mTypeClassifier;
+ private final HeadlineGenerator mHeadlineGenerator;
+ private final boolean mIsSingleImage;
+ private final int mFileCount;
+ private ViewGroup mContentPreviewView;
+ private boolean mIsMetadataUpdated = false;
+ @Nullable
+ private Uri mFirstFilePreviewUri;
+ private boolean mAllImages;
+ private boolean mAllVideos;
+ // TODO(b/285309527): make this a flag
+ private static final boolean SHOW_TOGGLE_CHECKMARK = false;
+
+ FilesPlusTextContentPreviewUi(
+ Lifecycle lifecycle,
+ boolean isSingleImage,
+ int fileCount,
+ CharSequence text,
+ ChooserContentPreviewUi.ActionFactory actionFactory,
+ ImageLoader imageLoader,
+ MimeTypeClassifier typeClassifier,
+ HeadlineGenerator headlineGenerator) {
+ mLifecycle = lifecycle;
+ if (isSingleImage && fileCount != 1) {
+ throw new IllegalArgumentException(
+ "fileCount = " + fileCount + " and isSingleImage = true");
+ }
+ mFileCount = fileCount;
+ mIsSingleImage = isSingleImage;
+ mText = text;
+ mActionFactory = actionFactory;
+ mImageLoader = imageLoader;
+ mTypeClassifier = typeClassifier;
+ mHeadlineGenerator = headlineGenerator;
+ }
+
+ @Override
+ public int getType() {
+ return mIsSingleImage ? CONTENT_PREVIEW_IMAGE : CONTENT_PREVIEW_FILE;
+ }
+
+ @Override
+ public ViewGroup display(Resources resources, LayoutInflater layoutInflater, ViewGroup parent) {
+ ViewGroup layout = displayInternal(layoutInflater, parent);
+ displayModifyShareAction(layout, mActionFactory);
+ return layout;
+ }
+
+ public void updatePreviewMetadata(List<FileInfo> files) {
+ boolean allImages = true;
+ boolean allVideos = true;
+ for (FileInfo fileInfo : files) {
+ ScrollableImagePreviewView.PreviewType previewType =
+ getPreviewType(mTypeClassifier, fileInfo.getMimeType());
+ allImages = allImages && previewType == ScrollableImagePreviewView.PreviewType.Image;
+ allVideos = allVideos && previewType == ScrollableImagePreviewView.PreviewType.Video;
+ }
+ mAllImages = allImages;
+ mAllVideos = allVideos;
+ mFirstFilePreviewUri = files.isEmpty() ? null : files.get(0).getPreviewUri();
+ mIsMetadataUpdated = true;
+ if (mContentPreviewView != null) {
+ updateUiWithMetadata(mContentPreviewView);
+ }
+ }
+
+ private ViewGroup displayInternal(LayoutInflater layoutInflater, ViewGroup parent) {
+ mContentPreviewView = (ViewGroup) layoutInflater.inflate(
+ R.layout.chooser_grid_preview_files_text, parent, false);
+
+ final ActionRow actionRow =
+ mContentPreviewView.findViewById(com.android.internal.R.id.chooser_action_row);
+ List<ActionRow.Action> actions = mActionFactory.createCustomActions();
+ actionRow.setActions(actions);
+
+ if (mIsMetadataUpdated) {
+ updateUiWithMetadata(mContentPreviewView);
+ } else if (!mIsSingleImage) {
+ mContentPreviewView.requireViewById(R.id.image_view).setVisibility(View.GONE);
+ }
+
+ return mContentPreviewView;
+ }
+
+ private void updateUiWithMetadata(ViewGroup contentPreviewView) {
+ prepareTextPreview(contentPreviewView, mActionFactory);
+ updateHeadline(contentPreviewView);
+
+ ImageView imagePreview = mContentPreviewView.requireViewById(R.id.image_view);
+ if (mIsSingleImage && mFirstFilePreviewUri != null) {
+ mImageLoader.loadImage(
+ mLifecycle,
+ mFirstFilePreviewUri,
+ bitmap -> {
+ if (bitmap == null) {
+ imagePreview.setVisibility(View.GONE);
+ } else {
+ imagePreview.setImageBitmap(bitmap);
+ }
+ });
+ } else {
+ imagePreview.setVisibility(View.GONE);
+ }
+ }
+
+ private void updateHeadline(ViewGroup contentPreview) {
+ CheckBox includeText = contentPreview.requireViewById(R.id.include_text_action);
+ String headline;
+ if (includeText.getVisibility() == View.VISIBLE && includeText.isChecked()) {
+ if (mAllImages) {
+ headline = mHeadlineGenerator.getImagesWithTextHeadline(mText, mFileCount);
+ } else if (mAllVideos) {
+ headline = mHeadlineGenerator.getVideosWithTextHeadline(mText, mFileCount);
+ } else {
+ headline = mHeadlineGenerator.getFilesWithTextHeadline(mText, mFileCount);
+ }
+ } else {
+ if (mAllImages) {
+ headline = mHeadlineGenerator.getImagesHeadline(mFileCount);
+ } else if (mAllVideos) {
+ headline = mHeadlineGenerator.getVideosHeadline(mFileCount);
+ } else {
+ headline = mHeadlineGenerator.getFilesHeadline(mFileCount);
+ }
+ }
+
+ displayHeadline(contentPreview, headline);
+ }
+
+ private void prepareTextPreview(
+ ViewGroup contentPreview,
+ ChooserContentPreviewUi.ActionFactory actionFactory) {
+ final TextView textView = contentPreview.requireViewById(R.id.content_preview_text);
+ CheckBox includeText = contentPreview.requireViewById(R.id.include_text_action);
+ boolean isLink = HttpUriMatcher.isHttpUri(mText.toString());
+ textView.setAutoLinkMask(isLink ? Linkify.WEB_URLS : 0);
+ textView.setText(mText);
+
+ final Consumer<Boolean> shareTextAction = actionFactory.getExcludeSharedTextAction();
+ includeText.setChecked(true);
+ includeText.setText(isLink ? R.string.include_link : R.string.include_text);
+ shareTextAction.accept(false);
+ includeText.setOnCheckedChangeListener((view, isChecked) -> {
+ if (isChecked) {
+ textView.setText(mText);
+ } else {
+ textView.setText(getNoTextString(contentPreview.getResources()));
+ }
+ shareTextAction.accept(!isChecked);
+ updateHeadline(contentPreview);
+ });
+ if (SHOW_TOGGLE_CHECKMARK) {
+ includeText.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private String getNoTextString(Resources resources) {
+ int stringResource;
+
+ if (mAllImages) {
+ stringResource = R.string.sharing_images_only;
+ } else if (mAllVideos) {
+ stringResource = R.string.sharing_videos_only;
+ } else {
+ stringResource = R.string.sharing_files_only;
+ }
+
+ HashMap<String, Object> params = new HashMap<>();
+ params.put("count", mFileCount);
+
+ return PluralsMessageFormatter.format(
+ resources,
+ params,
+ stringResource
+ );
+ }
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/HeadlineGenerator.kt b/java/src/com/android/intentresolver/contentpreview/HeadlineGenerator.kt
new file mode 100644
index 00000000..5f87c924
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/HeadlineGenerator.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+/**
+ * HeadlineGenerator generates the text to show at the top of the sharesheet as a brief
+ * description of the content being shared.
+ */
+interface HeadlineGenerator {
+ fun getTextHeadline(text: CharSequence): String
+
+ fun getImagesWithTextHeadline(text: CharSequence, count: Int): String
+
+ fun getVideosWithTextHeadline(text: CharSequence, count: Int): String
+
+ fun getFilesWithTextHeadline(text: CharSequence, count: Int): String
+
+ fun getImagesHeadline(count: Int): String
+
+ fun getVideosHeadline(count: Int): String
+
+ fun getFilesHeadline(count: Int): String
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImpl.kt b/java/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImpl.kt
new file mode 100644
index 00000000..1aace8c3
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImpl.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import android.annotation.StringRes
+import android.content.Context
+import com.android.intentresolver.R
+import android.util.PluralsMessageFormatter
+
+private const val PLURALS_COUNT = "count"
+
+/**
+ * HeadlineGenerator generates the text to show at the top of the sharesheet as a brief
+ * description of the content being shared.
+ */
+class HeadlineGeneratorImpl(private val context: Context) : HeadlineGenerator {
+ override fun getTextHeadline(text: CharSequence): String {
+ return context.getString(
+ getTemplateResource(text, R.string.sharing_link, R.string.sharing_text))
+ }
+
+ override fun getImagesWithTextHeadline(text: CharSequence, count: Int): String {
+ return getPluralString(getTemplateResource(
+ text, R.string.sharing_images_with_link, R.string.sharing_images_with_text), count)
+ }
+
+ override fun getVideosWithTextHeadline(text: CharSequence, count: Int): String {
+ return getPluralString(getTemplateResource(
+ text, R.string.sharing_videos_with_link, R.string.sharing_videos_with_text), count)
+ }
+
+ override fun getFilesWithTextHeadline(text: CharSequence, count: Int): String {
+ return getPluralString(getTemplateResource(
+ text, R.string.sharing_files_with_link, R.string.sharing_files_with_text), count)
+ }
+
+ override fun getImagesHeadline(count: Int): String {
+ return getPluralString(R.string.sharing_images, count)
+ }
+
+ override fun getVideosHeadline(count: Int): String {
+ return getPluralString(R.string.sharing_videos, count)
+ }
+
+ override fun getFilesHeadline(count: Int): String {
+ return getPluralString(R.string.sharing_files, count)
+ }
+
+ private fun getPluralString(@StringRes templateResource: Int, count: Int): String {
+ return PluralsMessageFormatter.format(
+ context.resources,
+ mapOf(PLURALS_COUNT to count),
+ templateResource
+ )
+ }
+
+ @StringRes
+ private fun getTemplateResource(
+ text: CharSequence, @StringRes linkResource: Int, @StringRes nonLinkResource: Int
+ ): Int {
+ return if (text.toString().isHttpUri()) linkResource else nonLinkResource
+ }
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/ImageContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ImageContentPreviewUi.java
deleted file mode 100644
index db26ab1b..00000000
--- a/java/src/com/android/intentresolver/contentpreview/ImageContentPreviewUi.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.intentresolver.contentpreview;
-
-import static com.android.intentresolver.contentpreview.ContentPreviewType.CONTENT_PREVIEW_IMAGE;
-
-import android.content.res.Resources;
-import android.net.Uri;
-import android.text.TextUtils;
-import android.text.util.Linkify;
-import android.transition.TransitionManager;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewStub;
-import android.widget.CheckBox;
-import android.widget.TextView;
-
-import androidx.annotation.LayoutRes;
-import androidx.annotation.Nullable;
-
-import com.android.intentresolver.ImageLoader;
-import com.android.intentresolver.R;
-import com.android.intentresolver.flags.FeatureFlagRepository;
-import com.android.intentresolver.flags.Flags;
-import com.android.intentresolver.widget.ActionRow;
-import com.android.intentresolver.widget.ImagePreviewView;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-
-class ImageContentPreviewUi extends ContentPreviewUi {
- private final List<Uri> mImageUris;
- @Nullable
- private final CharSequence mText;
- private final ChooserContentPreviewUi.ActionFactory mActionFactory;
- private final ImageLoader mImageLoader;
- private final ImagePreviewView.TransitionElementStatusCallback mTransitionElementStatusCallback;
- private final FeatureFlagRepository mFeatureFlagRepository;
-
- ImageContentPreviewUi(
- List<Uri> imageUris,
- @Nullable CharSequence text,
- ChooserContentPreviewUi.ActionFactory actionFactory,
- ImageLoader imageLoader,
- ImagePreviewView.TransitionElementStatusCallback transitionElementStatusCallback,
- FeatureFlagRepository featureFlagRepository) {
- mImageUris = imageUris;
- mText = text;
- mActionFactory = actionFactory;
- mImageLoader = imageLoader;
- mTransitionElementStatusCallback = transitionElementStatusCallback;
- mFeatureFlagRepository = featureFlagRepository;
-
- mImageLoader.prePopulate(mImageUris);
- }
-
- @Override
- public int getType() {
- return CONTENT_PREVIEW_IMAGE;
- }
-
- @Override
- public ViewGroup display(Resources resources, LayoutInflater layoutInflater, ViewGroup parent) {
- ViewGroup layout = displayInternal(layoutInflater, parent);
- displayPayloadReselectionAction(layout, mActionFactory, mFeatureFlagRepository);
- return layout;
- }
-
- private ViewGroup displayInternal(LayoutInflater layoutInflater, ViewGroup parent) {
- @LayoutRes int actionRowLayout = getActionRowLayout(mFeatureFlagRepository);
- ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate(
- R.layout.chooser_grid_preview_image, parent, false);
- ImagePreviewView imagePreview = inflateImagePreviewView(contentPreviewLayout);
-
- final ActionRow actionRow = inflateActionRow(contentPreviewLayout, actionRowLayout);
- if (actionRow != null) {
- actionRow.setActions(
- createActions(
- createImagePreviewActions(),
- mActionFactory.createCustomActions(),
- mFeatureFlagRepository));
- }
-
- if (mImageUris.size() == 0) {
- Log.i(
- TAG,
- "Attempted to display image preview area with zero"
- + " available images detected in EXTRA_STREAM list");
- ((View) imagePreview).setVisibility(View.GONE);
- mTransitionElementStatusCallback.onAllTransitionElementsReady();
- return contentPreviewLayout;
- }
-
- setTextInImagePreviewVisibility(contentPreviewLayout, mActionFactory);
- imagePreview.setTransitionElementStatusCallback(mTransitionElementStatusCallback);
- imagePreview.setImages(mImageUris, mImageLoader);
-
- return contentPreviewLayout;
- }
-
- private List<ActionRow.Action> createImagePreviewActions() {
- ArrayList<ActionRow.Action> actions = new ArrayList<>(2);
- //TODO: add copy action;
- ActionRow.Action action = mActionFactory.createNearbyButton();
- if (action != null) {
- actions.add(action);
- }
- action = mActionFactory.createEditButton();
- if (action != null) {
- actions.add(action);
- }
- return actions;
- }
-
- private ImagePreviewView inflateImagePreviewView(ViewGroup previewLayout) {
- ViewStub stub = previewLayout.findViewById(R.id.image_preview_stub);
- if (stub != null) {
- int layoutId =
- mFeatureFlagRepository.isEnabled(Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW)
- ? R.layout.scrollable_image_preview_view
- : R.layout.chooser_image_preview_view;
- stub.setLayoutResource(layoutId);
- stub.inflate();
- }
- return previewLayout.findViewById(
- com.android.internal.R.id.content_preview_image_area);
- }
-
- private void setTextInImagePreviewVisibility(
- ViewGroup contentPreview, ChooserContentPreviewUi.ActionFactory actionFactory) {
- int visibility = mFeatureFlagRepository.isEnabled(Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW)
- && !TextUtils.isEmpty(mText)
- ? View.VISIBLE
- : View.GONE;
-
- final TextView textView = contentPreview
- .requireViewById(com.android.internal.R.id.content_preview_text);
- CheckBox actionView = contentPreview
- .requireViewById(R.id.include_text_action);
- textView.setVisibility(visibility);
- boolean isLink = visibility == View.VISIBLE && HttpUriMatcher.isHttpUri(mText.toString());
- textView.setAutoLinkMask(isLink ? Linkify.WEB_URLS : 0);
- textView.setText(mText);
-
- if (visibility == View.VISIBLE) {
- final int[] actionLabels = isLink
- ? new int[] { R.string.include_link, R.string.exclude_link }
- : new int[] { R.string.include_text, R.string.exclude_text };
- final Consumer<Boolean> shareTextAction = actionFactory.getExcludeSharedTextAction();
- actionView.setChecked(true);
- actionView.setText(actionLabels[1]);
- shareTextAction.accept(false);
- actionView.setOnCheckedChangeListener((view, isChecked) -> {
- view.setText(actionLabels[isChecked ? 1 : 0]);
- TransitionManager.beginDelayedTransition((ViewGroup) textView.getParent());
- textView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
- shareTextAction.accept(!isChecked);
- });
- }
- actionView.setVisibility(visibility);
- }
-}
diff --git a/java/src/com/android/intentresolver/contentpreview/ImageLoader.kt b/java/src/com/android/intentresolver/contentpreview/ImageLoader.kt
new file mode 100644
index 00000000..8d0fb84b
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/ImageLoader.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import android.graphics.Bitmap
+import android.net.Uri
+import androidx.lifecycle.Lifecycle
+import java.util.function.Consumer
+
+/** A content preview image loader. */
+interface ImageLoader : suspend (Uri) -> Bitmap?, suspend (Uri, Boolean) -> Bitmap? {
+ /**
+ * Load preview image asynchronously; caching is allowed.
+ *
+ * @param uri content URI
+ * @param callback a callback that will be invoked with the loaded image or null if loading has
+ * failed.
+ */
+ fun loadImage(callerLifecycle: Lifecycle, uri: Uri, callback: Consumer<Bitmap?>)
+
+ /** Prepopulate the image loader cache. */
+ fun prePopulate(uris: List<Uri>)
+
+ /** Load preview image; caching is allowed. */
+ override suspend fun invoke(uri: Uri) = invoke(uri, true)
+
+ /**
+ * Load preview image.
+ *
+ * @param uri content URI
+ * @param caching indicates if the loaded image could be cached.
+ */
+ override suspend fun invoke(uri: Uri, caching: Boolean): Bitmap?
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt b/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt
new file mode 100644
index 00000000..22dd1125
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import android.content.ContentResolver
+import android.graphics.Bitmap
+import android.net.Uri
+import android.util.Log
+import android.util.Size
+import androidx.annotation.GuardedBy
+import androidx.annotation.VisibleForTesting
+import androidx.collection.LruCache
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.coroutineScope
+import java.util.function.Consumer
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Semaphore
+
+private const val TAG = "ImagePreviewImageLoader"
+
+/**
+ * Implements preview image loading for the content preview UI. Provides requests deduplication,
+ * image caching, and a limit on the number of parallel loadings.
+ */
+@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+class ImagePreviewImageLoader
+@VisibleForTesting
+constructor(
+ private val scope: CoroutineScope,
+ thumbnailSize: Int,
+ private val contentResolver: ContentResolver,
+ cacheSize: Int,
+ // TODO: consider providing a scope with the dispatcher configured with
+ // [CoroutineDispatcher#limitedParallelism] instead
+ private val contentResolverSemaphore: Semaphore,
+) : ImageLoader {
+
+ constructor(
+ scope: CoroutineScope,
+ thumbnailSize: Int,
+ contentResolver: ContentResolver,
+ cacheSize: Int,
+ maxSimultaneousRequests: Int = 4
+ ) : this(scope, thumbnailSize, contentResolver, cacheSize, Semaphore(maxSimultaneousRequests))
+
+ private val thumbnailSize: Size = Size(thumbnailSize, thumbnailSize)
+
+ private val lock = Any()
+ @GuardedBy("lock") private val cache = LruCache<Uri, RequestRecord>(cacheSize)
+ @GuardedBy("lock") private val runningRequests = HashMap<Uri, RequestRecord>()
+
+ override suspend fun invoke(uri: Uri, caching: Boolean): Bitmap? = loadImageAsync(uri, caching)
+
+ override fun loadImage(callerLifecycle: Lifecycle, uri: Uri, callback: Consumer<Bitmap?>) {
+ callerLifecycle.coroutineScope.launch {
+ val image = loadImageAsync(uri, caching = true)
+ if (isActive) {
+ callback.accept(image)
+ }
+ }
+ }
+
+ override fun prePopulate(uris: List<Uri>) {
+ uris.asSequence().take(cache.maxSize()).forEach { uri ->
+ scope.launch { loadImageAsync(uri, caching = true) }
+ }
+ }
+
+ private suspend fun loadImageAsync(uri: Uri, caching: Boolean): Bitmap? {
+ return getRequestDeferred(uri, caching).await()
+ }
+
+ private fun getRequestDeferred(uri: Uri, caching: Boolean): Deferred<Bitmap?> {
+ var shouldLaunchImageLoading = false
+ val request =
+ synchronized(lock) {
+ cache[uri]
+ ?: runningRequests
+ .getOrPut(uri) {
+ shouldLaunchImageLoading = true
+ RequestRecord(uri, CompletableDeferred(), caching)
+ }
+ .apply { this.caching = this.caching || caching }
+ }
+ if (shouldLaunchImageLoading) {
+ request.loadBitmapAsync()
+ }
+ return request.deferred
+ }
+
+ private fun RequestRecord.loadBitmapAsync() {
+ scope
+ .launch { loadBitmap() }
+ .invokeOnCompletion { cause ->
+ if (cause is CancellationException) {
+ cancel()
+ }
+ }
+ }
+
+ private suspend fun RequestRecord.loadBitmap() {
+ contentResolverSemaphore.acquire()
+ val bitmap =
+ try {
+ contentResolver.loadThumbnail(uri, thumbnailSize, null)
+ } catch (t: Throwable) {
+ Log.d(TAG, "failed to load $uri preview", t)
+ null
+ } finally {
+ contentResolverSemaphore.release()
+ }
+ complete(bitmap)
+ }
+
+ private fun RequestRecord.cancel() {
+ synchronized(lock) {
+ runningRequests.remove(uri)
+ deferred.cancel()
+ }
+ }
+
+ private fun RequestRecord.complete(bitmap: Bitmap?) {
+ deferred.complete(bitmap)
+ synchronized(lock) {
+ runningRequests.remove(uri)
+ if (bitmap != null && caching) {
+ cache.put(uri, this)
+ }
+ }
+ }
+
+ private class RequestRecord(
+ val uri: Uri,
+ val deferred: CompletableDeferred<Bitmap?>,
+ @GuardedBy("lock") var caching: Boolean
+ )
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java b/java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java
new file mode 100644
index 00000000..0c333b68
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview;
+
+import android.content.ClipDescription;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Testing shim to specify whether a given mime type is considered to be an "image."
+ */
+public interface MimeTypeClassifier {
+ /** @return whether the specified {@code mimeType} is classified as an "image" type. */
+ default boolean isImageType(@Nullable String mimeType) {
+ return (mimeType != null) && ClipDescription.compareMimeTypes(mimeType, "image/*");
+ }
+
+ /** @return whether the specified {@code mimeType} is classified as an "video" type */
+ default boolean isVideoType(@Nullable String mimeType) {
+ return (mimeType != null) && ClipDescription.compareMimeTypes(mimeType, "video/*");
+ }
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt b/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt
new file mode 100644
index 00000000..8ab3a272
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import android.content.ContentInterface
+import android.content.Intent
+import android.database.Cursor
+import android.media.MediaMetadata
+import android.net.Uri
+import android.provider.DocumentsContract
+import android.provider.DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL
+import android.provider.Downloads
+import android.provider.OpenableColumns
+import android.text.TextUtils
+import android.util.Log
+import androidx.annotation.OpenForTesting
+import androidx.annotation.VisibleForTesting
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.coroutineScope
+import com.android.intentresolver.contentpreview.ContentPreviewType.CONTENT_PREVIEW_FILE
+import com.android.intentresolver.contentpreview.ContentPreviewType.CONTENT_PREVIEW_IMAGE
+import com.android.intentresolver.contentpreview.ContentPreviewType.CONTENT_PREVIEW_TEXT
+import com.android.intentresolver.measurements.runTracing
+import com.android.intentresolver.util.ownedByCurrentUser
+import java.util.concurrent.atomic.AtomicInteger
+import java.util.function.Consumer
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+import kotlinx.coroutines.withTimeoutOrNull
+
+/**
+ * A set of metadata columns we read for a content URI (see
+ * [PreviewDataProvider.UriRecord.readQueryResult] method).
+ */
+@VisibleForTesting
+val METADATA_COLUMNS =
+ arrayOf(
+ DocumentsContract.Document.COLUMN_FLAGS,
+ MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI,
+ OpenableColumns.DISPLAY_NAME,
+ Downloads.Impl.COLUMN_TITLE
+ )
+private const val TIMEOUT_MS = 1_000L
+
+/**
+ * Asynchronously loads and stores shared URI metadata (see [Intent.EXTRA_STREAM]) such as mime
+ * type, file name, and a preview thumbnail URI.
+ */
+@OpenForTesting
+open class PreviewDataProvider
+@VisibleForTesting
+constructor(
+ private val targetIntent: Intent,
+ private val contentResolver: ContentInterface,
+ private val typeClassifier: MimeTypeClassifier,
+ private val dispatcher: CoroutineDispatcher,
+) {
+ constructor(
+ targetIntent: Intent,
+ contentResolver: ContentInterface,
+ ) : this(
+ targetIntent,
+ contentResolver,
+ DefaultMimeTypeClassifier,
+ Dispatchers.IO,
+ )
+
+ private val records = targetIntent.contentUris.map { UriRecord(it) }
+
+ /** returns number of shared URIs, see [Intent.EXTRA_STREAM] */
+ @get:OpenForTesting
+ open val uriCount: Int
+ get() = records.size
+
+ /**
+ * Preview type to use. The type is determined asynchronously with a timeout; the fall-back
+ * values is [ContentPreviewType.CONTENT_PREVIEW_FILE]
+ */
+ @get:OpenForTesting
+ @get:ContentPreviewType
+ open val previewType: Int by lazy {
+ runTracing("preview-type") {
+ /* In [android.content.Intent#getType], the app may specify a very general mime type
+ * that broadly covers all data being shared, such as '*' when sending an image
+ * and text. We therefore should inspect each item for the preferred type, in order:
+ * IMAGE, FILE, TEXT. */
+ if (!targetIntent.isSend || records.isEmpty()) {
+ CONTENT_PREVIEW_TEXT
+ } else {
+ runBlocking(dispatcher) {
+ withTimeoutOrNull(TIMEOUT_MS) {
+ loadPreviewType()
+ } ?: CONTENT_PREVIEW_FILE
+ }
+ }
+ }
+ }
+
+ /**
+ * The first shared URI's metadata. This call wait's for the data to be loaded and falls back to
+ * a crude value if the data is not loaded within a time limit.
+ */
+ open val firstFileInfo: FileInfo? by lazy {
+ runTracing("first-uri-metadata") {
+ records.firstOrNull()?.let { record ->
+ runBlocking(dispatcher) {
+ val builder = FileInfo.Builder(record.uri)
+ withTimeoutOrNull(TIMEOUT_MS) {
+ builder.readFromRecord(record)
+ }
+ builder.build()
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a collection of [FileInfo], for each shared URI in order, with [FileInfo.mimeType]
+ * and [FileInfo.previewUri] set (a data projection tailored for the image preview UI).
+ */
+ @OpenForTesting
+ open fun getFileMetadataForImagePreview(
+ callerLifecycle: Lifecycle,
+ callback: Consumer<List<FileInfo>>,
+ ) {
+ callerLifecycle.coroutineScope.launch {
+ val result = withContext(dispatcher) {
+ getFileMetadataForImagePreview()
+ }
+ callback.accept(result)
+ }
+ }
+
+ private fun getFileMetadataForImagePreview(): List<FileInfo> =
+ runTracing("image-preview-metadata") {
+ ArrayList<FileInfo>(records.size).also { result ->
+ for (record in records) {
+ result.add(
+ FileInfo.Builder(record.uri)
+ .readFromRecord(record)
+ .build()
+ )
+ }
+ }
+ }
+
+ private fun FileInfo.Builder.readFromRecord(record: UriRecord): FileInfo.Builder {
+ withMimeType(record.mimeType)
+ val previewUri =
+ when {
+ record.isImageType || record.supportsImageType || record.supportsThumbnail ->
+ record.uri
+ else -> record.iconUri
+ }
+ withPreviewUri(previewUri)
+ return this
+ }
+
+ /**
+ * Returns a title for the first shared URI which is read from URI metadata or, if the metadata
+ * is not provided, derived from the URI.
+ */
+ @Throws(IndexOutOfBoundsException::class)
+ fun getFirstFileName(callerLifecycle: Lifecycle, callback: Consumer<String>) {
+ if (records.isEmpty()) {
+ throw IndexOutOfBoundsException("There are no shared URIs")
+ }
+ callerLifecycle.coroutineScope.launch {
+ val result = withContext(dispatcher) {
+ getFirstFileName()
+ }
+ callback.accept(result)
+ }
+ }
+
+ @Throws(IndexOutOfBoundsException::class)
+ private fun getFirstFileName(): String {
+ if (records.isEmpty()) throw IndexOutOfBoundsException("There are no shared URIs")
+
+ val record = records[0]
+ return if (TextUtils.isEmpty(record.title)) getFileName(record.uri) else record.title
+ }
+
+ @ContentPreviewType
+ private suspend fun loadPreviewType(): Int {
+ // Execute [ContentResolver#getType()] calls sequentially as the method contains a timeout
+ // logic for the actual [ContentProvider#getType] call. Thus it is possible for one getType
+ // call's timeout work against other concurrent getType calls e.g. when a two concurrent
+ // calls on the caller side are scheduled on the same thread on the callee side.
+ records
+ .firstOrNull { it.isImageType }
+ ?.run {
+ return CONTENT_PREVIEW_IMAGE
+ }
+
+ val resultDeferred = CompletableDeferred<Int>()
+ return coroutineScope {
+ val job = launch {
+ coroutineScope {
+ val nextIndex = AtomicInteger(0)
+ repeat(4) {
+ launch {
+ while (isActive) {
+ val i = nextIndex.getAndIncrement()
+ if (i >= records.size) break
+ val hasPreview =
+ with(records[i]) {
+ supportsImageType || supportsThumbnail || iconUri != null
+ }
+ if (hasPreview) {
+ resultDeferred.complete(CONTENT_PREVIEW_IMAGE)
+ break
+ }
+ }
+ }
+ }
+ }
+ resultDeferred.complete(CONTENT_PREVIEW_FILE)
+ }
+ resultDeferred.await()
+ .also { job.cancel() }
+ }
+ }
+
+ /**
+ * Provides a lazy evaluation and caches results of [ContentInterface.getType],
+ * [ContentInterface.getStreamTypes], and [ContentInterface.query] methods for the given [uri].
+ */
+ private inner class UriRecord(val uri: Uri) {
+ val mimeType: String? by lazy { contentResolver.getTypeSafe(uri) }
+ val isImageType: Boolean
+ get() = typeClassifier.isImageType(mimeType)
+ val supportsImageType: Boolean by lazy {
+ contentResolver.getStreamTypesSafe(uri)
+ ?.firstOrNull(typeClassifier::isImageType) != null
+ }
+ val supportsThumbnail: Boolean
+ get() = query.supportsThumbnail
+ val title: String
+ get() = query.title
+ val iconUri: Uri?
+ get() = query.iconUri
+
+ private val query by lazy { readQueryResult() }
+
+ private fun readQueryResult(): QueryResult {
+ val cursor = contentResolver.querySafe(uri)
+ ?.takeIf { it.moveToFirst() }
+ ?: return QueryResult()
+
+ var flagColIdx = -1
+ var displayIconUriColIdx = -1
+ var nameColIndex = -1
+ var titleColIndex = -1
+ // TODO: double-check why Cursor#getColumnInded didn't work
+ cursor.columnNames.forEachIndexed { i, columnName ->
+ when (columnName) {
+ DocumentsContract.Document.COLUMN_FLAGS -> flagColIdx = i
+ MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI -> displayIconUriColIdx = i
+ OpenableColumns.DISPLAY_NAME -> nameColIndex = i
+ Downloads.Impl.COLUMN_TITLE -> titleColIndex = i
+ }
+ }
+
+ val supportsThumbnail =
+ flagColIdx >= 0 && ((cursor.getInt(flagColIdx) and FLAG_SUPPORTS_THUMBNAIL) != 0)
+
+ var title = ""
+ if (nameColIndex >= 0) {
+ title = cursor.getString(nameColIndex) ?: ""
+ }
+ if (TextUtils.isEmpty(title) && titleColIndex >= 0) {
+ title = cursor.getString(titleColIndex) ?: ""
+ }
+
+ val iconUri =
+ if (displayIconUriColIdx >= 0) {
+ cursor.getString(displayIconUriColIdx)?.let(Uri::parse)
+ } else {
+ null
+ }
+
+ return QueryResult(supportsThumbnail, title, iconUri)
+ }
+ }
+
+ private class QueryResult(
+ val supportsThumbnail: Boolean = false,
+ val title: String = "",
+ val iconUri: Uri? = null
+ )
+}
+
+private val Intent.isSend: Boolean
+ get() =
+ action.let { action ->
+ Intent.ACTION_SEND == action || Intent.ACTION_SEND_MULTIPLE == action
+ }
+
+private val Intent.contentUris: ArrayList<Uri>
+ get() =
+ ArrayList<Uri>().also { uris ->
+ if (Intent.ACTION_SEND == action) {
+ getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
+ ?.takeIf { it.ownedByCurrentUser }
+ ?.let { uris.add(it) }
+ } else {
+ getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)?.fold(uris) { accumulator, uri
+ ->
+ if (uri.ownedByCurrentUser) {
+ accumulator.add(uri)
+ }
+ accumulator
+ }
+ }
+ }
+
+private fun getFileName(uri: Uri): String {
+ val fileName = uri.path ?: return ""
+ val index = fileName.lastIndexOf('/')
+ return if (index < 0) {
+ fileName
+ } else {
+ fileName.substring(index + 1)
+ }
+}
+
+private fun ContentInterface.getTypeSafe(uri: Uri): String? =
+ runTracing("getType") {
+ try {
+ getType(uri)
+ } catch (e: SecurityException) {
+ logProviderPermissionWarning(uri, "mime type")
+ null
+ } catch (t: Throwable) {
+ Log.e(ContentPreviewUi.TAG, "Failed to read metadata, uri: $uri", t)
+ null
+ }
+ }
+
+private fun ContentInterface.getStreamTypesSafe(uri: Uri): Array<String>? =
+ runTracing("getStreamTypes") {
+ try {
+ getStreamTypes(uri, "*/*")
+ } catch (e: SecurityException) {
+ logProviderPermissionWarning(uri, "stream types")
+ null
+ } catch (t: Throwable) {
+ Log.e(ContentPreviewUi.TAG, "Failed to read stream types, uri: $uri", t)
+ null
+ }
+ }
+
+private fun ContentInterface.querySafe(uri: Uri): Cursor? =
+ runTracing("query") {
+ try {
+ query(uri, METADATA_COLUMNS, null, null)
+ } catch (e: SecurityException) {
+ logProviderPermissionWarning(uri, "metadata")
+ null
+ } catch (t: Throwable) {
+ Log.e(ContentPreviewUi.TAG, "Failed to read metadata, uri: $uri", t)
+ null
+ }
+ }
+
+private fun logProviderPermissionWarning(uri: Uri, dataName: String) {
+ // The ContentResolver already logs the exception. Log something more informative.
+ Log.w(
+ ContentPreviewUi.TAG,
+ "Could not read $uri $dataName. If a preview is desired, call Intent#setClipData() to" +
+ " ensure that the sharesheet is given permission."
+ )
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt b/java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt
new file mode 100644
index 00000000..331b0cb6
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import android.app.Application
+import androidx.annotation.MainThread
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
+import androidx.lifecycle.viewModelScope
+import androidx.lifecycle.viewmodel.CreationExtras
+import com.android.intentresolver.ChooserRequestParameters
+import com.android.intentresolver.R
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.plus
+
+/** A trivial view model to keep a [PreviewDataProvider] instance over a configuration change */
+class PreviewViewModel(private val application: Application) : BasePreviewViewModel() {
+ private var previewDataProvider: PreviewDataProvider? = null
+ private var imageLoader: ImagePreviewImageLoader? = null
+
+ @MainThread
+ override fun createOrReuseProvider(
+ chooserRequest: ChooserRequestParameters
+ ): PreviewDataProvider =
+ previewDataProvider
+ ?: PreviewDataProvider(chooserRequest.targetIntent, application.contentResolver).also {
+ previewDataProvider = it
+ }
+
+ @MainThread
+ override fun createOrReuseImageLoader(): ImageLoader =
+ imageLoader
+ ?: ImagePreviewImageLoader(
+ viewModelScope + Dispatchers.IO,
+ thumbnailSize =
+ application.resources.getDimensionPixelSize(
+ R.dimen.chooser_preview_image_max_dimen
+ ),
+ application.contentResolver,
+ cacheSize = 16
+ )
+ .also { imageLoader = it }
+
+ companion object {
+ val Factory: ViewModelProvider.Factory =
+ object : ViewModelProvider.Factory {
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(
+ modelClass: Class<T>,
+ extras: CreationExtras
+ ): T = PreviewViewModel(checkNotNull(extras[APPLICATION_KEY])) as T
+ }
+ }
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java
index 7901e4cb..c38ed03a 100644
--- a/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java
@@ -16,6 +16,8 @@
package com.android.intentresolver.contentpreview;
+import static com.android.intentresolver.util.UriFilters.isOwnedByCurrentUser;
+
import android.content.res.Resources;
import android.net.Uri;
import android.text.TextUtils;
@@ -25,18 +27,14 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
-import androidx.annotation.LayoutRes;
import androidx.annotation.Nullable;
+import androidx.lifecycle.Lifecycle;
-import com.android.intentresolver.ImageLoader;
import com.android.intentresolver.R;
-import com.android.intentresolver.flags.FeatureFlagRepository;
import com.android.intentresolver.widget.ActionRow;
-import java.util.ArrayList;
-import java.util.List;
-
class TextContentPreviewUi extends ContentPreviewUi {
+ private final Lifecycle mLifecycle;
@Nullable
private final CharSequence mSharingText;
@Nullable
@@ -45,21 +43,23 @@ class TextContentPreviewUi extends ContentPreviewUi {
private final Uri mPreviewThumbnail;
private final ImageLoader mImageLoader;
private final ChooserContentPreviewUi.ActionFactory mActionFactory;
- private final FeatureFlagRepository mFeatureFlagRepository;
+ private final HeadlineGenerator mHeadlineGenerator;
TextContentPreviewUi(
+ Lifecycle lifecycle,
@Nullable CharSequence sharingText,
@Nullable CharSequence previewTitle,
@Nullable Uri previewThumbnail,
ChooserContentPreviewUi.ActionFactory actionFactory,
ImageLoader imageLoader,
- FeatureFlagRepository featureFlagRepository) {
+ HeadlineGenerator headlineGenerator) {
+ mLifecycle = lifecycle;
mSharingText = sharingText;
mPreviewTitle = previewTitle;
mPreviewThumbnail = previewThumbnail;
mImageLoader = imageLoader;
mActionFactory = actionFactory;
- mFeatureFlagRepository = featureFlagRepository;
+ mHeadlineGenerator = headlineGenerator;
}
@Override
@@ -70,69 +70,69 @@ class TextContentPreviewUi extends ContentPreviewUi {
@Override
public ViewGroup display(Resources resources, LayoutInflater layoutInflater, ViewGroup parent) {
ViewGroup layout = displayInternal(layoutInflater, parent);
- displayPayloadReselectionAction(layout, mActionFactory, mFeatureFlagRepository);
+ displayModifyShareAction(layout, mActionFactory);
return layout;
}
private ViewGroup displayInternal(
LayoutInflater layoutInflater,
ViewGroup parent) {
- @LayoutRes int actionRowLayout = getActionRowLayout(mFeatureFlagRepository);
ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate(
R.layout.chooser_grid_preview_text, parent, false);
- final ActionRow actionRow = inflateActionRow(contentPreviewLayout, actionRowLayout);
- if (actionRow != null) {
- actionRow.setActions(
- createActions(
- createTextPreviewActions(),
- mActionFactory.createCustomActions(),
- mFeatureFlagRepository));
- }
+ final ActionRow actionRow =
+ contentPreviewLayout.findViewById(com.android.internal.R.id.chooser_action_row);
+ actionRow.setActions(mActionFactory.createCustomActions());
if (mSharingText == null) {
contentPreviewLayout
- .findViewById(com.android.internal.R.id.content_preview_text_layout)
+ .findViewById(R.id.text_preview_layout)
.setVisibility(View.GONE);
- } else {
- TextView textView = contentPreviewLayout.findViewById(
- com.android.internal.R.id.content_preview_text);
- textView.setText(mSharingText);
+ return contentPreviewLayout;
}
+ TextView textView = contentPreviewLayout.findViewById(
+ com.android.internal.R.id.content_preview_text);
+ String text = mSharingText.toString();
+
+ // If we're only previewing one line, then strip out newlines.
+ if (textView.getMaxLines() == 1) {
+ text = text.replace("\n", " ");
+ }
+ textView.setText(text);
+
+ TextView previewTitleView = contentPreviewLayout.findViewById(
+ com.android.internal.R.id.content_preview_title);
if (TextUtils.isEmpty(mPreviewTitle)) {
- contentPreviewLayout
- .findViewById(com.android.internal.R.id.content_preview_title_layout)
- .setVisibility(View.GONE);
+ previewTitleView.setVisibility(View.GONE);
} else {
- TextView previewTitleView = contentPreviewLayout.findViewById(
- com.android.internal.R.id.content_preview_title);
previewTitleView.setText(mPreviewTitle);
-
- ImageView previewThumbnailView = contentPreviewLayout.findViewById(
- com.android.internal.R.id.content_preview_thumbnail);
- if (!validForContentPreview(mPreviewThumbnail)) {
- previewThumbnailView.setVisibility(View.GONE);
- } else {
- mImageLoader.loadImage(
- mPreviewThumbnail,
- (bitmap) -> updateViewWithImage(
- contentPreviewLayout.findViewById(
- com.android.internal.R.id.content_preview_thumbnail),
- bitmap));
- }
}
- return contentPreviewLayout;
- }
+ ImageView previewThumbnailView = contentPreviewLayout.findViewById(
+ com.android.internal.R.id.content_preview_thumbnail);
+ if (!isOwnedByCurrentUser(mPreviewThumbnail)) {
+ previewThumbnailView.setVisibility(View.GONE);
+ } else {
+ mImageLoader.loadImage(
+ mLifecycle,
+ mPreviewThumbnail,
+ (bitmap) -> updateViewWithImage(
+ contentPreviewLayout.findViewById(
+ com.android.internal.R.id.content_preview_thumbnail),
+ bitmap));
+ }
- private List<ActionRow.Action> createTextPreviewActions() {
- ArrayList<ActionRow.Action> actions = new ArrayList<>(2);
- actions.add(mActionFactory.createCopyButton());
- ActionRow.Action nearbyAction = mActionFactory.createNearbyButton();
- if (nearbyAction != null) {
- actions.add(nearbyAction);
+ Runnable onCopy = mActionFactory.getCopyButtonRunnable();
+ View copyButton = contentPreviewLayout.findViewById(R.id.copy);
+ if (onCopy != null) {
+ copyButton.setOnClickListener((v) -> onCopy.run());
+ } else {
+ copyButton.setVisibility(View.GONE);
}
- return actions;
+
+ displayHeadline(contentPreviewLayout, mHeadlineGenerator.getTextHeadline(mSharingText));
+
+ return contentPreviewLayout;
}
}
diff --git a/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java
new file mode 100644
index 00000000..6385f2b6
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview;
+
+import static com.android.intentresolver.contentpreview.ContentPreviewType.CONTENT_PREVIEW_IMAGE;
+
+import android.content.res.Resources;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+
+import com.android.intentresolver.R;
+import com.android.intentresolver.widget.ActionRow;
+import com.android.intentresolver.widget.ImagePreviewView.TransitionElementStatusCallback;
+import com.android.intentresolver.widget.ScrollableImagePreviewView;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+class UnifiedContentPreviewUi extends ContentPreviewUi {
+ private final boolean mShowEditAction;
+ private final ChooserContentPreviewUi.ActionFactory mActionFactory;
+ private final ImageLoader mImageLoader;
+ private final MimeTypeClassifier mTypeClassifier;
+ private final TransitionElementStatusCallback mTransitionElementStatusCallback;
+ private final HeadlineGenerator mHeadlineGenerator;
+ @Nullable
+ private List<FileInfo> mFiles;
+ @Nullable
+ private ViewGroup mContentPreviewView;
+
+ UnifiedContentPreviewUi(
+ boolean isSingleImage,
+ ChooserContentPreviewUi.ActionFactory actionFactory,
+ ImageLoader imageLoader,
+ MimeTypeClassifier typeClassifier,
+ TransitionElementStatusCallback transitionElementStatusCallback,
+ HeadlineGenerator headlineGenerator) {
+ mShowEditAction = isSingleImage;
+ mActionFactory = actionFactory;
+ mImageLoader = imageLoader;
+ mTypeClassifier = typeClassifier;
+ mTransitionElementStatusCallback = transitionElementStatusCallback;
+ mHeadlineGenerator = headlineGenerator;
+ }
+
+ @Override
+ public int getType() {
+ return CONTENT_PREVIEW_IMAGE;
+ }
+
+ @Override
+ public ViewGroup display(Resources resources, LayoutInflater layoutInflater, ViewGroup parent) {
+ ViewGroup layout = displayInternal(layoutInflater, parent);
+ displayModifyShareAction(layout, mActionFactory);
+ return layout;
+ }
+
+ public void setFiles(List<FileInfo> files) {
+ mImageLoader.prePopulate(files.stream()
+ .map(FileInfo::getPreviewUri)
+ .filter(Objects::nonNull)
+ .toList());
+ mFiles = files;
+ if (mContentPreviewView != null) {
+ updatePreviewWithFiles(mContentPreviewView, files);
+ }
+ }
+
+ private ViewGroup displayInternal(LayoutInflater layoutInflater, ViewGroup parent) {
+ mContentPreviewView = (ViewGroup) layoutInflater.inflate(
+ R.layout.chooser_grid_preview_image, parent, false);
+
+ final ActionRow actionRow =
+ mContentPreviewView.findViewById(com.android.internal.R.id.chooser_action_row);
+ List<ActionRow.Action> actions = mActionFactory.createCustomActions();
+ actionRow.setActions(actions);
+
+ ScrollableImagePreviewView imagePreview =
+ mContentPreviewView.requireViewById(R.id.scrollable_image_preview);
+ imagePreview.setOnNoPreviewCallback(() -> imagePreview.setVisibility(View.GONE));
+ imagePreview.setTransitionElementStatusCallback(mTransitionElementStatusCallback);
+
+ if (mFiles != null) {
+ updatePreviewWithFiles(mContentPreviewView, mFiles);
+ }
+
+ return mContentPreviewView;
+ }
+
+ private void updatePreviewWithFiles(ViewGroup contentPreviewView, List<FileInfo> files) {
+ final int count = files.size();
+ ScrollableImagePreviewView imagePreview =
+ contentPreviewView.requireViewById(R.id.scrollable_image_preview);
+ if (count == 0) {
+ Log.i(
+ TAG,
+ "Attempted to display image preview area with zero"
+ + " available images detected in EXTRA_STREAM list");
+ imagePreview.setVisibility(View.GONE);
+ mTransitionElementStatusCallback.onAllTransitionElementsReady();
+ return;
+ }
+
+ List<ScrollableImagePreviewView.Preview> previews = new ArrayList<>();
+ boolean allImages = true;
+ boolean allVideos = true;
+ for (FileInfo fileInfo : files) {
+ ScrollableImagePreviewView.PreviewType previewType =
+ getPreviewType(mTypeClassifier, fileInfo.getMimeType());
+ allImages = allImages && previewType == ScrollableImagePreviewView.PreviewType.Image;
+ allVideos = allVideos && previewType == ScrollableImagePreviewView.PreviewType.Video;
+
+ if (fileInfo.getPreviewUri() != null) {
+ Runnable editAction =
+ mShowEditAction ? mActionFactory.getEditButtonRunnable() : null;
+ previews.add(
+ new ScrollableImagePreviewView.Preview(
+ previewType, fileInfo.getPreviewUri(), editAction));
+ }
+ }
+
+ imagePreview.setPreviews(previews, count - previews.size(), mImageLoader);
+
+ if (allImages) {
+ displayHeadline(contentPreviewView, mHeadlineGenerator.getImagesHeadline(count));
+ } else if (allVideos) {
+ displayHeadline(contentPreviewView, mHeadlineGenerator.getVideosHeadline(count));
+ } else {
+ displayHeadline(contentPreviewView, mHeadlineGenerator.getFilesHeadline(count));
+ }
+ }
+}
diff --git a/java/src/com/android/intentresolver/flags/Flags.kt b/java/src/com/android/intentresolver/flags/Flags.kt
index f4dbeddb..b303dd1a 100644
--- a/java/src/com/android/intentresolver/flags/Flags.kt
+++ b/java/src/com/android/intentresolver/flags/Flags.kt
@@ -16,39 +16,15 @@
package com.android.intentresolver.flags
+import com.android.systemui.flags.ReleasedFlag
import com.android.systemui.flags.UnreleasedFlag
// Flag id, name and namespace should be kept in sync with [com.android.systemui.flags.Flags] to
// make the flags available in the flag flipper app (see go/sysui-flags).
+// All flags added should be included in UnbundledChooserActivityTest.ALL_FLAGS.
object Flags {
- const val SHARESHEET_CUSTOM_ACTIONS_NAME = "sharesheet_custom_actions"
- const val SHARESHEET_RESELECTION_ACTION_NAME = "sharesheet_reselection_action"
- const val SHARESHEET_IMAGE_AND_TEXT_PREVIEW_NAME = "sharesheet_image_text_preview"
- const val SHARESHEET_SCROLLABLE_IMAGE_PREVIEW_NAME = "sharesheet_scrollable_image_preview"
-
- // TODO(b/266983432) Tracking Bug
- @JvmField
- val SHARESHEET_CUSTOM_ACTIONS = unreleasedFlag(
- 1501, SHARESHEET_CUSTOM_ACTIONS_NAME, teamfood = true
- )
-
- // TODO(b/266982749) Tracking Bug
- @JvmField
- val SHARESHEET_RESELECTION_ACTION = unreleasedFlag(
- 1502, SHARESHEET_RESELECTION_ACTION_NAME, teamfood = true
- )
-
- // TODO(b/266983474) Tracking Bug
- @JvmField
- val SHARESHEET_IMAGE_AND_TEXT_PREVIEW = unreleasedFlag(
- id = 1503, name = SHARESHEET_IMAGE_AND_TEXT_PREVIEW_NAME, teamfood = true
- )
-
- // TODO(b/267355521) Tracking Bug
- @JvmField
- val SHARESHEET_SCROLLABLE_IMAGE_PREVIEW = unreleasedFlag(
- 1504, SHARESHEET_SCROLLABLE_IMAGE_PREVIEW_NAME, teamfood = true
- )
+ private fun releasedFlag(id: Int, name: String) =
+ ReleasedFlag(id, name, "systemui")
private fun unreleasedFlag(id: Int, name: String, teamfood: Boolean = false) =
UnreleasedFlag(id, name, "systemui", teamfood)
diff --git a/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java b/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java
index 1cf59316..77ae20f5 100644
--- a/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java
+++ b/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java
@@ -58,7 +58,7 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.
/**
* Injectable interface for any considerations that should be delegated to other components
- * in the {@link ChooserActivity}.
+ * in the {@link com.android.intentresolver.ChooserActivity}.
* TODO: determine whether any of these methods return parameters that can safely be
* precomputed; whether any should be converted to `ChooserGridAdapter` setters to be
* invoked by external callbacks; and whether any reflect requirements that should be moved
@@ -89,26 +89,6 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.
* behaviors on this view.
*/
void updateProfileViewButton(View newButtonFromProfileRow);
-
- /**
- * @return the number of "valid" targets in the active list adapter.
- * TODO: define "valid."
- */
- int getValidTargetCount();
-
- /**
- * Request that the client update our {@code directShareGroup} to match their desired
- * state for the "expansion" UI.
- */
- void updateDirectShareExpansion(DirectShareViewHolder directShareGroup);
-
- /**
- * Request that the client handle a scroll event that should be taken as expanding the
- * provided {@code directShareGroup}. Note that this currently never happens due to a
- * hard-coded condition in {@link #canExpandDirectShare()}.
- */
- void handleScrollToExpandDirectShare(
- DirectShareViewHolder directShareGroup, int y, int oldy);
}
private static final int VIEW_TYPE_DIRECT_SHARE = 0;
@@ -119,8 +99,6 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.
private static final int VIEW_TYPE_CALLER_AND_RANK = 5;
private static final int VIEW_TYPE_FOOTER = 6;
- private static final int NUM_EXPANSIONS_TO_HIDE_AZ_LABEL = 20;
-
private final ChooserActivityDelegate mChooserActivityDelegate;
private final ChooserListAdapter mChooserListAdapter;
private final LayoutInflater mLayoutInflater;
@@ -129,20 +107,19 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.
private final boolean mShouldShowContentPreview;
private final int mChooserWidthPixels;
private final int mChooserRowTextOptionTranslatePixelSize;
- private final boolean mShowAzLabelIfPoss;
- private DirectShareViewHolder mDirectShareViewHolder;
private int mChooserTargetWidth = 0;
private int mFooterHeight = 0;
+ private boolean mAzLabelVisibility = false;
+
public ChooserGridAdapter(
Context context,
ChooserActivityDelegate chooserActivityDelegate,
ChooserListAdapter wrappedAdapter,
boolean shouldShowContentPreview,
- int maxTargetsPerRow,
- int numSheetExpansions) {
+ int maxTargetsPerRow) {
super();
mChooserActivityDelegate = chooserActivityDelegate;
@@ -157,8 +134,6 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.
mChooserRowTextOptionTranslatePixelSize = context.getResources().getDimensionPixelSize(
R.dimen.chooser_row_text_option_translate);
- mShowAzLabelIfPoss = numSheetExpansions < NUM_EXPANSIONS_TO_HIDE_AZ_LABEL;
-
wrappedAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
@@ -190,8 +165,7 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.
}
// Limit width to the maximum width of the chooser activity
- int maxWidth = mChooserWidthPixels;
- width = Math.min(maxWidth, width);
+ width = Math.min(mChooserWidthPixels, width);
int newWidth = width / mMaxTargetsPerRow;
if (newWidth != mChooserTargetWidth) {
@@ -265,20 +239,30 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.
public int getAzLabelRowCount() {
// Only show a label if the a-z list is showing
- return (mShowAzLabelIfPoss && mChooserListAdapter.getAlphaTargetCount() > 0) ? 1 : 0;
+ return (mChooserListAdapter.getAlphaTargetCount() > 0) ? 1 : 0;
+ }
+
+ private int getAzLabelRowPosition() {
+ int azRowCount = getAzLabelRowCount();
+ if (azRowCount == 0) {
+ return -1;
+ }
+
+ return getSystemRowCount()
+ + getProfileRowCount()
+ + getServiceTargetRowCount()
+ + getCallerAndRankedTargetRowCount();
}
@Override
public int getItemCount() {
- return (int) (
- getSystemRowCount()
- + getProfileRowCount()
- + getServiceTargetRowCount()
- + getCallerAndRankedTargetRowCount()
- + getAzLabelRowCount()
- + mChooserListAdapter.getAlphaTargetCount()
- + getFooterRowCount()
- );
+ return getSystemRowCount()
+ + getProfileRowCount()
+ + getServiceTargetRowCount()
+ + getCallerAndRankedTargetRowCount()
+ + getAzLabelRowCount()
+ + mChooserListAdapter.getAlphaTargetCount()
+ + getFooterRowCount();
}
@Override
@@ -322,8 +306,26 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.
}
}
+ /**
+ * Set the app divider's visibility, when it's present.
+ */
+ public void setAzLabelVisibility(boolean isVisible) {
+ if (mAzLabelVisibility == isVisible) {
+ return;
+ }
+ mAzLabelVisibility = isVisible;
+ int azRowPos = getAzLabelRowPosition();
+ if (azRowPos >= 0) {
+ notifyItemChanged(azRowPos);
+ }
+ }
+
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ if (holder.getItemViewType() == VIEW_TYPE_AZ_LABEL) {
+ holder.itemView.setVisibility(
+ mAzLabelVisibility ? View.VISIBLE : View.INVISIBLE);
+ }
int viewType = ((ViewHolderBase) holder).getViewType();
switch (viewType) {
case VIEW_TYPE_DIRECT_SHARE:
@@ -453,12 +455,11 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.
parentGroup.addView(row1);
parentGroup.addView(row2);
- mDirectShareViewHolder = new DirectShareViewHolder(parentGroup,
- Lists.newArrayList(row1, row2), mMaxTargetsPerRow, viewType,
- mChooserActivityDelegate::getValidTargetCount);
- loadViewsIntoGroup(mDirectShareViewHolder);
+ DirectShareViewHolder directShareViewHolder = new DirectShareViewHolder(parentGroup,
+ Lists.newArrayList(row1, row2), mMaxTargetsPerRow, viewType);
+ loadViewsIntoGroup(directShareViewHolder);
- return mDirectShareViewHolder;
+ return directShareViewHolder;
} else {
ViewGroup row = (ViewGroup) mLayoutInflater.inflate(
R.layout.chooser_row, parent, false);
@@ -572,21 +573,6 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.
return callerAndRankedCount + serviceCount + position;
}
- public void handleScroll(View v, int y, int oldy) {
- boolean canExpandDirectShare = canExpandDirectShare();
- if (mDirectShareViewHolder != null && canExpandDirectShare) {
- mChooserActivityDelegate.handleScrollToExpandDirectShare(
- mDirectShareViewHolder, y, oldy);
- }
- }
-
- /** Only expand direct share area if there is a minimum number of targets. */
- private boolean canExpandDirectShare() {
- // Do not enable until we have confirmed more apps are using sharing shortcuts
- // Check git history for enablement logic
- return false;
- }
-
public ChooserListAdapter getListAdapter() {
return mChooserListAdapter;
}
@@ -594,11 +580,4 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.
public boolean shouldCellSpan(int position) {
return getItemViewType(position) == VIEW_TYPE_NORMAL;
}
-
- public void updateDirectShareExpansion() {
- if (mDirectShareViewHolder == null || !canExpandDirectShare()) {
- return;
- }
- mChooserActivityDelegate.updateDirectShareExpansion(mDirectShareViewHolder);
- }
}
diff --git a/java/src/com/android/intentresolver/grid/DirectShareViewHolder.java b/java/src/com/android/intentresolver/grid/DirectShareViewHolder.java
index 316c9f07..ad78c719 100644
--- a/java/src/com/android/intentresolver/grid/DirectShareViewHolder.java
+++ b/java/src/com/android/intentresolver/grid/DirectShareViewHolder.java
@@ -25,35 +25,25 @@ import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.intentresolver.ChooserActivity;
-
import java.util.Arrays;
import java.util.List;
-import java.util.function.Supplier;
/** Holder for direct share targets in the {@link ChooserGridAdapter}. */
public class DirectShareViewHolder extends ItemGroupViewHolder {
private final ViewGroup mParent;
private final List<ViewGroup> mRows;
- private int mCellCountPerRow;
+ private final int mCellCountPerRow;
- private boolean mHideDirectShareExpansion = false;
private int mDirectShareMinHeight = 0;
private int mDirectShareCurrHeight = 0;
- private int mDirectShareMaxHeight = 0;
private final boolean[] mCellVisibility;
- private final Supplier<Integer> mDeferredTargetCountSupplier;
-
public DirectShareViewHolder(
ViewGroup parent,
List<ViewGroup> rows,
int cellCountPerRow,
- int viewType,
- Supplier<Integer> deferredTargetCountSupplier) {
+ int viewType) {
super(rows.size() * cellCountPerRow, parent, viewType);
this.mParent = parent;
@@ -61,7 +51,6 @@ public class DirectShareViewHolder extends ItemGroupViewHolder {
this.mCellCountPerRow = cellCountPerRow;
this.mCellVisibility = new boolean[rows.size() * cellCountPerRow];
Arrays.fill(mCellVisibility, true);
- this.mDeferredTargetCountSupplier = deferredTargetCountSupplier;
}
public ViewGroup addView(int index, View v) {
@@ -92,7 +81,6 @@ public class DirectShareViewHolder extends ItemGroupViewHolder {
mDirectShareMinHeight = getRow(0).getMeasuredHeight();
mDirectShareCurrHeight = (mDirectShareCurrHeight > 0)
? mDirectShareCurrHeight : mDirectShareMinHeight;
- mDirectShareMaxHeight = 2 * mDirectShareMinHeight;
}
public int getMeasuredRowHeight() {
@@ -123,75 +111,4 @@ public class DirectShareViewHolder extends ItemGroupViewHolder {
fadeAnim.start();
}
}
-
- public void handleScroll(RecyclerView view, int y, int oldy, int maxTargetsPerRow) {
- // only exit early if fully collapsed, otherwise onListRebuilt() with shifting
- // targets can lock us into an expanded mode
- boolean notExpanded = mDirectShareCurrHeight == mDirectShareMinHeight;
- if (notExpanded) {
- if (mHideDirectShareExpansion) {
- return;
- }
-
- // only expand if we have more than maxTargetsPerRow, and delay that decision
- // until they start to scroll
- final int validTargets = this.mDeferredTargetCountSupplier.get();
- if (validTargets <= maxTargetsPerRow) {
- mHideDirectShareExpansion = true;
- return;
- }
- }
-
- int yDiff = (int) ((oldy - y) * ChooserActivity.DIRECT_SHARE_EXPANSION_RATE);
-
- int prevHeight = mDirectShareCurrHeight;
- int newHeight = Math.min(prevHeight + yDiff, mDirectShareMaxHeight);
- newHeight = Math.max(newHeight, mDirectShareMinHeight);
- yDiff = newHeight - prevHeight;
-
- updateDirectShareRowHeight(view, yDiff, newHeight);
- }
-
- public void expand(RecyclerView view) {
- updateDirectShareRowHeight(
- view, mDirectShareMaxHeight - mDirectShareCurrHeight, mDirectShareMaxHeight);
- }
-
- public void collapse(RecyclerView view) {
- updateDirectShareRowHeight(
- view, mDirectShareMinHeight - mDirectShareCurrHeight, mDirectShareMinHeight);
- }
-
- private void updateDirectShareRowHeight(RecyclerView view, int yDiff, int newHeight) {
- if (view == null || view.getChildCount() == 0 || yDiff == 0) {
- return;
- }
-
- // locate the item to expand, and offset the rows below that one
- boolean foundExpansion = false;
- for (int i = 0; i < view.getChildCount(); i++) {
- View child = view.getChildAt(i);
-
- if (foundExpansion) {
- child.offsetTopAndBottom(yDiff);
- } else {
- if (child.getTag() != null && child.getTag() instanceof DirectShareViewHolder) {
- int widthSpec = MeasureSpec.makeMeasureSpec(child.getWidth(),
- MeasureSpec.EXACTLY);
- int heightSpec = MeasureSpec.makeMeasureSpec(newHeight,
- MeasureSpec.EXACTLY);
- child.measure(widthSpec, heightSpec);
- child.getLayoutParams().height = child.getMeasuredHeight();
- child.layout(child.getLeft(), child.getTop(), child.getRight(),
- child.getTop() + child.getMeasuredHeight());
-
- foundExpansion = true;
- }
- }
- }
-
- if (foundExpansion) {
- mDirectShareCurrHeight = newHeight;
- }
- }
}
diff --git a/java/src/com/android/intentresolver/icons/BaseLoadIconTask.java b/java/src/com/android/intentresolver/icons/BaseLoadIconTask.java
new file mode 100644
index 00000000..2eceb89c
--- /dev/null
+++ b/java/src/com/android/intentresolver/icons/BaseLoadIconTask.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.icons;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+
+import com.android.intentresolver.R;
+import com.android.intentresolver.TargetPresentationGetter;
+
+import java.util.function.Consumer;
+
+abstract class BaseLoadIconTask extends AsyncTask<Void, Void, Drawable> {
+ protected final Context mContext;
+ protected final TargetPresentationGetter.Factory mPresentationFactory;
+ private final Consumer<Drawable> mCallback;
+
+ BaseLoadIconTask(
+ Context context,
+ TargetPresentationGetter.Factory presentationFactory,
+ Consumer<Drawable> callback) {
+ mContext = context;
+ mPresentationFactory = presentationFactory;
+ mCallback = callback;
+ }
+
+ protected final Drawable loadIconPlaceholder() {
+ return mContext.getDrawable(R.drawable.resolver_icon_placeholder);
+ }
+
+ @Override
+ protected final void onPostExecute(Drawable d) {
+ mCallback.accept(d);
+ }
+}
diff --git a/java/src/com/android/intentresolver/icons/DefaultTargetDataLoader.kt b/java/src/com/android/intentresolver/icons/DefaultTargetDataLoader.kt
new file mode 100644
index 00000000..0e4d0209
--- /dev/null
+++ b/java/src/com/android/intentresolver/icons/DefaultTargetDataLoader.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.icons
+
+import android.app.ActivityManager
+import android.content.Context
+import android.content.pm.ResolveInfo
+import android.graphics.drawable.Drawable
+import android.os.AsyncTask
+import android.os.UserHandle
+import android.util.SparseArray
+import androidx.annotation.GuardedBy
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import com.android.intentresolver.TargetPresentationGetter
+import com.android.intentresolver.chooser.DisplayResolveInfo
+import com.android.intentresolver.chooser.SelectableTargetInfo
+import java.util.concurrent.atomic.AtomicInteger
+import java.util.function.Consumer
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asExecutor
+
+/** An actual [TargetDataLoader] implementation. */
+// TODO: replace async tasks with coroutines.
+class DefaultTargetDataLoader(
+ private val context: Context,
+ private val lifecycle: Lifecycle,
+ private val isAudioCaptureDevice: Boolean,
+) : TargetDataLoader() {
+ private val presentationFactory =
+ TargetPresentationGetter.Factory(
+ context,
+ context.getSystemService(ActivityManager::class.java)?.launcherLargeIconDensity
+ ?: error("Unable to access ActivityManager")
+ )
+ private val nextTaskId = AtomicInteger(0)
+ @GuardedBy("self") private val activeTasks = SparseArray<AsyncTask<*, *, *>>()
+ private val executor = Dispatchers.IO.asExecutor()
+
+ init {
+ lifecycle.addObserver(
+ object : DefaultLifecycleObserver {
+ override fun onDestroy(owner: LifecycleOwner) {
+ lifecycle.removeObserver(this)
+ destroy()
+ }
+ }
+ )
+ }
+
+ override fun loadAppTargetIcon(
+ info: DisplayResolveInfo,
+ userHandle: UserHandle,
+ callback: Consumer<Drawable>,
+ ) {
+ val taskId = nextTaskId.getAndIncrement()
+ LoadIconTask(context, info, userHandle, presentationFactory) { result ->
+ removeTask(taskId)
+ callback.accept(result)
+ }
+ .also { addTask(taskId, it) }
+ .executeOnExecutor(executor)
+ }
+
+ override fun loadDirectShareIcon(
+ info: SelectableTargetInfo,
+ userHandle: UserHandle,
+ callback: Consumer<Drawable>,
+ ) {
+ val taskId = nextTaskId.getAndIncrement()
+ LoadDirectShareIconTask(
+ context.createContextAsUser(userHandle, 0),
+ info,
+ presentationFactory,
+ ) { result ->
+ removeTask(taskId)
+ callback.accept(result)
+ }
+ .also { addTask(taskId, it) }
+ .executeOnExecutor(executor)
+ }
+
+ override fun loadLabel(info: DisplayResolveInfo, callback: Consumer<Array<CharSequence?>>) {
+ val taskId = nextTaskId.getAndIncrement()
+ LoadLabelTask(context, info, isAudioCaptureDevice, presentationFactory) { result ->
+ removeTask(taskId)
+ callback.accept(result)
+ }
+ .also { addTask(taskId, it) }
+ .executeOnExecutor(executor)
+ }
+
+ override fun createPresentationGetter(info: ResolveInfo): TargetPresentationGetter =
+ presentationFactory.makePresentationGetter(info)
+
+ private fun addTask(id: Int, task: AsyncTask<*, *, *>) {
+ synchronized(activeTasks) { activeTasks.put(id, task) }
+ }
+
+ private fun removeTask(id: Int) {
+ synchronized(activeTasks) { activeTasks.remove(id) }
+ }
+
+ private fun destroy() {
+ synchronized(activeTasks) {
+ for (i in 0 until activeTasks.size()) {
+ activeTasks.valueAt(i).cancel(false)
+ }
+ activeTasks.clear()
+ }
+ }
+}
diff --git a/java/src/com/android/intentresolver/icons/LoadDirectShareIconTask.java b/java/src/com/android/intentresolver/icons/LoadDirectShareIconTask.java
new file mode 100644
index 00000000..6aee69b5
--- /dev/null
+++ b/java/src/com/android/intentresolver/icons/LoadDirectShareIconTask.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.icons;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
+import android.content.pm.ShortcutInfo;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Trace;
+import android.util.Log;
+
+import androidx.annotation.WorkerThread;
+
+import com.android.intentresolver.SimpleIconFactory;
+import com.android.intentresolver.TargetPresentationGetter;
+import com.android.intentresolver.chooser.SelectableTargetInfo;
+import com.android.intentresolver.util.UriFilters;
+
+import java.util.function.Consumer;
+
+/**
+ * Loads direct share targets icons.
+ */
+class LoadDirectShareIconTask extends BaseLoadIconTask {
+ private static final String TAG = "DirectShareIconTask";
+ private final SelectableTargetInfo mTargetInfo;
+
+ LoadDirectShareIconTask(
+ Context context,
+ SelectableTargetInfo targetInfo,
+ TargetPresentationGetter.Factory presentationFactory,
+ Consumer<Drawable> callback) {
+ super(context, presentationFactory, callback);
+ mTargetInfo = targetInfo;
+ }
+
+ @Override
+ protected Drawable doInBackground(Void... voids) {
+ Drawable drawable;
+ Trace.beginSection("shortcut-icon");
+ try {
+ final Icon icon = mTargetInfo.getChooserTargetIcon();
+ if (icon == null || UriFilters.hasValidIcon(icon)) {
+ drawable = getChooserTargetIconDrawable(
+ mContext,
+ icon,
+ mTargetInfo.getChooserTargetComponentName(),
+ mTargetInfo.getDirectShareShortcutInfo());
+ } else {
+ Log.e(TAG, "Failed to load shortcut icon for "
+ + mTargetInfo.getChooserTargetComponentName() + "; no access");
+ drawable = loadIconPlaceholder();
+ }
+ } catch (Exception e) {
+ Log.e(
+ TAG,
+ "Failed to load shortcut icon for "
+ + mTargetInfo.getChooserTargetComponentName(),
+ e);
+ drawable = loadIconPlaceholder();
+ } finally {
+ Trace.endSection();
+ }
+ return drawable;
+ }
+
+ @WorkerThread
+ private Drawable getChooserTargetIconDrawable(
+ Context context,
+ @Nullable Icon icon,
+ ComponentName targetComponentName,
+ @Nullable ShortcutInfo shortcutInfo) {
+ Drawable directShareIcon = null;
+
+ // First get the target drawable and associated activity info
+ if (icon != null) {
+ directShareIcon = icon.loadDrawable(context);
+ } else if (shortcutInfo != null) {
+ LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
+ if (launcherApps != null) {
+ directShareIcon = launcherApps.getShortcutIconDrawable(shortcutInfo, 0);
+ }
+ }
+
+ if (directShareIcon == null) {
+ return null;
+ }
+
+ ActivityInfo info = null;
+ try {
+ info = context.getPackageManager().getActivityInfo(targetComponentName, 0);
+ } catch (PackageManager.NameNotFoundException error) {
+ Log.e(TAG, "Could not find activity associated with ChooserTarget");
+ }
+
+ if (info == null) {
+ return null;
+ }
+
+ // Now fetch app icon and raster with no badging even in work profile
+ Bitmap appIcon = mPresentationFactory.makePresentationGetter(info).getIconBitmap(null);
+
+ // Raster target drawable with appIcon as a badge
+ SimpleIconFactory sif = SimpleIconFactory.obtain(context);
+ Bitmap directShareBadgedIcon = sif.createAppBadgedIconBitmap(directShareIcon, appIcon);
+ sif.recycle();
+
+ return new BitmapDrawable(context.getResources(), directShareBadgedIcon);
+ }
+}
diff --git a/java/src/com/android/intentresolver/icons/LoadIconTask.java b/java/src/com/android/intentresolver/icons/LoadIconTask.java
new file mode 100644
index 00000000..37ce4093
--- /dev/null
+++ b/java/src/com/android/intentresolver/icons/LoadIconTask.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.icons;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.intentresolver.ResolverActivity;
+import com.android.intentresolver.TargetPresentationGetter;
+import com.android.intentresolver.chooser.DisplayResolveInfo;
+
+import java.util.function.Consumer;
+
+class LoadIconTask extends BaseLoadIconTask {
+ private static final String TAG = "IconTask";
+ protected final DisplayResolveInfo mDisplayResolveInfo;
+ private final UserHandle mUserHandle;
+ private final ResolveInfo mResolveInfo;
+
+ LoadIconTask(
+ Context context, DisplayResolveInfo dri,
+ UserHandle userHandle,
+ TargetPresentationGetter.Factory presentationFactory,
+ Consumer<Drawable> callback) {
+ super(context, presentationFactory, callback);
+ mUserHandle = userHandle;
+ mDisplayResolveInfo = dri;
+ mResolveInfo = dri.getResolveInfo();
+ }
+
+ @Override
+ protected Drawable doInBackground(Void... params) {
+ Trace.beginSection("app-icon");
+ try {
+ return loadIconForResolveInfo(mResolveInfo);
+ } catch (Exception e) {
+ ComponentName componentName = mDisplayResolveInfo.getResolvedComponentName();
+ Log.e(TAG, "Failed to load app icon for " + componentName, e);
+ return loadIconPlaceholder();
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ protected final Drawable loadIconForResolveInfo(ResolveInfo ri) {
+ // Load icons based on userHandle from ResolveInfo. If in work profile/clone profile, icons
+ // should be badged.
+ return mPresentationFactory.makePresentationGetter(ri)
+ .getIcon(ResolverActivity.getResolveInfoUserHandle(ri, mUserHandle));
+ }
+
+}
diff --git a/java/src/com/android/intentresolver/icons/LoadLabelTask.java b/java/src/com/android/intentresolver/icons/LoadLabelTask.java
new file mode 100644
index 00000000..a0867b8e
--- /dev/null
+++ b/java/src/com/android/intentresolver/icons/LoadLabelTask.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.icons;
+
+import android.content.Context;
+import android.content.PermissionChecker;
+import android.content.pm.ActivityInfo;
+import android.os.AsyncTask;
+import android.os.Trace;
+
+import com.android.intentresolver.R;
+import com.android.intentresolver.TargetPresentationGetter;
+import com.android.intentresolver.chooser.DisplayResolveInfo;
+
+import java.util.function.Consumer;
+
+class LoadLabelTask extends AsyncTask<Void, Void, CharSequence[]> {
+ private final Context mContext;
+ private final DisplayResolveInfo mDisplayResolveInfo;
+ private final boolean mIsAudioCaptureDevice;
+ protected final TargetPresentationGetter.Factory mPresentationFactory;
+ private final Consumer<CharSequence[]> mCallback;
+
+ LoadLabelTask(Context context, DisplayResolveInfo dri,
+ boolean isAudioCaptureDevice, TargetPresentationGetter.Factory presentationFactory,
+ Consumer<CharSequence[]> callback) {
+ mContext = context;
+ mDisplayResolveInfo = dri;
+ mIsAudioCaptureDevice = isAudioCaptureDevice;
+ mPresentationFactory = presentationFactory;
+ mCallback = callback;
+ }
+
+ @Override
+ protected CharSequence[] doInBackground(Void... voids) {
+ try {
+ Trace.beginSection("app-label");
+ return loadLabel();
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ private CharSequence[] loadLabel() {
+ TargetPresentationGetter pg = mPresentationFactory.makePresentationGetter(
+ mDisplayResolveInfo.getResolveInfo());
+
+ if (mIsAudioCaptureDevice) {
+ // This is an audio capture device, so check record permissions
+ ActivityInfo activityInfo = mDisplayResolveInfo.getResolveInfo().activityInfo;
+ String packageName = activityInfo.packageName;
+
+ int uid = activityInfo.applicationInfo.uid;
+ boolean hasRecordPermission =
+ PermissionChecker.checkPermissionForPreflight(
+ mContext,
+ android.Manifest.permission.RECORD_AUDIO, -1, uid,
+ packageName)
+ == android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+ if (!hasRecordPermission) {
+ // Doesn't have record permission, so warn the user
+ return new CharSequence[]{
+ pg.getLabel(),
+ mContext.getString(R.string.usb_device_resolve_prompt_warn)
+ };
+ }
+ }
+
+ return new CharSequence[]{
+ pg.getLabel(),
+ pg.getSubLabel()
+ };
+ }
+
+ @Override
+ protected void onPostExecute(CharSequence[] result) {
+ mCallback.accept(result);
+ }
+}
diff --git a/java/src/com/android/intentresolver/icons/TargetDataLoader.kt b/java/src/com/android/intentresolver/icons/TargetDataLoader.kt
new file mode 100644
index 00000000..50f731f8
--- /dev/null
+++ b/java/src/com/android/intentresolver/icons/TargetDataLoader.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.icons
+
+import android.content.pm.ResolveInfo
+import android.graphics.drawable.Drawable
+import android.os.UserHandle
+import com.android.intentresolver.TargetPresentationGetter
+import com.android.intentresolver.chooser.DisplayResolveInfo
+import com.android.intentresolver.chooser.SelectableTargetInfo
+import java.util.function.Consumer
+
+/** A target data loader contract. Added to support testing. */
+abstract class TargetDataLoader {
+ /** Load an app target icon */
+ abstract fun loadAppTargetIcon(
+ info: DisplayResolveInfo,
+ userHandle: UserHandle,
+ callback: Consumer<Drawable>,
+ )
+
+ /** Load a shortcut icon */
+ abstract fun loadDirectShareIcon(
+ info: SelectableTargetInfo,
+ userHandle: UserHandle,
+ callback: Consumer<Drawable>,
+ )
+
+ /** Load target label */
+ abstract fun loadLabel(info: DisplayResolveInfo, callback: Consumer<Array<CharSequence?>>)
+
+ /** Create a presentation getter to be used with a [DisplayResolveInfo] */
+ // TODO: get rid of DisplayResolveInfo's dependency on the presentation getter and remove this
+ // method.
+ abstract fun createPresentationGetter(info: ResolveInfo): TargetPresentationGetter
+}
diff --git a/java/src/com/android/intentresolver/measurements/Tracer.kt b/java/src/com/android/intentresolver/measurements/Tracer.kt
new file mode 100644
index 00000000..5f69932a
--- /dev/null
+++ b/java/src/com/android/intentresolver/measurements/Tracer.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.measurements
+
+import android.os.SystemClock
+import android.os.Trace
+import android.os.UserHandle
+import android.util.SparseArray
+import androidx.annotation.GuardedBy
+import java.util.concurrent.atomic.AtomicInteger
+import java.util.concurrent.atomic.AtomicLong
+
+private const val SECTION_LAUNCH_TO_SHORTCUT = "launch-to-shortcut"
+private const val SECTION_APP_PREDICTOR_PREFIX = "app-predictor-"
+private const val SECTION_APP_TARGET_PREFIX = "app-target-"
+
+object Tracer {
+ private val launchToFirstShortcut = AtomicLong(-1L)
+ private val nextId = AtomicInteger(0)
+ @GuardedBy("self") private val profileRecords = SparseArray<ProfileRecord>()
+
+ fun markLaunched() {
+ if (launchToFirstShortcut.compareAndSet(-1, elapsedTimeNow())) {
+ Trace.beginAsyncSection(SECTION_LAUNCH_TO_SHORTCUT, 1)
+ }
+ }
+
+ fun endLaunchToShortcutTrace(): Long {
+ val time = elapsedTimeNow()
+ val startTime = launchToFirstShortcut.get()
+ return if (startTime >= 0 && launchToFirstShortcut.compareAndSet(startTime, -1L)) {
+ Trace.endAsyncSection(SECTION_LAUNCH_TO_SHORTCUT, 1)
+ time - startTime
+ } else {
+ -1L
+ }
+ }
+
+ /**
+ * Begin shortcuts request tracing. The logic is based on an assumption that each request for
+ * shortcuts update is followed by at least one response. Note, that it is not always measure
+ * the request duration correctly as in the case of a two overlapping requests when the second
+ * requests starts and ends while the first is running, the end of the second request will be
+ * attributed to the first. This is tolerable as this still represents the visible to the user
+ * app's behavior and expected to be quite rare.
+ */
+ fun beginAppPredictorQueryTrace(userHandle: UserHandle) {
+ val queue = getUserShortcutRequestQueue(userHandle, createIfMissing = true) ?: return
+ val startTime = elapsedTimeNow()
+ val id = nextId.getAndIncrement()
+ val sectionName = userHandle.toAppPredictorSectionName()
+ synchronized(queue) {
+ Trace.beginAsyncSection(sectionName, id)
+ queue.addFirst(longArrayOf(startTime, id.toLong()))
+ }
+ }
+
+ /**
+ * End shortcut request tracing, see [beginAppPredictorQueryTrace].
+ *
+ * @return request duration is milliseconds.
+ */
+ fun endAppPredictorQueryTrace(userHandle: UserHandle): Long {
+ val queue = getUserShortcutRequestQueue(userHandle, createIfMissing = false) ?: return -1L
+ val endTime = elapsedTimeNow()
+ val sectionName = userHandle.toAppPredictorSectionName()
+ return synchronized(queue) { queue.removeLastOrNull() }
+ ?.let { record ->
+ Trace.endAsyncSection(sectionName, record[1].toInt())
+ endTime - record[0]
+ }
+ ?: -1L
+ }
+
+ /**
+ * Trace app target loading section per profile. If there's already an active section, it will
+ * be ended an a new section started.
+ */
+ fun beginAppTargetLoadingSection(userHandle: UserHandle) {
+ val profile = getProfileRecord(userHandle, createIfMissing = true) ?: return
+ val sectionName = userHandle.toAppTargetSectionName()
+ val time = elapsedTimeNow()
+ synchronized(profile) {
+ if (profile.appTargetLoading >= 0) {
+ Trace.endAsyncSection(sectionName, 0)
+ }
+ profile.appTargetLoading = time
+ Trace.beginAsyncSection(sectionName, 0)
+ }
+ }
+
+ fun endAppTargetLoadingSection(userHandle: UserHandle): Long {
+ val profile = getProfileRecord(userHandle, createIfMissing = false) ?: return -1L
+ val time = elapsedTimeNow()
+ val sectionName = userHandle.toAppTargetSectionName()
+ return synchronized(profile) {
+ if (profile.appTargetLoading >= 0) {
+ Trace.endAsyncSection(sectionName, 0)
+ (time - profile.appTargetLoading).also { profile.appTargetLoading = -1L }
+ } else {
+ -1L
+ }
+ }
+ }
+
+ private fun getUserShortcutRequestQueue(
+ userHandle: UserHandle,
+ createIfMissing: Boolean
+ ): ArrayDeque<LongArray>? = getProfileRecord(userHandle, createIfMissing)?.appPredictorRequests
+
+ private fun getProfileRecord(userHandle: UserHandle, createIfMissing: Boolean): ProfileRecord? =
+ synchronized(profileRecords) {
+ val idx = profileRecords.indexOfKey(userHandle.identifier)
+ when {
+ idx >= 0 -> profileRecords.valueAt(idx)
+ createIfMissing ->
+ ProfileRecord().also { profileRecords.put(userHandle.identifier, it) }
+ else -> null
+ }
+ }
+
+ private fun elapsedTimeNow() = SystemClock.elapsedRealtime()
+}
+
+private class ProfileRecord {
+ val appPredictorRequests = ArrayDeque<LongArray>()
+ @GuardedBy("this") var appTargetLoading = -1L
+}
+
+private fun UserHandle.toAppPredictorSectionName() = SECTION_APP_PREDICTOR_PREFIX + identifier
+
+private fun UserHandle.toAppTargetSectionName() = SECTION_APP_TARGET_PREFIX + identifier
+
+inline fun <R> runTracing(name: String, block: () -> R): R {
+ Trace.beginSection(name)
+ try {
+ return block()
+ } finally {
+ Trace.endSection()
+ }
+}
diff --git a/java/src/com/android/intentresolver/model/AbstractResolverComparator.java b/java/src/com/android/intentresolver/model/AbstractResolverComparator.java
index ea767568..bc54e01e 100644
--- a/java/src/com/android/intentresolver/model/AbstractResolverComparator.java
+++ b/java/src/com/android/intentresolver/model/AbstractResolverComparator.java
@@ -16,6 +16,7 @@
package com.android.intentresolver.model;
+import android.annotation.Nullable;
import android.app.usage.UsageStatsManager;
import android.content.ComponentName;
import android.content.Context;
@@ -32,11 +33,14 @@ import android.util.Log;
import com.android.intentresolver.ChooserActivityLogger;
import com.android.intentresolver.ResolvedComponentInfo;
import com.android.intentresolver.ResolverActivity;
+import com.android.intentresolver.chooser.TargetInfo;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Used to sort resolved activities in {@link ResolverListController}.
@@ -50,10 +54,11 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC
private static final String TAG = "AbstractResolverComp";
protected Runnable mAfterCompute;
- protected final PackageManager mPm;
- protected final UsageStatsManager mUsm;
+ protected final Map<UserHandle, PackageManager> mPmMap = new HashMap<>();
+ protected final Map<UserHandle, UsageStatsManager> mUsmMap = new HashMap<>();
protected String[] mAnnotations;
protected String mContentType;
+ protected final ComponentName mPromoteToFirst;
// True if the current share is a link.
private final boolean mHttp;
@@ -100,14 +105,35 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC
}
};
- public AbstractResolverComparator(Context context, Intent intent) {
+ /**
+ * Constructor to initialize the comparator.
+ * @param launchedFromContext the activity calling this comparator
+ * @param intent original intent
+ * @param resolvedActivityUserSpaceList refers to the userSpace(s) used by the comparator for
+ * fetching activity stats and recording activity
+ * selection. The latter could be different from the
+ * userSpace provided by context.
+ * @param promoteToFirst a component to be moved to the front of the app list if it's being
+ * ranked. Unlike pinned apps, this cannot be modified by the user.
+ */
+ public AbstractResolverComparator(
+ Context launchedFromContext,
+ Intent intent,
+ List<UserHandle> resolvedActivityUserSpaceList,
+ @Nullable ComponentName promoteToFirst) {
String scheme = intent.getScheme();
mHttp = "http".equals(scheme) || "https".equals(scheme);
mContentType = intent.getType();
getContentAnnotations(intent);
- mPm = context.getPackageManager();
- mUsm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
- mAzComparator = new AzInfoComparator(context);
+ for (UserHandle user : resolvedActivityUserSpaceList) {
+ Context userContext = launchedFromContext.createContextAsUser(user, 0);
+ mPmMap.put(user, userContext.getPackageManager());
+ mUsmMap.put(
+ user,
+ (UsageStatsManager) userContext.getSystemService(Context.USAGE_STATS_SERVICE));
+ }
+ mAzComparator = new AzInfoComparator(launchedFromContext);
+ mPromoteToFirst = promoteToFirst;
}
// get annotations of content from intent.
@@ -163,6 +189,16 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC
return -1;
}
+ if (mPromoteToFirst != null) {
+ // A single component can be cemented to the front of the list. If it is seen, let it
+ // always get priority.
+ if (mPromoteToFirst.equals(lhs.activityInfo.getComponentName())) {
+ return -1;
+ } else if (mPromoteToFirst.equals(rhs.activityInfo.getComponentName())) {
+ return 1;
+ }
+ }
+
if (mHttp) {
final boolean lhsSpecific = ResolverActivity.isSpecificUriMatch(lhs.match);
final boolean rhsSpecific = ResolverActivity.isSpecificUriMatch(rhs.match);
@@ -197,8 +233,8 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC
/**
* Computes features for each target. This will be called before calls to {@link
- * #getScore(ComponentName)} or {@link #compare(Object, Object)}, in order to prepare the
- * comparator for those calls. Note that {@link #getScore(ComponentName)} uses {@link
+ * #getScore(TargetInfo)} or {@link #compare(ResolveInfo, ResolveInfo)}, in order to prepare the
+ * comparator for those calls. Note that {@link #getScore(TargetInfo)} uses {@link
* ComponentName}, so the implementation will have to be prepared to identify a {@link
* ResolvedComponentInfo} by {@link ComponentName}. {@link #beforeCompute()} will be called
* before doing any computing.
@@ -215,7 +251,7 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC
* Returns the score that was calculated for the corresponding {@link ResolvedComponentInfo}
* when {@link #compute(List)} was called before this.
*/
- public abstract float getScore(ComponentName name);
+ public abstract float getScore(TargetInfo targetInfo);
/** Handles result message sent to mHandler. */
abstract void handleResultMessage(Message message);
@@ -223,9 +259,14 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC
/**
* Reports to UsageStats what was chosen.
*/
- public final void updateChooserCounts(String packageName, int userId, String action) {
- if (mUsm != null) {
- mUsm.reportChooserSelection(packageName, userId, mContentType, mAnnotations, action);
+ public final void updateChooserCounts(String packageName, UserHandle user, String action) {
+ if (mUsmMap.containsKey(user)) {
+ mUsmMap.get(user).reportChooserSelection(
+ packageName,
+ user.getIdentifier(),
+ mContentType,
+ mAnnotations,
+ action);
}
}
@@ -235,9 +276,9 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC
* <p>Default implementation does nothing, as we could have simple model that does not train
* online.
*
- * @param componentName the component that the user clicked
+ * * @param targetInfo the target that the user clicked.
*/
- public void updateModel(ComponentName componentName) {
+ public void updateModel(TargetInfo targetInfo) {
}
/** Called before {@link #doCompute(List)}. Sets up 500ms timeout. */
diff --git a/java/src/com/android/intentresolver/model/AppPredictionServiceResolverComparator.java b/java/src/com/android/intentresolver/model/AppPredictionServiceResolverComparator.java
index c986ef15..ba054731 100644
--- a/java/src/com/android/intentresolver/model/AppPredictionServiceResolverComparator.java
+++ b/java/src/com/android/intentresolver/model/AppPredictionServiceResolverComparator.java
@@ -33,6 +33,9 @@ import android.util.Log;
import com.android.intentresolver.ChooserActivityLogger;
import com.android.intentresolver.ResolvedComponentInfo;
+import com.android.intentresolver.chooser.TargetInfo;
+
+import com.google.android.collect.Lists;
import java.util.ArrayList;
import java.util.Comparator;
@@ -69,8 +72,9 @@ public class AppPredictionServiceResolverComparator extends AbstractResolverComp
String referrerPackage,
AppPredictor appPredictor,
UserHandle user,
- ChooserActivityLogger chooserActivityLogger) {
- super(context, intent);
+ ChooserActivityLogger chooserActivityLogger,
+ @Nullable ComponentName promoteToFirst) {
+ super(context, intent, Lists.newArrayList(user), promoteToFirst);
mContext = context;
mIntent = intent;
mAppPredictor = appPredictor;
@@ -108,9 +112,13 @@ public class AppPredictionServiceResolverComparator extends AbstractResolverComp
// APS for chooser is disabled. Fallback to resolver.
mResolverRankerService =
new ResolverRankerServiceResolverComparator(
- mContext, mIntent, mReferrerPackage,
+ mContext,
+ mIntent,
+ mReferrerPackage,
() -> mHandler.sendEmptyMessage(RANKER_SERVICE_RESULT),
- getChooserActivityLogger());
+ getChooserActivityLogger(),
+ mUser,
+ mPromoteToFirst);
mComparatorModel = buildUpdatedModel();
mResolverRankerService.compute(targets);
} else {
@@ -167,13 +175,13 @@ public class AppPredictionServiceResolverComparator extends AbstractResolverComp
}
@Override
- public float getScore(ComponentName name) {
- return mComparatorModel.getScore(name);
+ public float getScore(TargetInfo targetInfo) {
+ return mComparatorModel.getScore(targetInfo);
}
@Override
- public void updateModel(ComponentName componentName) {
- mComparatorModel.notifyOnTargetSelected(componentName);
+ public void updateModel(TargetInfo targetInfo) {
+ mComparatorModel.notifyOnTargetSelected(targetInfo);
}
@Override
@@ -246,11 +254,11 @@ public class AppPredictionServiceResolverComparator extends AbstractResolverComp
}
@Override
- public float getScore(ComponentName name) {
+ public float getScore(TargetInfo targetInfo) {
if (mResolverRankerService != null) {
- return mResolverRankerService.getScore(name);
+ return mResolverRankerService.getScore(targetInfo);
}
- Integer rank = mTargetRanks.get(name);
+ Integer rank = mTargetRanks.get(targetInfo.getResolvedComponentName());
if (rank == null) {
Log.w(TAG, "Score requested for unknown component. Did you call compute yet?");
return 0f;
@@ -260,18 +268,19 @@ public class AppPredictionServiceResolverComparator extends AbstractResolverComp
}
@Override
- public void notifyOnTargetSelected(ComponentName componentName) {
+ public void notifyOnTargetSelected(TargetInfo targetInfo) {
if (mResolverRankerService != null) {
- mResolverRankerService.updateModel(componentName);
+ mResolverRankerService.updateModel(targetInfo);
return;
}
+ ComponentName targetComponent = targetInfo.getResolvedComponentName();
+ AppTargetId targetId = new AppTargetId(targetComponent.toString());
+ AppTarget appTarget =
+ new AppTarget.Builder(targetId, targetComponent.getPackageName(), mUser)
+ .setClassName(targetComponent.getClassName())
+ .build();
mAppPredictor.notifyAppTargetEvent(
- new AppTargetEvent.Builder(
- new AppTarget.Builder(
- new AppTargetId(componentName.toString()),
- componentName.getPackageName(), mUser)
- .setClassName(componentName.getClassName()).build(),
- ACTION_LAUNCH).build());
+ new AppTargetEvent.Builder(appTarget, ACTION_LAUNCH).build());
}
}
}
diff --git a/java/src/com/android/intentresolver/model/ResolverComparatorModel.java b/java/src/com/android/intentresolver/model/ResolverComparatorModel.java
index 3616a853..4835ea17 100644
--- a/java/src/com/android/intentresolver/model/ResolverComparatorModel.java
+++ b/java/src/com/android/intentresolver/model/ResolverComparatorModel.java
@@ -16,9 +16,10 @@
package com.android.intentresolver.model;
-import android.content.ComponentName;
import android.content.pm.ResolveInfo;
+import com.android.intentresolver.chooser.TargetInfo;
+
import java.util.Comparator;
/**
@@ -44,7 +45,7 @@ interface ResolverComparatorModel {
* likelihood that the user will select that component as the target. Implementations that don't
* assign numerical scores are <em>recommended</em> to return a value of 0 for all components.
*/
- float getScore(ComponentName name);
+ float getScore(TargetInfo targetInfo);
/**
* Notify the model that the user selected a target. (Models may log this information, use it as
@@ -52,5 +53,5 @@ interface ResolverComparatorModel {
* {@code ResolverComparatorModel} instance is immutable, clients will need to get an up-to-date
* instance in order to see any changes in the ranking that might result from this feedback.
*/
- void notifyOnTargetSelected(ComponentName componentName);
+ void notifyOnTargetSelected(TargetInfo targetInfo);
}
diff --git a/java/src/com/android/intentresolver/model/ResolverRankerServiceResolverComparator.java b/java/src/com/android/intentresolver/model/ResolverRankerServiceResolverComparator.java
index 0431078c..ebaffc36 100644
--- a/java/src/com/android/intentresolver/model/ResolverRankerServiceResolverComparator.java
+++ b/java/src/com/android/intentresolver/model/ResolverRankerServiceResolverComparator.java
@@ -17,11 +17,13 @@
package com.android.intentresolver.model;
+import android.annotation.Nullable;
import android.app.usage.UsageStats;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -39,12 +41,16 @@ import android.util.Log;
import com.android.intentresolver.ChooserActivityLogger;
import com.android.intentresolver.ResolvedComponentInfo;
+import com.android.intentresolver.chooser.TargetInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.google.android.collect.Lists;
+
import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -70,10 +76,10 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
private static final int CONNECTION_COST_TIMEOUT_MILLIS = 200;
private final Collator mCollator;
- private final Map<String, UsageStats> mStats;
+ private final Map<UserHandle, Map<String, UsageStats>> mStatsPerUser;
private final long mCurrentTime;
private final long mSinceTime;
- private final LinkedHashMap<ComponentName, ResolverTarget> mTargetsDict = new LinkedHashMap<>();
+ private final Map<UserHandle, Map<ComponentName, ResolverTarget>> mTargetsDictPerUser;
private final String mReferrerPackage;
private final Object mLock = new Object();
private ArrayList<ResolverTarget> mTargets;
@@ -86,17 +92,50 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
private CountDownLatch mConnectSignal;
private ResolverRankerServiceComparatorModel mComparatorModel;
- public ResolverRankerServiceResolverComparator(Context context, Intent intent,
- String referrerPackage, Runnable afterCompute,
- ChooserActivityLogger chooserActivityLogger) {
- super(context, intent);
- mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
+ /**
+ * Constructor to initialize the comparator.
+ * @param launchedFromContext the activity calling this comparator
+ * @param intent original intent
+ * @param targetUserSpace the userSpace(s) used by the comparator for fetching activity stats
+ * and recording activity selection. The latter could be different from
+ * the userSpace provided by context.
+ */
+ public ResolverRankerServiceResolverComparator(Context launchedFromContext, Intent intent,
+ String referrerPackage, Runnable afterCompute,
+ ChooserActivityLogger chooserActivityLogger, UserHandle targetUserSpace,
+ ComponentName promoteToFirst) {
+ this(launchedFromContext, intent, referrerPackage, afterCompute, chooserActivityLogger,
+ Lists.newArrayList(targetUserSpace), promoteToFirst);
+ }
+
+ /**
+ * Constructor to initialize the comparator.
+ * @param launchedFromContext the activity calling this comparator
+ * @param intent original intent
+ * @param targetUserSpaceList the userSpace(s) used by the comparator for fetching activity
+ * stats and recording activity selection. The latter could be
+ * different from the userSpace provided by context.
+ */
+ public ResolverRankerServiceResolverComparator(Context launchedFromContext, Intent intent,
+ String referrerPackage, Runnable afterCompute,
+ ChooserActivityLogger chooserActivityLogger, List<UserHandle> targetUserSpaceList,
+ @Nullable ComponentName promoteToFirst) {
+ super(launchedFromContext, intent, targetUserSpaceList, promoteToFirst);
+ mCollator = Collator.getInstance(
+ launchedFromContext.getResources().getConfiguration().locale);
mReferrerPackage = referrerPackage;
- mContext = context;
+ mContext = launchedFromContext;
mCurrentTime = System.currentTimeMillis();
mSinceTime = mCurrentTime - USAGE_STATS_PERIOD;
- mStats = mUsm.queryAndAggregateUsageStats(mSinceTime, mCurrentTime);
+ mStatsPerUser = new HashMap<>();
+ mTargetsDictPerUser = new HashMap<>();
+ for (UserHandle user : targetUserSpaceList) {
+ mStatsPerUser.put(
+ user,
+ mUsmMap.get(user).queryAndAggregateUsageStats(mSinceTime, mCurrentTime));
+ mTargetsDictPerUser.put(user, new LinkedHashMap<>());
+ }
mAction = intent.getAction();
mRankerServiceName = new ComponentName(mContext, this.getClass());
setCallBack(afterCompute);
@@ -147,58 +186,68 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
float mostChooserScore = 1.0f;
for (ResolvedComponentInfo target : targets) {
+ if (target.getResolveInfoAt(0) == null) {
+ continue;
+ }
final ResolverTarget resolverTarget = new ResolverTarget();
- mTargetsDict.put(target.name, resolverTarget);
- final UsageStats pkStats = mStats.get(target.name.getPackageName());
- if (pkStats != null) {
- // Only count recency for apps that weren't the caller
- // since the caller is always the most recent.
- // Persistent processes muck this up, so omit them too.
- if (!target.name.getPackageName().equals(mReferrerPackage)
- && !isPersistentProcess(target)) {
- final float recencyScore =
- (float) Math.max(pkStats.getLastTimeUsed() - recentSinceTime, 0);
- resolverTarget.setRecencyScore(recencyScore);
- if (recencyScore > mostRecencyScore) {
- mostRecencyScore = recencyScore;
+ final UserHandle resolvedComponentUserSpace =
+ target.getResolveInfoAt(0).userHandle;
+ final Map<ComponentName, ResolverTarget> targetsDict =
+ mTargetsDictPerUser.get(resolvedComponentUserSpace);
+ final Map<String, UsageStats> stats = mStatsPerUser.get(resolvedComponentUserSpace);
+ if (targetsDict != null && stats != null) {
+ targetsDict.put(target.name, resolverTarget);
+ final UsageStats pkStats = stats.get(target.name.getPackageName());
+ if (pkStats != null) {
+ // Only count recency for apps that weren't the caller
+ // since the caller is always the most recent.
+ // Persistent processes muck this up, so omit them too.
+ if (!target.name.getPackageName().equals(mReferrerPackage)
+ && !isPersistentProcess(target)) {
+ final float recencyScore =
+ (float) Math.max(pkStats.getLastTimeUsed() - recentSinceTime, 0);
+ resolverTarget.setRecencyScore(recencyScore);
+ if (recencyScore > mostRecencyScore) {
+ mostRecencyScore = recencyScore;
+ }
+ }
+ final float timeSpentScore = (float) pkStats.getTotalTimeInForeground();
+ resolverTarget.setTimeSpentScore(timeSpentScore);
+ if (timeSpentScore > mostTimeSpentScore) {
+ mostTimeSpentScore = timeSpentScore;
+ }
+ final float launchScore = (float) pkStats.mLaunchCount;
+ resolverTarget.setLaunchScore(launchScore);
+ if (launchScore > mostLaunchScore) {
+ mostLaunchScore = launchScore;
}
- }
- final float timeSpentScore = (float) pkStats.getTotalTimeInForeground();
- resolverTarget.setTimeSpentScore(timeSpentScore);
- if (timeSpentScore > mostTimeSpentScore) {
- mostTimeSpentScore = timeSpentScore;
- }
- final float launchScore = (float) pkStats.mLaunchCount;
- resolverTarget.setLaunchScore(launchScore);
- if (launchScore > mostLaunchScore) {
- mostLaunchScore = launchScore;
- }
- float chooserScore = 0.0f;
- if (pkStats.mChooserCounts != null && mAction != null
- && pkStats.mChooserCounts.get(mAction) != null) {
- chooserScore = (float) pkStats.mChooserCounts.get(mAction)
- .getOrDefault(mContentType, 0);
- if (mAnnotations != null) {
- final int size = mAnnotations.length;
- for (int i = 0; i < size; i++) {
- chooserScore += (float) pkStats.mChooserCounts.get(mAction)
- .getOrDefault(mAnnotations[i], 0);
+ float chooserScore = 0.0f;
+ if (pkStats.mChooserCounts != null && mAction != null
+ && pkStats.mChooserCounts.get(mAction) != null) {
+ chooserScore = (float) pkStats.mChooserCounts.get(mAction)
+ .getOrDefault(mContentType, 0);
+ if (mAnnotations != null) {
+ final int size = mAnnotations.length;
+ for (int i = 0; i < size; i++) {
+ chooserScore += (float) pkStats.mChooserCounts.get(mAction)
+ .getOrDefault(mAnnotations[i], 0);
+ }
}
}
- }
- if (DEBUG) {
- if (mAction == null) {
- Log.d(TAG, "Action type is null");
- } else {
- Log.d(TAG, "Chooser Count of " + mAction + ":"
- + target.name.getPackageName() + " is "
- + Float.toString(chooserScore));
+ if (DEBUG) {
+ if (mAction == null) {
+ Log.d(TAG, "Action type is null");
+ } else {
+ Log.d(TAG, "Chooser Count of " + mAction + ":"
+ + target.name.getPackageName() + " is "
+ + Float.toString(chooserScore));
+ }
+ }
+ resolverTarget.setChooserScore(chooserScore);
+ if (chooserScore > mostChooserScore) {
+ mostChooserScore = chooserScore;
}
- }
- resolverTarget.setChooserScore(chooserScore);
- if (chooserScore > mostChooserScore) {
- mostChooserScore = chooserScore;
}
}
}
@@ -210,7 +259,10 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
+ " mostChooserScore: " + mostChooserScore);
}
- mTargets = new ArrayList<>(mTargetsDict.values());
+ mTargets = new ArrayList<>();
+ for (UserHandle u : mTargetsDictPerUser.keySet()) {
+ mTargets.addAll(mTargetsDictPerUser.get(u).values());
+ }
for (ResolverTarget target : mTargets) {
final float recency = target.getRecencyScore() / mostRecencyScore;
setFeatures(target, recency * recency * RECENCY_MULTIPLIER,
@@ -233,15 +285,15 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
}
@Override
- public float getScore(ComponentName name) {
- return mComparatorModel.getScore(name);
+ public float getScore(TargetInfo targetInfo) {
+ return mComparatorModel.getScore(targetInfo);
}
// update ranking model when the connection to it is valid.
@Override
- public void updateModel(ComponentName componentName) {
+ public void updateModel(TargetInfo targetInfo) {
synchronized (mLock) {
- mComparatorModel.notifyOnTargetSelected(componentName);
+ mComparatorModel.notifyOnTargetSelected(targetInfo);
}
}
@@ -282,7 +334,8 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
// resolve the service for ranking.
private Intent resolveRankerService() {
Intent intent = new Intent(ResolverRankerService.SERVICE_INTERFACE);
- final List<ResolveInfo> resolveInfos = mPm.queryIntentServices(intent, 0);
+ final List<ResolveInfo> resolveInfos = mContext.getPackageManager()
+ .queryIntentServices(intent, 0);
for (ResolveInfo resolveInfo : resolveInfos) {
if (resolveInfo == null || resolveInfo.serviceInfo == null
|| resolveInfo.serviceInfo.applicationInfo == null) {
@@ -295,7 +348,8 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
resolveInfo.serviceInfo.applicationInfo.packageName,
resolveInfo.serviceInfo.name);
try {
- final String perm = mPm.getServiceInfo(componentName, 0).permission;
+ final String perm =
+ mContext.getPackageManager().getServiceInfo(componentName, 0).permission;
if (!ResolverRankerService.BIND_PERMISSION.equals(perm)) {
Log.w(TAG, "ResolverRankerService " + componentName + " does not require"
+ " permission " + ResolverRankerService.BIND_PERMISSION
@@ -306,9 +360,9 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
+ " in the manifest.");
continue;
}
- if (PackageManager.PERMISSION_GRANTED != mPm.checkPermission(
- ResolverRankerService.HOLD_PERMISSION,
- resolveInfo.serviceInfo.packageName)) {
+ if (PackageManager.PERMISSION_GRANTED != mContext.getPackageManager()
+ .checkPermission(ResolverRankerService.HOLD_PERMISSION,
+ resolveInfo.serviceInfo.packageName)) {
Log.w(TAG, "ResolverRankerService " + componentName + " does not hold"
+ " permission " + ResolverRankerService.HOLD_PERMISSION
+ " - this service will not be queried for "
@@ -386,7 +440,9 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
@Override
void beforeCompute() {
super.beforeCompute();
- mTargetsDict.clear();
+ for (UserHandle userHandle : mTargetsDictPerUser.keySet()) {
+ mTargetsDictPerUser.get(userHandle).clear();
+ }
mTargets = null;
mRankerServiceName = new ComponentName(mContext, this.getClass());
mComparatorModel = buildUpdatedModel();
@@ -468,14 +524,14 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
// so the ResolverComparatorModel may provide inconsistent results. We should make immutable
// copies of the data (waiting for any necessary remaining data before creating the model).
return new ResolverRankerServiceComparatorModel(
- mStats,
- mTargetsDict,
+ mStatsPerUser,
+ mTargetsDictPerUser,
mTargets,
mCollator,
mRanker,
mRankerServiceName,
(mAnnotations != null),
- mPm);
+ mPmMap);
}
/**
@@ -484,35 +540,36 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
* removing the complex legacy API.
*/
static class ResolverRankerServiceComparatorModel implements ResolverComparatorModel {
- private final Map<String, UsageStats> mStats; // Treat as immutable.
- private final Map<ComponentName, ResolverTarget> mTargetsDict; // Treat as immutable.
+ private final Map<UserHandle, Map<String, UsageStats>> mStatsPerUser; // Treat as immutable.
+ // Treat as immutable.
+ private final Map<UserHandle, Map<ComponentName, ResolverTarget>> mTargetsDictPerUser;
private final List<ResolverTarget> mTargets; // Treat as immutable.
private final Collator mCollator;
private final IResolverRankerService mRanker;
private final ComponentName mRankerServiceName;
private final boolean mAnnotationsUsed;
- private final PackageManager mPm;
+ private final Map<UserHandle, PackageManager> mPmMap;
// TODO: it doesn't look like we should have to pass both targets and targetsDict, but it's
// not written in a way that makes it clear whether we can derive one from the other (at
// least in this constructor).
ResolverRankerServiceComparatorModel(
- Map<String, UsageStats> stats,
- Map<ComponentName, ResolverTarget> targetsDict,
+ Map<UserHandle, Map<String, UsageStats>> statsPerUser,
+ Map<UserHandle, Map<ComponentName, ResolverTarget>> targetsDictPerUser,
List<ResolverTarget> targets,
Collator collator,
IResolverRankerService ranker,
ComponentName rankerServiceName,
boolean annotationsUsed,
- PackageManager pm) {
- mStats = stats;
- mTargetsDict = targetsDict;
+ Map<UserHandle, PackageManager> pmMap) {
+ mStatsPerUser = statsPerUser;
+ mTargetsDictPerUser = targetsDictPerUser;
mTargets = targets;
mCollator = collator;
mRanker = ranker;
mRankerServiceName = rankerServiceName;
mAnnotationsUsed = annotationsUsed;
- mPm = pm;
+ mPmMap = pmMap;
}
@Override
@@ -521,25 +578,29 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
// a bug there, or do we have a way of knowing it will be non-null under certain
// conditions?
return (lhs, rhs) -> {
- if (mStats != null) {
- final ResolverTarget lhsTarget = mTargetsDict.get(new ComponentName(
- lhs.activityInfo.packageName, lhs.activityInfo.name));
- final ResolverTarget rhsTarget = mTargetsDict.get(new ComponentName(
- rhs.activityInfo.packageName, rhs.activityInfo.name));
-
- if (lhsTarget != null && rhsTarget != null) {
- final int selectProbabilityDiff = Float.compare(
- rhsTarget.getSelectProbability(), lhsTarget.getSelectProbability());
-
- if (selectProbabilityDiff != 0) {
- return selectProbabilityDiff > 0 ? 1 : -1;
- }
+ final ResolverTarget lhsTarget =
+ getActivityResolverTargetForUser(lhs.activityInfo, lhs.userHandle);
+ final ResolverTarget rhsTarget =
+ getActivityResolverTargetForUser(rhs.activityInfo, rhs.userHandle);
+
+ if (lhsTarget != null && rhsTarget != null) {
+ final int selectProbabilityDiff = Float.compare(
+ rhsTarget.getSelectProbability(), lhsTarget.getSelectProbability());
+
+ if (selectProbabilityDiff != 0) {
+ return selectProbabilityDiff > 0 ? 1 : -1;
}
}
- CharSequence sa = lhs.loadLabel(mPm);
+ CharSequence sa = null;
+ if (mPmMap.containsKey(lhs.userHandle)) {
+ sa = lhs.loadLabel(mPmMap.get(lhs.userHandle));
+ }
if (sa == null) sa = lhs.activityInfo.name;
- CharSequence sb = rhs.loadLabel(mPm);
+ CharSequence sb = null;
+ if (mPmMap.containsKey(rhs.userHandle)) {
+ sb = rhs.loadLabel(mPmMap.get(rhs.userHandle));
+ }
if (sb == null) sb = rhs.activityInfo.name;
return mCollator.compare(sa.toString().trim(), sb.toString().trim());
@@ -547,8 +608,9 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
}
@Override
- public float getScore(ComponentName name) {
- final ResolverTarget target = mTargetsDict.get(name);
+ public float getScore(TargetInfo targetInfo) {
+ ResolverTarget target = getResolverTargetForUserAndComponent(
+ targetInfo.getResolvedComponentName(), targetInfo.getResolveInfo().userHandle);
if (target != null) {
return target.getSelectProbability();
}
@@ -556,13 +618,17 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
}
@Override
- public void notifyOnTargetSelected(ComponentName componentName) {
+ public void notifyOnTargetSelected(TargetInfo targetInfo) {
if (mRanker != null) {
try {
- int selectedPos = new ArrayList<ComponentName>(mTargetsDict.keySet())
- .indexOf(componentName);
+ int selectedPos = -1;
+ if (mTargetsDictPerUser.containsKey(targetInfo.getResolveInfo().userHandle)) {
+ selectedPos = new ArrayList<>(mTargetsDictPerUser
+ .get(targetInfo.getResolveInfo().userHandle).keySet())
+ .indexOf(targetInfo.getResolvedComponentName());
+ }
if (selectedPos >= 0 && mTargets != null) {
- final float selectedProbability = getScore(componentName);
+ final float selectedProbability = getScore(targetInfo);
int order = 0;
for (ResolverTarget target : mTargets) {
if (target.getSelectProbability() > selectedProbability) {
@@ -573,7 +639,8 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
mRanker.train(mTargets, selectedPos);
} else {
if (DEBUG) {
- Log.d(TAG, "Selected a unknown component: " + componentName);
+ Log.d(TAG, "Selected a unknown component: " + targetInfo
+ .getResolvedComponentName());
}
}
} catch (RemoteException e) {
@@ -597,5 +664,21 @@ public class ResolverRankerServiceResolverComparator extends AbstractResolverCom
metricsLogger.write(log);
}
}
+
+ @Nullable
+ private ResolverTarget getActivityResolverTargetForUser(
+ ActivityInfo activity, UserHandle user) {
+ return getResolverTargetForUserAndComponent(
+ new ComponentName(activity.packageName, activity.name), user);
+ }
+
+ @Nullable
+ private ResolverTarget getResolverTargetForUserAndComponent(
+ ComponentName targetComponentName, UserHandle user) {
+ if ((mStatsPerUser == null) || !mTargetsDictPerUser.containsKey(user)) {
+ return null;
+ }
+ return mTargetsDictPerUser.get(user).get(targetComponentName);
+ }
}
}
diff --git a/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt b/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt
index 6f7542f1..3ffbe039 100644
--- a/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt
+++ b/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt
@@ -26,7 +26,6 @@ import android.content.pm.PackageManager
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.content.pm.ShortcutManager.ShareShortcutInfo
-import android.os.AsyncTask
import android.os.UserHandle
import android.os.UserManager
import android.service.chooser.ChooserTarget
@@ -36,126 +35,181 @@ import androidx.annotation.MainThread
import androidx.annotation.OpenForTesting
import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.coroutineScope
import com.android.intentresolver.chooser.DisplayResolveInfo
-import java.lang.RuntimeException
-import java.util.ArrayList
-import java.util.HashMap
+import com.android.intentresolver.measurements.Tracer
+import com.android.intentresolver.measurements.runTracing
import java.util.concurrent.Executor
-import java.util.concurrent.atomic.AtomicReference
import java.util.function.Consumer
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.launch
/**
* Encapsulates shortcuts loading logic from either AppPredictor or ShortcutManager.
*
- *
* A ShortcutLoader instance can be viewed as a per-profile singleton hot stream of shortcut
- * updates. The shortcut loading is triggered by the [queryShortcuts],
- * the processing will happen on the [backgroundExecutor] and the result is delivered
- * through the [callback] on the [callbackExecutor], the main thread.
- *
- *
- * The current version does not improve on the legacy in a way that it does not guarantee that
- * each invocation of the [queryShortcuts] will be matched by an
- * invocation of the callback (there are early terminations of the flow). Also, the fetched
- * shortcuts would be matched against the last known input, i.e. two invocations of
- * [queryShortcuts] may result in two callbacks where shortcuts are
- * processed against the latest input.
- *
+ * updates. The shortcut loading is triggered in the constructor or by the [reset] method, the
+ * processing happens on the [dispatcher] and the result is delivered through the [callback] on the
+ * default [lifecycle]'s dispatcher, the main thread.
*/
@OpenForTesting
-open class ShortcutLoader @VisibleForTesting constructor(
+open class ShortcutLoader
+@VisibleForTesting
+constructor(
private val context: Context,
+ private val lifecycle: Lifecycle,
private val appPredictor: AppPredictorProxy?,
private val userHandle: UserHandle,
private val isPersonalProfile: Boolean,
private val targetIntentFilter: IntentFilter?,
- private val backgroundExecutor: Executor,
- private val callbackExecutor: Executor,
+ private val dispatcher: CoroutineDispatcher,
private val callback: Consumer<Result>
) {
private val shortcutToChooserTargetConverter = ShortcutToChooserTargetConverter()
private val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
- private val activeRequest = AtomicReference(NO_REQUEST)
private val appPredictorCallback = AppPredictor.Callback { onAppPredictorCallback(it) }
- private var isDestroyed = false
+ private val appTargetSource =
+ MutableSharedFlow<Array<DisplayResolveInfo>?>(
+ replay = 1,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
+ private val shortcutSource =
+ MutableSharedFlow<ShortcutData?>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ private val isDestroyed
+ get() = !lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)
@MainThread
constructor(
context: Context,
+ lifecycle: Lifecycle,
appPredictor: AppPredictor?,
userHandle: UserHandle,
targetIntentFilter: IntentFilter?,
callback: Consumer<Result>
) : this(
context,
+ lifecycle,
appPredictor?.let { AppPredictorProxy(it) },
- userHandle, userHandle == UserHandle.of(ActivityManager.getCurrentUser()),
+ userHandle,
+ userHandle == UserHandle.of(ActivityManager.getCurrentUser()),
targetIntentFilter,
- AsyncTask.SERIAL_EXECUTOR,
- context.mainExecutor,
+ Dispatchers.IO,
callback
)
init {
- appPredictor?.registerPredictionUpdates(callbackExecutor, appPredictorCallback)
+ appPredictor?.registerPredictionUpdates(dispatcher.asExecutor(), appPredictorCallback)
+ lifecycle.coroutineScope
+ .launch {
+ appTargetSource
+ .combine(shortcutSource) { appTargets, shortcutData ->
+ if (appTargets == null || shortcutData == null) {
+ null
+ } else {
+ runTracing("filter-shortcuts-${userHandle.identifier}") {
+ filterShortcuts(
+ appTargets,
+ shortcutData.shortcuts,
+ shortcutData.isFromAppPredictor,
+ shortcutData.appPredictorTargets
+ )
+ }
+ }
+ }
+ .filter { it != null }
+ .flowOn(dispatcher)
+ .collect { callback.accept(it ?: error("can not be null")) }
+ }
+ .invokeOnCompletion {
+ runCatching { appPredictor?.unregisterPredictionUpdates(appPredictorCallback) }
+ Log.d(TAG, "destroyed, user: $userHandle")
+ }
+ reset()
}
- /**
- * Unsubscribe from app predictor if one was provided.
- */
- @OpenForTesting
- @MainThread
- open fun destroy() {
- isDestroyed = true
- appPredictor?.unregisterPredictionUpdates(appPredictorCallback)
+ /** Clear application targets (see [updateAppTargets] and initiate shrtcuts loading. */
+ fun reset() {
+ Log.d(TAG, "reset shortcut loader for user $userHandle")
+ appTargetSource.tryEmit(null)
+ shortcutSource.tryEmit(null)
+ lifecycle.coroutineScope.launch(dispatcher) { loadShortcuts() }
}
/**
- * Set new resolved targets. This will trigger shortcut loading.
- * @param appTargets a collection of application targets a loaded set of shortcuts will be
- * grouped against
+ * Update resolved application targets; as soon as shortcuts are loaded, they will be filtered
+ * against the targets and the is delivered to the client through the [callback].
*/
@OpenForTesting
- @MainThread
- open fun queryShortcuts(appTargets: Array<DisplayResolveInfo>) {
- if (isDestroyed) return
- activeRequest.set(Request(appTargets))
- backgroundExecutor.execute { loadShortcuts() }
+ open fun updateAppTargets(appTargets: Array<DisplayResolveInfo>) {
+ appTargetSource.tryEmit(appTargets)
}
@WorkerThread
private fun loadShortcuts() {
// no need to query direct share for work profile when its locked or disabled
- if (!shouldQueryDirectShareTargets()) return
- Log.d(TAG, "querying direct share targets")
+ if (!shouldQueryDirectShareTargets()) {
+ Log.d(TAG, "skip shortcuts loading for user $userHandle")
+ return
+ }
+ Log.d(TAG, "querying direct share targets for user $userHandle")
queryDirectShareTargets(false)
}
@WorkerThread
private fun queryDirectShareTargets(skipAppPredictionService: Boolean) {
if (!skipAppPredictionService && appPredictor != null) {
- appPredictor.requestPredictionUpdate()
- return
+ try {
+ Log.d(TAG, "query AppPredictor for user $userHandle")
+ Tracer.beginAppPredictorQueryTrace(userHandle)
+ appPredictor.requestPredictionUpdate()
+ return
+ } catch (e: Throwable) {
+ endAppPredictorQueryTrace(userHandle)
+ // we might have been destroyed concurrently, nothing left to do
+ if (isDestroyed) {
+ return
+ }
+ Log.e(TAG, "Failed to query AppPredictor for user $userHandle", e)
+ }
}
// Default to just querying ShortcutManager if AppPredictor not present.
- if (targetIntentFilter == null) return
- val shortcuts = queryShortcutManager(targetIntentFilter)
+ if (targetIntentFilter == null) {
+ Log.d(TAG, "skip querying ShortcutManager for $userHandle")
+ return
+ }
+ Log.d(TAG, "query ShortcutManager for user $userHandle")
+ val shortcuts =
+ runTracing("shortcut-mngr-${userHandle.identifier}") {
+ queryShortcutManager(targetIntentFilter)
+ }
+ Log.d(TAG, "receive shortcuts from ShortcutManager for user $userHandle")
sendShareShortcutInfoList(shortcuts, false, null)
}
@WorkerThread
private fun queryShortcutManager(targetIntentFilter: IntentFilter): List<ShareShortcutInfo> {
val selectedProfileContext = context.createContextAsUser(userHandle, 0 /* flags */)
- val sm = selectedProfileContext
- .getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager?
+ val sm =
+ selectedProfileContext.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager?
val pm = context.createContextAsUser(userHandle, 0 /* flags */).packageManager
- return sm?.getShareTargets(targetIntentFilter)
- ?.filter { pm.isPackageEnabled(it.targetComponent.packageName) }
+ return sm?.getShareTargets(targetIntentFilter)?.filter {
+ pm.isPackageEnabled(it.targetComponent.packageName)
+ }
?: emptyList()
}
@WorkerThread
private fun onAppPredictorCallback(appPredictorTargets: List<AppTarget>) {
+ endAppPredictorQueryTrace(userHandle)
+ Log.d(TAG, "receive app targets from AppPredictor")
if (appPredictorTargets.isEmpty() && shouldQueryDirectShareTargets()) {
// APS may be disabled, so try querying targets ourselves.
queryDirectShareTargets(true)
@@ -168,9 +222,7 @@ open class ShortcutLoader @VisibleForTesting constructor(
@WorkerThread
private fun List<AppTarget>.toShortcuts(pm: PackageManager): ShortcutsAppTargetsPair =
- fold(
- ShortcutsAppTargetsPair(ArrayList(size), ArrayList(size))
- ) { acc, appTarget ->
+ fold(ShortcutsAppTargetsPair(ArrayList(size), ArrayList(size))) { acc, appTarget ->
val shortcutInfo = appTarget.shortcutInfo
val packageName = appTarget.packageName
val className = appTarget.className
@@ -189,11 +241,22 @@ open class ShortcutLoader @VisibleForTesting constructor(
isFromAppPredictor: Boolean,
appPredictorTargets: List<AppTarget>?
) {
+ shortcutSource.tryEmit(ShortcutData(shortcuts, isFromAppPredictor, appPredictorTargets))
+ }
+
+ private fun filterShortcuts(
+ appTargets: Array<DisplayResolveInfo>,
+ shortcuts: List<ShareShortcutInfo>,
+ isFromAppPredictor: Boolean,
+ appPredictorTargets: List<AppTarget>?
+ ): Result {
if (appPredictorTargets != null && appPredictorTargets.size != shortcuts.size) {
throw RuntimeException(
- "resultList and appTargets must have the same size."
- + " resultList.size()=" + shortcuts.size
- + " appTargets.size()=" + appPredictorTargets.size
+ "resultList and appTargets must have the same size." +
+ " resultList.size()=" +
+ shortcuts.size +
+ " appTargets.size()=" +
+ appPredictorTargets.size
)
}
val directShareAppTargetCache = HashMap<ChooserTarget, AppTarget>()
@@ -201,77 +264,65 @@ open class ShortcutLoader @VisibleForTesting constructor(
// Match ShareShortcutInfos with DisplayResolveInfos to be able to use the old code path
// for direct share targets. After ShareSheet is refactored we should use the
// ShareShortcutInfos directly.
- val appTargets = activeRequest.get().appTargets
val resultRecords: MutableList<ShortcutResultInfo> = ArrayList()
for (displayResolveInfo in appTargets) {
- val matchingShortcuts = shortcuts.filter {
- it.targetComponent == displayResolveInfo.resolvedComponentName
- }
+ val matchingShortcuts =
+ shortcuts.filter { it.targetComponent == displayResolveInfo.resolvedComponentName }
if (matchingShortcuts.isEmpty()) continue
- val chooserTargets = shortcutToChooserTargetConverter.convertToChooserTarget(
- matchingShortcuts,
- shortcuts,
- appPredictorTargets,
- directShareAppTargetCache,
- directShareShortcutInfoCache
- )
+ val chooserTargets =
+ shortcutToChooserTargetConverter.convertToChooserTarget(
+ matchingShortcuts,
+ shortcuts,
+ appPredictorTargets,
+ directShareAppTargetCache,
+ directShareShortcutInfoCache
+ )
val resultRecord = ShortcutResultInfo(displayResolveInfo, chooserTargets)
resultRecords.add(resultRecord)
}
- postReport(
- Result(
- isFromAppPredictor,
- appTargets,
- resultRecords.toTypedArray(),
- directShareAppTargetCache,
- directShareShortcutInfoCache
- )
+ return Result(
+ isFromAppPredictor,
+ appTargets,
+ resultRecords.toTypedArray(),
+ directShareAppTargetCache,
+ directShareShortcutInfoCache
)
}
- private fun postReport(result: Result) = callbackExecutor.execute { report(result) }
-
- @MainThread
- private fun report(result: Result) {
- if (isDestroyed) return
- callback.accept(result)
- }
-
/**
- * Returns `false` if `userHandle` is the work profile and it's either
- * in quiet mode or not running.
+ * Returns `false` if `userHandle` is the work profile and it's either in quiet mode or not
+ * running.
*/
private fun shouldQueryDirectShareTargets(): Boolean = isPersonalProfile || isProfileActive
@get:VisibleForTesting
protected val isProfileActive: Boolean
- get() = userManager.isUserRunning(userHandle)
- && userManager.isUserUnlocked(userHandle)
- && !userManager.isQuietModeEnabled(userHandle)
+ get() =
+ userManager.isUserRunning(userHandle) &&
+ userManager.isUserUnlocked(userHandle) &&
+ !userManager.isQuietModeEnabled(userHandle)
- private class Request(val appTargets: Array<DisplayResolveInfo>)
+ private class ShortcutData(
+ val shortcuts: List<ShareShortcutInfo>,
+ val isFromAppPredictor: Boolean,
+ val appPredictorTargets: List<AppTarget>?
+ )
- /**
- * Resolved shortcuts with corresponding app targets.
- */
+ /** Resolved shortcuts with corresponding app targets. */
class Result(
val isFromAppPredictor: Boolean,
/**
- * Input app targets (see [ShortcutLoader.queryShortcuts] the
- * shortcuts were process against.
+ * Input app targets (see [ShortcutLoader.updateAppTargets] the shortcuts were process
+ * against.
*/
val appTargets: Array<DisplayResolveInfo>,
- /**
- * Shortcuts grouped by app target.
- */
+ /** Shortcuts grouped by app target. */
val shortcutsByApp: Array<ShortcutResultInfo>,
val directShareAppTargetCache: Map<ChooserTarget, AppTarget>,
val directShareShortcutInfoCache: Map<ChooserTarget, ShortcutInfo>
)
- /**
- * Shortcuts grouped by app.
- */
+ /** Shortcuts grouped by app. */
class ShortcutResultInfo(
val appTarget: DisplayResolveInfo,
val shortcuts: List<ChooserTarget?>
@@ -282,45 +333,46 @@ open class ShortcutLoader @VisibleForTesting constructor(
val appTargets: List<AppTarget>?
)
- /**
- * A wrapper around AppPredictor to facilitate unit-testing.
- */
+ /** A wrapper around AppPredictor to facilitate unit-testing. */
@VisibleForTesting
open class AppPredictorProxy internal constructor(private val mAppPredictor: AppPredictor) {
- /**
- * [AppPredictor.registerPredictionUpdates]
- */
+ /** [AppPredictor.registerPredictionUpdates] */
open fun registerPredictionUpdates(
- callbackExecutor: Executor, callback: AppPredictor.Callback
+ callbackExecutor: Executor,
+ callback: AppPredictor.Callback
) = mAppPredictor.registerPredictionUpdates(callbackExecutor, callback)
- /**
- * [AppPredictor.unregisterPredictionUpdates]
- */
+ /** [AppPredictor.unregisterPredictionUpdates] */
open fun unregisterPredictionUpdates(callback: AppPredictor.Callback) =
mAppPredictor.unregisterPredictionUpdates(callback)
- /**
- * [AppPredictor.requestPredictionUpdate]
- */
+ /** [AppPredictor.requestPredictionUpdate] */
open fun requestPredictionUpdate() = mAppPredictor.requestPredictionUpdate()
}
companion object {
private const val TAG = "ShortcutLoader"
- private val NO_REQUEST = Request(arrayOf())
private fun PackageManager.isPackageEnabled(packageName: String): Boolean {
if (TextUtils.isEmpty(packageName)) {
return false
}
return runCatching {
- val appInfo = getApplicationInfo(
- packageName,
- PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())
- )
- appInfo.enabled && (appInfo.flags and ApplicationInfo.FLAG_SUSPENDED) == 0
- }.getOrDefault(false)
+ val appInfo =
+ getApplicationInfo(
+ packageName,
+ PackageManager.ApplicationInfoFlags.of(
+ PackageManager.GET_META_DATA.toLong()
+ )
+ )
+ appInfo.enabled && (appInfo.flags and ApplicationInfo.FLAG_SUSPENDED) == 0
+ }
+ .getOrDefault(false)
+ }
+
+ private fun endAppPredictorQueryTrace(userHandle: UserHandle) {
+ val duration = Tracer.endAppPredictorQueryTrace(userHandle)
+ Log.d(TAG, "AppPredictor query duration for user $userHandle: $duration ms")
}
}
}
diff --git a/java/src/com/android/intentresolver/util/Flow.kt b/java/src/com/android/intentresolver/util/Flow.kt
new file mode 100644
index 00000000..1155b9fe
--- /dev/null
+++ b/java/src/com/android/intentresolver/util/Flow.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.util
+
+import android.os.SystemClock
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.channelFlow
+import kotlinx.coroutines.launch
+
+/**
+ * Returns a flow that mirrors the original flow, but delays values following emitted values for the
+ * given [periodMs]. If the original flow emits more than one value during this period, only the
+ * latest value is emitted.
+ *
+ * Example:
+ *
+ * ```kotlin
+ * flow {
+ * emit(1) // t=0ms
+ * delay(90)
+ * emit(2) // t=90ms
+ * delay(90)
+ * emit(3) // t=180ms
+ * delay(1010)
+ * emit(4) // t=1190ms
+ * delay(1010)
+ * emit(5) // t=2200ms
+ * }.throttle(1000)
+ * ```
+ *
+ * produces the following emissions at the following times
+ *
+ * ```text
+ * 1 (t=0ms), 3 (t=1000ms), 4 (t=2000ms), 5 (t=3000ms)
+ * ```
+ */
+// A SystemUI com.android.systemui.util.kotlin.throttle copy.
+fun <T> Flow<T>.throttle(periodMs: Long): Flow<T> = channelFlow {
+ coroutineScope {
+ var previousEmitTimeMs = 0L
+ var delayJob: Job? = null
+ var sendJob: Job? = null
+ val outerScope = this
+
+ collect {
+ delayJob?.cancel()
+ sendJob?.join()
+ val currentTimeMs = SystemClock.elapsedRealtime()
+ val timeSinceLastEmit = currentTimeMs - previousEmitTimeMs
+ val timeUntilNextEmit = maxOf(0L, periodMs - timeSinceLastEmit)
+ if (timeUntilNextEmit > 0L) {
+ // We create delayJob to allow cancellation during the delay period
+ delayJob = launch {
+ delay(timeUntilNextEmit)
+ sendJob = outerScope.launch(start = CoroutineStart.UNDISPATCHED) {
+ send(it)
+ previousEmitTimeMs = SystemClock.elapsedRealtime()
+ }
+ }
+ } else {
+ send(it)
+ previousEmitTimeMs = currentTimeMs
+ }
+ }
+ }
+}
diff --git a/java/src/com/android/intentresolver/util/UriFilters.kt b/java/src/com/android/intentresolver/util/UriFilters.kt
new file mode 100644
index 00000000..a4c6e574
--- /dev/null
+++ b/java/src/com/android/intentresolver/util/UriFilters.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@file:JvmName("UriFilters")
+
+package com.android.intentresolver.util
+
+import android.content.ContentProvider.getUserIdFromUri
+import android.content.ContentResolver.SCHEME_CONTENT
+import android.graphics.drawable.Icon
+import android.graphics.drawable.Icon.TYPE_URI
+import android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP
+import android.net.Uri
+import android.os.UserHandle
+import android.service.chooser.ChooserAction
+
+/**
+ * Checks if the [Uri] is a `content://` uri which references the current user (from process uid).
+ *
+ * MediaStore interprets the user field of a content:// URI as a UserId and applies it if the caller
+ * holds INTERACT_ACROSS_USERS permission. (Example: `content://10@media/images/1234`)
+ *
+ * No URI content should be loaded unless it passes this check since the caller would not have
+ * permission to read it.
+ *
+ * @return false if this is a content:// [Uri] which references another user
+ */
+val Uri?.ownedByCurrentUser: Boolean
+ @JvmName("isOwnedByCurrentUser")
+ get() =
+ this?.let {
+ when (getUserIdFromUri(this, UserHandle.USER_CURRENT)) {
+ UserHandle.USER_CURRENT,
+ UserHandle.myUserId() -> true
+ else -> false
+ }
+ } == true
+
+/** Does the [Uri] reference a content provider ('content://')? */
+internal val Uri.contentScheme: Boolean
+ get() = scheme == SCHEME_CONTENT
+
+/**
+ * Checks if the Icon of a [ChooserAction] backed by content:// [Uri] is safe for display.
+ *
+ * @param action the chooser action
+ * @see [Uri.ownedByCurrentUser]
+ */
+fun hasValidIcon(action: ChooserAction) = hasValidIcon(action.icon)
+
+/**
+ * Checks if the Icon backed by content:// [Uri] is safe for display.
+ *
+ * @see [Uri.ownedByCurrentUser]
+ */
+fun hasValidIcon(icon: Icon) =
+ with(icon) {
+ when (type) {
+ TYPE_URI,
+ TYPE_URI_ADAPTIVE_BITMAP -> !uri.contentScheme || uri.ownedByCurrentUser
+ else -> true
+ }
+ }
diff --git a/java/src/com/android/intentresolver/widget/ChooserActionRow.kt b/java/src/com/android/intentresolver/widget/ChooserActionRow.kt
deleted file mode 100644
index a4656bb5..00000000
--- a/java/src/com/android/intentresolver/widget/ChooserActionRow.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.intentresolver.widget
-
-import android.annotation.LayoutRes
-import android.content.Context
-import android.os.Parcelable
-import android.util.AttributeSet
-import android.view.LayoutInflater
-import android.widget.Button
-import android.widget.LinearLayout
-import com.android.intentresolver.R
-import com.android.intentresolver.widget.ActionRow.Action
-
-class ChooserActionRow : LinearLayout, ActionRow {
- constructor(context: Context) : this(context, null)
- constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
- constructor(
- context: Context, attrs: AttributeSet?, defStyleAttr: Int
- ) : this(context, attrs, defStyleAttr, 0)
-
- constructor(
- context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int
- ) : super(context, attrs, defStyleAttr, defStyleRes) {
- orientation = HORIZONTAL
- }
-
- @LayoutRes
- private val itemLayout = R.layout.chooser_action_button
- private val itemMargin =
- context.resources.getDimensionPixelSize(R.dimen.resolver_icon_margin) / 2
- private var actions: List<Action> = emptyList()
-
- override fun onRestoreInstanceState(state: Parcelable?) {
- super.onRestoreInstanceState(state)
- setActions(actions)
- }
-
- override fun setActions(actions: List<Action>) {
- removeAllViews()
- this.actions = ArrayList(actions)
- for (action in actions) {
- addAction(action)
- }
- }
-
- private fun addAction(action: Action) {
- val b = LayoutInflater.from(context).inflate(itemLayout, null) as Button
- if (action.icon != null) {
- val size = resources
- .getDimensionPixelSize(R.dimen.chooser_action_button_icon_size)
- action.icon.setBounds(0, 0, size, size)
- b.setCompoundDrawablesRelative(action.icon, null, null, null)
- }
- b.text = action.label ?: ""
- b.setOnClickListener {
- action.onClicked.run()
- }
- b.id = action.id
- addView(b)
- }
-
- override fun generateDefaultLayoutParams(): LayoutParams =
- super.generateDefaultLayoutParams().apply {
- setMarginsRelative(itemMargin, 0, itemMargin, 0)
- }
-}
diff --git a/java/src/com/android/intentresolver/widget/ChooserImagePreviewView.kt b/java/src/com/android/intentresolver/widget/ChooserImagePreviewView.kt
deleted file mode 100644
index ca94a95d..00000000
--- a/java/src/com/android/intentresolver/widget/ChooserImagePreviewView.kt
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.intentresolver.widget
-
-import android.animation.ObjectAnimator
-import android.content.Context
-import android.net.Uri
-import android.util.AttributeSet
-import android.view.LayoutInflater
-import android.view.animation.DecelerateInterpolator
-import android.widget.RelativeLayout
-import androidx.core.view.isVisible
-import com.android.intentresolver.R
-import com.android.intentresolver.widget.ImagePreviewView.TransitionElementStatusCallback
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.MainScope
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.launch
-import com.android.internal.R as IntR
-
-private const val IMAGE_FADE_IN_MILLIS = 150L
-
-class ChooserImagePreviewView : RelativeLayout, ImagePreviewView {
-
- constructor(context: Context) : this(context, null)
- constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
-
- constructor(
- context: Context, attrs: AttributeSet?, defStyleAttr: Int
- ) : this(context, attrs, defStyleAttr, 0)
-
- constructor(
- context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int
- ) : super(context, attrs, defStyleAttr, defStyleRes)
-
- private val coroutineScope = MainScope()
- private lateinit var mainImage: RoundedRectImageView
- private lateinit var secondLargeImage: RoundedRectImageView
- private lateinit var secondSmallImage: RoundedRectImageView
- private lateinit var thirdImage: RoundedRectImageView
-
- private var loadImageJob: Job? = null
- private var transitionStatusElementCallback: TransitionElementStatusCallback? = null
-
- override fun onFinishInflate() {
- LayoutInflater.from(context)
- .inflate(R.layout.chooser_image_preview_view_internals, this, true)
- mainImage = requireViewById(IntR.id.content_preview_image_1_large)
- secondLargeImage = requireViewById(IntR.id.content_preview_image_2_large)
- secondSmallImage = requireViewById(IntR.id.content_preview_image_2_small)
- thirdImage = requireViewById(IntR.id.content_preview_image_3_small)
- }
-
- /**
- * Specifies a transition animation target readiness callback. The callback will be
- * invoked once when views preparation is done.
- * Should be called before [setImages].
- */
- override fun setTransitionElementStatusCallback(callback: TransitionElementStatusCallback?) {
- transitionStatusElementCallback = callback
- }
-
- override fun setImages(uris: List<Uri>, imageLoader: ImageLoader) {
- loadImageJob?.cancel()
- loadImageJob = coroutineScope.launch {
- when (uris.size) {
- 0 -> hideAllViews()
- 1 -> showOneImage(uris, imageLoader)
- 2 -> showTwoImages(uris, imageLoader)
- else -> showThreeImages(uris, imageLoader)
- }
- }
- }
-
- private fun hideAllViews() {
- mainImage.isVisible = false
- secondLargeImage.isVisible = false
- secondSmallImage.isVisible = false
- thirdImage.isVisible = false
- invokeTransitionViewReadyCallback()
- }
-
- private suspend fun showOneImage(uris: List<Uri>, imageLoader: ImageLoader) {
- secondLargeImage.isVisible = false
- secondSmallImage.isVisible = false
- thirdImage.isVisible = false
- showImages(uris, imageLoader, mainImage)
- }
-
- private suspend fun showTwoImages(uris: List<Uri>, imageLoader: ImageLoader) {
- secondSmallImage.isVisible = false
- thirdImage.isVisible = false
- showImages(uris, imageLoader, mainImage, secondLargeImage)
- }
-
- private suspend fun showThreeImages(uris: List<Uri>, imageLoader: ImageLoader) {
- secondLargeImage.isVisible = false
- showImages(uris, imageLoader, mainImage, secondSmallImage, thirdImage)
- thirdImage.setExtraImageCount(uris.size - 3)
- }
-
- private suspend fun showImages(
- uris: List<Uri>, imageLoader: ImageLoader, vararg views: RoundedRectImageView
- ) = coroutineScope {
- for (i in views.indices) {
- launch {
- loadImageIntoView(views[i], uris[i], imageLoader)
- }
- }
- }
-
- private suspend fun loadImageIntoView(
- view: RoundedRectImageView, uri: Uri, imageLoader: ImageLoader
- ) {
- val bitmap = runCatching {
- imageLoader(uri)
- }.getOrDefault(null)
- if (bitmap == null) {
- view.isVisible = false
- if (view === mainImage) {
- invokeTransitionViewReadyCallback()
- }
- } else {
- view.isVisible = true
- view.setImageBitmap(bitmap)
-
- view.alpha = 0f
- ObjectAnimator.ofFloat(view, "alpha", 0.0f, 1.0f).apply {
- interpolator = DecelerateInterpolator(1.0f)
- duration = IMAGE_FADE_IN_MILLIS
- start()
- }
- if (view === mainImage && transitionStatusElementCallback != null) {
- view.waitForPreDraw()
- invokeTransitionViewReadyCallback()
- }
- }
- }
-
- private fun invokeTransitionViewReadyCallback() {
- transitionStatusElementCallback?.apply {
- if (mainImage.isVisible && mainImage.drawable != null) {
- mainImage.transitionName?.let { onTransitionElementReady(it) }
- }
- onAllTransitionElementsReady()
- }
- transitionStatusElementCallback = null
- }
-}
diff --git a/java/src/com/android/intentresolver/widget/ImagePreviewView.kt b/java/src/com/android/intentresolver/widget/ImagePreviewView.kt
index a166ef27..3f0458ee 100644
--- a/java/src/com/android/intentresolver/widget/ImagePreviewView.kt
+++ b/java/src/com/android/intentresolver/widget/ImagePreviewView.kt
@@ -16,14 +16,11 @@
package com.android.intentresolver.widget
-import android.graphics.Bitmap
-import android.net.Uri
-
-internal typealias ImageLoader = suspend (Uri) -> Bitmap?
+import android.view.View
interface ImagePreviewView {
fun setTransitionElementStatusCallback(callback: TransitionElementStatusCallback?)
- fun setImages(uris: List<Uri>, imageLoader: ImageLoader)
+ fun getTransitionView(): View?
/**
* [ImagePreviewView] progressively prepares views for shared element transition and reports
diff --git a/java/src/com/android/intentresolver/widget/ResolverDrawerLayout.java b/java/src/com/android/intentresolver/widget/ResolverDrawerLayout.java
index f5e20510..de76a1d2 100644
--- a/java/src/com/android/intentresolver/widget/ResolverDrawerLayout.java
+++ b/java/src/com/android/intentresolver/widget/ResolverDrawerLayout.java
@@ -841,7 +841,14 @@ public class ResolverDrawerLayout extends ViewGroup {
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
- if (!consumed && Math.abs(velocityY) > mMinFlingVelocity) {
+ // TODO: find a more suitable way to fix it.
+ // RecyclerView started reporting `consumed` as true whenever a scrolling is enabled,
+ // previously the value was based whether the fling can be performed in given direction
+ // i.e. whether it is at the top or at the bottom. isRecyclerViewAtTheTop method is a
+ // workaround that restores the legacy functionality.
+ boolean shouldConsume = (Math.abs(velocityY) > mMinFlingVelocity)
+ && (!consumed || (velocityY < 0 && isRecyclerViewAtTheTop(target)));
+ if (shouldConsume) {
if (getShowAtTop()) {
if (isDismissable() && velocityY > 0) {
abortAnimation();
@@ -863,6 +870,21 @@ public class ResolverDrawerLayout extends ViewGroup {
return false;
}
+ private static boolean isRecyclerViewAtTheTop(View target) {
+ // TODO: there's a very similar functionality in #isNestedRecyclerChildScrolled(),
+ // consolidate the two.
+ if (!(target instanceof RecyclerView)) {
+ return false;
+ }
+ RecyclerView recyclerView = (RecyclerView) target;
+ if (recyclerView.getChildCount() == 0) {
+ return true;
+ }
+ View firstChild = recyclerView.getChildAt(0);
+ return recyclerView.getChildAdapterPosition(firstChild) == 0
+ && firstChild.getTop() >= recyclerView.getPaddingTop();
+ }
+
private boolean performAccessibilityActionCommon(int action) {
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
diff --git a/java/src/com/android/intentresolver/widget/RoundedRectImageView.java b/java/src/com/android/intentresolver/widget/RoundedRectImageView.java
index 8538041b..8ca6ed14 100644
--- a/java/src/com/android/intentresolver/widget/RoundedRectImageView.java
+++ b/java/src/com/android/intentresolver/widget/RoundedRectImageView.java
@@ -17,6 +17,7 @@
package com.android.intentresolver.widget;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -52,7 +53,17 @@ public class RoundedRectImageView extends ImageView {
public RoundedRectImageView(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mRadius = context.getResources().getDimensionPixelSize(R.dimen.chooser_corner_radius);
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs,
+ R.styleable.RoundedRectImageView,
+ defStyleAttr,
+ 0);
+ mRadius = a.getDimensionPixelSize(R.styleable.RoundedRectImageView_radius, -1);
+ if (mRadius < 0) {
+ mRadius = context.getResources().getDimensionPixelSize(R.dimen.chooser_corner_radius);
+ }
+ a.recycle();
mOverlayPaint.setColor(0x99000000);
mOverlayPaint.setStyle(Paint.Style.FILL);
diff --git a/java/src/com/android/intentresolver/widget/ScrollableActionRow.kt b/java/src/com/android/intentresolver/widget/ScrollableActionRow.kt
index f2a8b9e8..2b64ca30 100644
--- a/java/src/com/android/intentresolver/widget/ScrollableActionRow.kt
+++ b/java/src/com/android/intentresolver/widget/ScrollableActionRow.kt
@@ -17,12 +17,14 @@
package com.android.intentresolver.widget
import android.content.Context
+import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
+import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.intentresolver.R
@@ -31,13 +33,23 @@ class ScrollableActionRow : RecyclerView, ActionRow {
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(
- context: Context, attrs: AttributeSet?, defStyleAttr: Int
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
) : super(context, attrs, defStyleAttr) {
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
adapter = Adapter(context)
+
+ addItemDecoration(
+ MarginDecoration(
+ context.resources.getDimensionPixelSize(R.dimen.chooser_action_horizontal_margin),
+ context.resources.getDimensionPixelSize(R.dimen.chooser_edge_margin_normal)
+ )
+ )
}
- private val actionsAdapter get() = adapter as Adapter
+ private val actionsAdapter
+ get() = adapter as Adapter
override fun setActions(actions: List<ActionRow.Action>) {
actionsAdapter.setActions(actions)
@@ -50,7 +62,7 @@ class ScrollableActionRow : RecyclerView, ActionRow {
)
}
- private class Adapter(private val context: Context) : RecyclerView.Adapter<ViewHolder>() {
+ private inner class Adapter(private val context: Context) : RecyclerView.Adapter<ViewHolder>() {
private val iconSize: Int =
context.resources.getDimensionPixelSize(R.dimen.chooser_action_view_icon_size)
private val itemLayout = R.layout.chooser_action_view
@@ -59,7 +71,7 @@ class ScrollableActionRow : RecyclerView, ActionRow {
override fun onCreateViewHolder(parent: ViewGroup, type: Int): ViewHolder =
ViewHolder(
LayoutInflater.from(context).inflate(itemLayout, null) as TextView,
- iconSize
+ iconSize,
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@@ -83,8 +95,9 @@ class ScrollableActionRow : RecyclerView, ActionRow {
}
}
- private class ViewHolder(
- private val view: TextView, private val iconSize: Int
+ private inner class ViewHolder(
+ private val view: TextView,
+ private val iconSize: Int,
) : RecyclerView.ViewHolder(view) {
fun bind(action: ActionRow.Action) {
@@ -93,12 +106,10 @@ class ScrollableActionRow : RecyclerView, ActionRow {
// some drawables (edit) does not gets tinted when set to the top of the text
// with TextView#setCompoundDrawableRelative
tintIcon(icon, view)
- view.setCompoundDrawablesRelative(null, icon, null, null)
+ view.setCompoundDrawablesRelative(icon, null, null, null)
}
view.text = action.label ?: ""
- view.setOnClickListener {
- action.onClicked.run()
- }
+ view.setOnClickListener { action.onClicked.run() }
view.id = action.id
}
@@ -113,4 +124,21 @@ class ScrollableActionRow : RecyclerView, ActionRow {
view.compoundDrawableTintBlendMode?.let { drawable.setTintBlendMode(it) }
}
}
+
+ private class MarginDecoration(private val innerMargin: Int, private val outerMargin: Int) :
+ ItemDecoration() {
+ override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: State) {
+ val index = parent.getChildAdapterPosition(view)
+ val startMargin = if (index == 0) outerMargin else innerMargin
+ val endMargin = if (index == state.itemCount - 1) outerMargin else innerMargin
+
+ if (ViewCompat.getLayoutDirection(parent) == ViewCompat.LAYOUT_DIRECTION_RTL) {
+ outRect.right = startMargin
+ outRect.left = endMargin
+ } else {
+ outRect.left = startMargin
+ outRect.right = endMargin
+ }
+ }
+ }
}
diff --git a/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt b/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt
index 467c404a..583a2887 100644
--- a/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt
+++ b/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt
@@ -17,43 +17,126 @@
package com.android.intentresolver.widget
import android.content.Context
+import android.graphics.Bitmap
import android.graphics.Rect
import android.net.Uri
import android.util.AttributeSet
+import android.util.PluralsMessageFormatter
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.VisibleForTesting
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.intentresolver.R
+import com.android.intentresolver.util.throttle
import com.android.intentresolver.widget.ImagePreviewView.TransitionElementStatusCallback
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
-import kotlinx.coroutines.isActive
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.onCompletion
+import kotlinx.coroutines.flow.takeWhile
+import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
private const val TRANSITION_NAME = "screenshot_preview_image"
+private const val PLURALS_COUNT = "count"
+private const val ADAPTER_UPDATE_INTERVAL_MS = 150L
+private const val MIN_ASPECT_RATIO = 0.4f
+private const val MIN_ASPECT_RATIO_STRING = "2:5"
+private const val MAX_ASPECT_RATIO = 2.5f
+private const val MAX_ASPECT_RATIO_STRING = "5:2"
+
+private typealias CachingImageLoader = suspend (Uri, Boolean) -> Bitmap?
class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(
- context: Context, attrs: AttributeSet?, defStyleAttr: Int
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
) : super(context, attrs, defStyleAttr) {
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
adapter = Adapter(context)
- val spacing = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, 5f, context.resources.displayMetrics
- ).toInt()
- addItemDecoration(SpacingDecoration(spacing))
+
+ context
+ .obtainStyledAttributes(attrs, R.styleable.ScrollableImagePreviewView, defStyleAttr, 0)
+ .use { a ->
+ var innerSpacing =
+ a.getDimensionPixelSize(
+ R.styleable.ScrollableImagePreviewView_itemInnerSpacing,
+ -1
+ )
+ if (innerSpacing < 0) {
+ innerSpacing =
+ TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ 3f,
+ context.resources.displayMetrics
+ )
+ .toInt()
+ }
+ outerSpacing =
+ a.getDimensionPixelSize(
+ R.styleable.ScrollableImagePreviewView_itemOuterSpacing,
+ -1
+ )
+ if (outerSpacing < 0) {
+ outerSpacing =
+ TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ 16f,
+ context.resources.displayMetrics
+ )
+ .toInt()
+ }
+ addItemDecoration(SpacingDecoration(innerSpacing, outerSpacing))
+
+ maxWidthHint =
+ a.getDimensionPixelSize(R.styleable.ScrollableImagePreviewView_maxWidthHint, -1)
+ }
}
- private val previewAdapter get() = adapter as Adapter
+ private var batchLoader: BatchPreviewLoader? = null
+ private val previewAdapter
+ get() = adapter as Adapter
+
+ /**
+ * A hint about the maximum width this view can grow to, this helps to optimize preview loading.
+ */
+ var maxWidthHint: Int = -1
+ private var requestedHeight: Int = 0
+ private var isMeasured = false
+ private var maxAspectRatio = MAX_ASPECT_RATIO
+ private var maxAspectRatioString = MAX_ASPECT_RATIO_STRING
+ private var outerSpacing: Int = 0
+
+ override fun onMeasure(widthSpec: Int, heightSpec: Int) {
+ super.onMeasure(widthSpec, heightSpec)
+ if (!isMeasured) {
+ isMeasured = true
+ updateMaxWidthHint(widthSpec)
+ updateMaxAspectRatio()
+ batchLoader?.loadAspectRatios(getMaxWidth(), this::updatePreviewSize)
+ }
+ }
+
+ private fun updateMaxWidthHint(widthSpec: Int) {
+ if (maxWidthHint > 0) return
+ if (View.MeasureSpec.getMode(widthSpec) != View.MeasureSpec.UNSPECIFIED) {
+ maxWidthHint = View.MeasureSpec.getSize(widthSpec)
+ }
+ }
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
@@ -66,41 +149,200 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
previewAdapter.transitionStatusElementCallback = callback
}
- override fun setImages(uris: List<Uri>, imageLoader: ImageLoader) {
- previewAdapter.setImages(uris, imageLoader)
+ override fun getTransitionView(): View? {
+ for (i in 0 until childCount) {
+ val child = getChildAt(i)
+ val vh = getChildViewHolder(child)
+ if (vh is PreviewViewHolder && vh.image.transitionName != null) return child
+ }
+ return null
+ }
+
+ fun setPreviews(previews: List<Preview>, otherItemCount: Int, imageLoader: CachingImageLoader) {
+ previewAdapter.reset(0, imageLoader)
+ batchLoader?.cancel()
+ batchLoader =
+ BatchPreviewLoader(
+ imageLoader,
+ previews,
+ otherItemCount,
+ onReset = { totalItemCount ->
+ previewAdapter.reset(totalItemCount, imageLoader)
+ },
+ onUpdate = previewAdapter::addPreviews,
+ onCompletion = {
+ if (!previewAdapter.hasPreviews) {
+ onNoPreviewCallback?.run()
+ }
+ }
+ )
+ .apply {
+ if (isMeasured) {
+ loadAspectRatios(
+ getMaxWidth(),
+ this@ScrollableImagePreviewView::updatePreviewSize
+ )
+ }
+ }
+ }
+
+ var onNoPreviewCallback: Runnable? = null
+
+ private fun getMaxWidth(): Int =
+ when {
+ maxWidthHint > 0 -> maxWidthHint
+ isLaidOut -> width
+ else -> measuredWidth
+ }
+
+ private fun updateMaxAspectRatio() {
+ val padding = outerSpacing * 2
+ val w = maxOf(padding, getMaxWidth() - padding)
+ val h = if (isLaidOut) height else measuredHeight
+ if (w > 0 && h > 0) {
+ maxAspectRatio =
+ (w.toFloat() / h.toFloat()).coerceIn(MIN_ASPECT_RATIO, MAX_ASPECT_RATIO)
+ maxAspectRatioString =
+ when {
+ maxAspectRatio <= MIN_ASPECT_RATIO -> MIN_ASPECT_RATIO_STRING
+ maxAspectRatio >= MAX_ASPECT_RATIO -> MAX_ASPECT_RATIO_STRING
+ else -> "$w:$h"
+ }
+ }
+ }
+
+ /**
+ * Sets [preview]'s aspect ratio based on the preview image size.
+ *
+ * @return adjusted preview width
+ */
+ private fun updatePreviewSize(preview: Preview, width: Int, height: Int): Int {
+ val effectiveHeight = if (isLaidOut) height else measuredHeight
+ return if (width <= 0 || height <= 0) {
+ preview.aspectRatioString = "1:1"
+ effectiveHeight
+ } else {
+ val aspectRatio =
+ (width.toFloat() / height.toFloat()).coerceIn(MIN_ASPECT_RATIO, maxAspectRatio)
+ preview.aspectRatioString =
+ when {
+ aspectRatio <= MIN_ASPECT_RATIO -> MIN_ASPECT_RATIO_STRING
+ aspectRatio >= maxAspectRatio -> maxAspectRatioString
+ else -> "$width:$height"
+ }
+ (effectiveHeight * aspectRatio).toInt()
+ }
+ }
+
+ class Preview
+ internal constructor(
+ val type: PreviewType,
+ val uri: Uri,
+ val editAction: Runnable?,
+ internal var aspectRatioString: String
+ ) {
+ constructor(
+ type: PreviewType,
+ uri: Uri,
+ editAction: Runnable?
+ ) : this(type, uri, editAction, "1:1")
+ }
+
+ enum class PreviewType {
+ Image,
+ Video,
+ File
}
private class Adapter(private val context: Context) : RecyclerView.Adapter<ViewHolder>() {
- private val uris = ArrayList<Uri>()
- private var imageLoader: ImageLoader? = null
+ private val previews = ArrayList<Preview>()
+ private val imagePreviewDescription =
+ context.resources.getString(R.string.image_preview_a11y_description)
+ private val videoPreviewDescription =
+ context.resources.getString(R.string.video_preview_a11y_description)
+ private val filePreviewDescription =
+ context.resources.getString(R.string.file_preview_a11y_description)
+ private var imageLoader: CachingImageLoader? = null
+ private var firstImagePos = -1
+ private var totalItemCount: Int = 0
+
+ private val hasOtherItem
+ get() = previews.size < totalItemCount
+ val hasPreviews: Boolean
+ get() = previews.isNotEmpty()
+
var transitionStatusElementCallback: TransitionElementStatusCallback? = null
- fun setImages(uris: List<Uri>, imageLoader: ImageLoader) {
- this.uris.clear()
- this.uris.addAll(uris)
+ fun reset(totalItemCount: Int, imageLoader: CachingImageLoader) {
this.imageLoader = imageLoader
+ firstImagePos = -1
+ previews.clear()
+ this.totalItemCount = maxOf(0, totalItemCount)
notifyDataSetChanged()
}
+ fun addPreviews(newPreviews: Collection<Preview>) {
+ if (newPreviews.isEmpty()) return
+ val insertPos = previews.size
+ val hadOtherItem = hasOtherItem
+ previews.addAll(newPreviews)
+ if (firstImagePos < 0) {
+ val pos = newPreviews.indexOfFirst { it.type == PreviewType.Image }
+ if (pos >= 0) firstImagePos = insertPos + pos
+ }
+ notifyItemRangeInserted(insertPos, newPreviews.size)
+ when {
+ hadOtherItem && previews.size >= totalItemCount -> {
+ notifyItemRemoved(previews.size)
+ }
+ !hadOtherItem && previews.size < totalItemCount -> {
+ notifyItemInserted(previews.size)
+ }
+ }
+ }
+
override fun onCreateViewHolder(parent: ViewGroup, itemType: Int): ViewHolder {
- return ViewHolder(
- LayoutInflater.from(context)
- .inflate(R.layout.image_preview_image_item, parent, false)
- )
+ val view = LayoutInflater.from(context).inflate(itemType, parent, false)
+ return if (itemType == R.layout.image_preview_other_item) {
+ OtherItemViewHolder(view)
+ } else {
+ PreviewViewHolder(
+ view,
+ imagePreviewDescription,
+ videoPreviewDescription,
+ filePreviewDescription,
+ )
+ }
}
- override fun getItemCount(): Int = uris.size
+ override fun getItemCount(): Int = previews.size + if (hasOtherItem) 1 else 0
+
+ override fun getItemViewType(position: Int): Int {
+ return if (position == previews.size) {
+ R.layout.image_preview_other_item
+ } else {
+ R.layout.image_preview_image_item
+ }
+ }
override fun onBindViewHolder(vh: ViewHolder, position: Int) {
- vh.bind(
- uris[position],
- imageLoader ?: error("ImageLoader is missing"),
- if (position == 0 && transitionStatusElementCallback != null) {
- this::onTransitionElementReady
- } else {
- null
- }
- )
+ when (vh) {
+ is OtherItemViewHolder -> vh.bind(totalItemCount - previews.size)
+ is PreviewViewHolder ->
+ vh.bind(
+ previews[position],
+ imageLoader ?: error("ImageLoader is missing"),
+ isSharedTransitionElement = position == firstImagePos,
+ previewReadyCallback =
+ if (
+ position == firstImagePos && transitionStatusElementCallback != null
+ ) {
+ this::onTransitionElementReady
+ } else {
+ null
+ }
+ )
+ }
}
override fun onViewRecycled(vh: ViewHolder) {
@@ -121,41 +363,80 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
}
}
- private class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
- private val image = view.requireViewById<ImageView>(R.id.image)
+ private sealed class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
+ abstract fun unbind()
+ }
+
+ private class PreviewViewHolder(
+ view: View,
+ private val imagePreviewDescription: String,
+ private val videoPreviewDescription: String,
+ private val filePreviewDescription: String,
+ ) : ViewHolder(view) {
+ val image = view.requireViewById<ImageView>(R.id.image)
+ private val badgeFrame = view.requireViewById<View>(R.id.badge_frame)
+ private val badge = view.requireViewById<ImageView>(R.id.badge)
+ private val editActionContainer = view.findViewById<View?>(R.id.edit)
private var scope: CoroutineScope? = null
fun bind(
- uri: Uri,
- imageLoader: ImageLoader,
+ preview: Preview,
+ imageLoader: CachingImageLoader,
+ isSharedTransitionElement: Boolean,
previewReadyCallback: ((String) -> Unit)?
) {
image.setImageDrawable(null)
- image.transitionName = if (previewReadyCallback != null) {
- TRANSITION_NAME
- } else {
- null
+ (image.layoutParams as? ConstraintLayout.LayoutParams)?.let { params ->
+ params.dimensionRatio = preview.aspectRatioString
+ }
+ image.transitionName =
+ if (isSharedTransitionElement) {
+ TRANSITION_NAME
+ } else {
+ null
+ }
+ when (preview.type) {
+ PreviewType.Image -> {
+ itemView.contentDescription = imagePreviewDescription
+ badgeFrame.visibility = View.GONE
+ }
+ PreviewType.Video -> {
+ itemView.contentDescription = videoPreviewDescription
+ badge.setImageResource(R.drawable.ic_file_video)
+ badgeFrame.visibility = View.VISIBLE
+ }
+ else -> {
+ itemView.contentDescription = filePreviewDescription
+ badge.setImageResource(R.drawable.chooser_file_generic)
+ badgeFrame.visibility = View.VISIBLE
+ }
+ }
+ preview.editAction?.also { onClick ->
+ editActionContainer?.apply {
+ setOnClickListener { onClick.run() }
+ visibility = View.VISIBLE
+ }
}
resetScope().launch {
- loadImage(uri, imageLoader, previewReadyCallback)
+ loadImage(preview, imageLoader)
+ if (preview.type == PreviewType.Image) {
+ previewReadyCallback?.let { callback ->
+ image.waitForPreDraw()
+ callback(TRANSITION_NAME)
+ }
+ }
}
}
- private suspend fun loadImage(
- uri: Uri,
- imageLoader: ImageLoader,
- previewReadyCallback: ((String) -> Unit)?
- ) {
- val bitmap = runCatching {
- // it's expected for all loading/caching optimizations to be implemented by the
- // loader
- imageLoader(uri)
- }.getOrNull()
+ private suspend fun loadImage(preview: Preview, imageLoader: CachingImageLoader) {
+ val bitmap =
+ runCatching {
+ // it's expected for all loading/caching optimizations to be implemented by
+ // the loader
+ imageLoader(preview.uri, true)
+ }
+ .getOrNull()
image.setImageBitmap(bitmap)
- previewReadyCallback?.let { callback ->
- image.waitForPreDraw()
- callback(TRANSITION_NAME)
- }
}
private fun resetScope(): CoroutineScope =
@@ -164,15 +445,153 @@ class ScrollableImagePreviewView : RecyclerView, ImagePreviewView {
scope = it
}
- fun unbind() {
+ override fun unbind() {
scope?.cancel()
scope = null
}
}
- private class SpacingDecoration(private val margin: Int) : RecyclerView.ItemDecoration() {
+ private class OtherItemViewHolder(view: View) : ViewHolder(view) {
+ private val label = view.requireViewById<TextView>(R.id.label)
+
+ fun bind(count: Int) {
+ label.text =
+ PluralsMessageFormatter.format(
+ itemView.context.resources,
+ mapOf(PLURALS_COUNT to count),
+ R.string.other_files
+ )
+ }
+
+ override fun unbind() = Unit
+ }
+
+ private class SpacingDecoration(private val innerSpacing: Int, private val outerSpacing: Int) :
+ ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: State) {
- outRect.set(margin, 0, margin, 0)
+ val itemCount = parent.adapter?.itemCount ?: return
+ val pos = parent.getChildAdapterPosition(view)
+ var startMargin = if (pos == 0) outerSpacing else innerSpacing
+ var endMargin = if (pos == itemCount - 1) outerSpacing else 0
+
+ if (ViewCompat.getLayoutDirection(parent) == ViewCompat.LAYOUT_DIRECTION_RTL) {
+ outRect.set(endMargin, 0, startMargin, 0)
+ } else {
+ outRect.set(startMargin, 0, endMargin, 0)
+ }
+ }
+ }
+
+ @VisibleForTesting
+ class BatchPreviewLoader(
+ private val imageLoader: CachingImageLoader,
+ previews: List<Preview>,
+ otherItemCount: Int,
+ private val onReset: (Int) -> Unit,
+ private val onUpdate: (List<Preview>) -> Unit,
+ private val onCompletion: () -> Unit,
+ ) {
+ private val previews: List<Preview> =
+ if (previews is RandomAccess) previews else ArrayList(previews)
+ private val totalItemCount = previews.size + otherItemCount
+ private var scope: CoroutineScope? = MainScope() + Dispatchers.Main.immediate
+
+ fun cancel() {
+ scope?.cancel()
+ scope = null
+ }
+
+ fun loadAspectRatios(maxWidth: Int, previewSizeUpdater: (Preview, Int, Int) -> Int) {
+ val scope = this.scope ?: return
+ // -1 encodes that the preview has not been processed,
+ // 0 means failed, > 0 is a preview width
+ val previewWidths = IntArray(previews.size) { -1 }
+ var blockStart = 0 // inclusive
+ var blockEnd = 0 // exclusive
+
+ // replay 2 items to guarantee that we'd get at least one update
+ val reportFlow = MutableSharedFlow<Any>(replay = 2)
+ val updateEvent = Any()
+ val completedEvent = Any()
+
+ // throttle adapter updates using flow; the flow first emits when enough preview
+ // elements is loaded to fill the viewport and then each time a subsequent block of
+ // previews is loaded
+ scope.launch(Dispatchers.Main) {
+ reportFlow
+ .takeWhile { it !== completedEvent }
+ .throttle(ADAPTER_UPDATE_INTERVAL_MS)
+ .onCompletion { cause ->
+ if (cause == null) {
+ onCompletion()
+ }
+ }
+ .collect {
+ if (blockStart == 0) {
+ onReset(totalItemCount)
+ }
+ val updates = ArrayList<Preview>(blockEnd - blockStart)
+ while (blockStart < blockEnd) {
+ if (previewWidths[blockStart] > 0) {
+ updates.add(previews[blockStart])
+ }
+ blockStart++
+ }
+ if (updates.isNotEmpty()) {
+ onUpdate(updates)
+ }
+ }
+ }
+
+ scope.launch {
+ var blockWidth = 0
+ var isFirstBlock = true
+ var nextIdx = 0
+ List<Job>(4) {
+ launch {
+ while (true) {
+ val i = nextIdx++
+ if (i >= previews.size) break
+ val preview = previews[i]
+
+ previewWidths[i] =
+ runCatching {
+ // TODO: decide on adding a timeout
+ imageLoader(preview.uri, isFirstBlock)?.let { bitmap ->
+ previewSizeUpdater(
+ preview,
+ bitmap.width,
+ bitmap.height
+ )
+ }
+ ?: 0
+ }
+ .getOrDefault(0)
+
+ if (blockEnd != i) continue
+ while (
+ blockEnd < previewWidths.size && previewWidths[blockEnd] >= 0
+ ) {
+ blockWidth += previewWidths[blockEnd]
+ blockEnd++
+ }
+ if (isFirstBlock) {
+ if (blockWidth >= maxWidth) {
+ isFirstBlock = false
+ // notify that the preview now can be displayed
+ reportFlow.emit(updateEvent)
+ }
+ } else {
+ reportFlow.emit(updateEvent)
+ }
+ }
+ }
+ }
+ .joinAll()
+ // in case all previews have failed to load
+ reportFlow.emit(updateEvent)
+ reportFlow.emit(completedEvent)
+ }
}
}
}
diff --git a/java/tests/Android.bp b/java/tests/Android.bp
index 4e835ec8..c381d0a8 100644
--- a/java/tests/Android.bp
+++ b/java/tests/Android.bp
@@ -29,12 +29,10 @@ android_test {
"androidx.lifecycle_lifecycle-runtime-ktx",
"truth-prebuilt",
"testables",
- "testng",
"kotlinx_coroutines_test",
],
test_suites: ["general-tests"],
sdk_version: "core_platform",
- platform_apis: true,
compile_multilib: "both",
dont_merge_manifests: true,
diff --git a/java/tests/AndroidManifest.xml b/java/tests/AndroidManifest.xml
index 306eccb9..05830c4c 100644
--- a/java/tests/AndroidManifest.xml
+++ b/java/tests/AndroidManifest.xml
@@ -29,6 +29,10 @@
<uses-library android:name="android.test.runner" />
<activity android:name="com.android.intentresolver.ChooserWrapperActivity" />
<activity android:name="com.android.intentresolver.ResolverWrapperActivity" />
+ <provider
+ android:authorities="com.android.intentresolver.tests"
+ android:name="com.android.intentresolver.TestContentProvider"
+ android:grantUriPermissions="true" />
</application>
<instrumentation android:name="android.testing.TestableInstrumentation"
diff --git a/java/tests/src/com/android/intentresolver/AnnotatedUserHandlesTest.kt b/java/tests/src/com/android/intentresolver/AnnotatedUserHandlesTest.kt
new file mode 100644
index 00000000..a17a560c
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/AnnotatedUserHandlesTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver
+
+import android.os.UserHandle
+
+import com.google.common.truth.Truth.assertThat
+
+import org.junit.Test
+
+class AnnotatedUserHandlesTest {
+
+ @Test
+ fun testBasicProperties() { // Fields that are reflected back w/o logic.
+ val info = AnnotatedUserHandles.newBuilder()
+ .setUserIdOfCallingApp(42)
+ .setUserHandleSharesheetLaunchedAs(UserHandle.of(116))
+ .setPersonalProfileUserHandle(UserHandle.of(117))
+ .setWorkProfileUserHandle(UserHandle.of(118))
+ .setCloneProfileUserHandle(UserHandle.of(119))
+ .build()
+
+ assertThat(info.userIdOfCallingApp).isEqualTo(42)
+ assertThat(info.userHandleSharesheetLaunchedAs.identifier).isEqualTo(116)
+ assertThat(info.personalProfileUserHandle.identifier).isEqualTo(117)
+ assertThat(info.workProfileUserHandle.identifier).isEqualTo(118)
+ assertThat(info.cloneProfileUserHandle.identifier).isEqualTo(119)
+ }
+
+ @Test
+ fun testWorkTabInitiallySelectedWhenLaunchedFromWorkProfile() {
+ val info = AnnotatedUserHandles.newBuilder()
+ .setUserIdOfCallingApp(42)
+ .setPersonalProfileUserHandle(UserHandle.of(101))
+ .setWorkProfileUserHandle(UserHandle.of(202))
+ .setUserHandleSharesheetLaunchedAs(UserHandle.of(202))
+ .build()
+
+ assertThat(info.tabOwnerUserHandleForLaunch.identifier).isEqualTo(202)
+ }
+
+ @Test
+ fun testPersonalTabInitiallySelectedWhenLaunchedFromPersonalProfile() {
+ val info = AnnotatedUserHandles.newBuilder()
+ .setUserIdOfCallingApp(42)
+ .setPersonalProfileUserHandle(UserHandle.of(101))
+ .setWorkProfileUserHandle(UserHandle.of(202))
+ .setUserHandleSharesheetLaunchedAs(UserHandle.of(101))
+ .build()
+
+ assertThat(info.tabOwnerUserHandleForLaunch.identifier).isEqualTo(101)
+ }
+
+ @Test
+ fun testPersonalTabInitiallySelectedWhenLaunchedFromOtherProfile() {
+ val info = AnnotatedUserHandles.newBuilder()
+ .setUserIdOfCallingApp(42)
+ .setPersonalProfileUserHandle(UserHandle.of(101))
+ .setWorkProfileUserHandle(UserHandle.of(202))
+ .setUserHandleSharesheetLaunchedAs(UserHandle.of(303))
+ .build()
+
+ assertThat(info.tabOwnerUserHandleForLaunch.identifier).isEqualTo(101)
+ }
+}
diff --git a/java/tests/src/com/android/intentresolver/ChooserActionFactoryTest.kt b/java/tests/src/com/android/intentresolver/ChooserActionFactoryTest.kt
index af134fcd..d72c9aa6 100644
--- a/java/tests/src/com/android/intentresolver/ChooserActionFactoryTest.kt
+++ b/java/tests/src/com/android/intentresolver/ChooserActionFactoryTest.kt
@@ -29,7 +29,6 @@ import android.view.View
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.intentresolver.flags.FeatureFlagRepository
-import com.android.intentresolver.flags.Flags
import com.google.common.collect.ImmutableList
import com.google.common.truth.Truth.assertThat
import org.junit.After
@@ -50,6 +49,7 @@ class ChooserActionFactoryTest {
private val logger = mock<ChooserActivityLogger>()
private val flags = mock<FeatureFlagRepository>()
private val actionLabel = "Action label"
+ private val modifyShareLabel = "Modify share"
private val testAction = "com.android.intentresolver.testaction"
private val countdown = CountDownLatch(1)
private val testReceiver: BroadcastReceiver = object : BroadcastReceiver() {
@@ -69,7 +69,6 @@ class ChooserActionFactoryTest {
@Before
fun setup() {
- whenever(flags.isEnabled(Flags.SHARESHEET_RESELECTION_ACTION)).thenReturn(true)
context.registerReceiver(testReceiver, IntentFilter(testAction))
}
@@ -104,18 +103,11 @@ class ChooserActionFactoryTest {
}
@Test
- fun testNoModifyShareAction_flagDisabled() {
- whenever(flags.isEnabled(Flags.SHARESHEET_RESELECTION_ACTION)).thenReturn(false)
- val factory = createFactory(includeModifyShare = true)
-
- assertThat(factory.modifyShareAction).isNull()
- }
-
- @Test
fun testModifyShareAction() {
val factory = createFactory(includeModifyShare = true)
- factory.modifyShareAction!!.run()
+ val action = factory.modifyShareAction ?: error("Modify share action should not be null")
+ action.onClicked.run()
Mockito.verify(logger).logActionSelected(
eq(ChooserActivityLogger.SELECTION_TYPE_MODIFY_SHARE))
@@ -137,13 +129,17 @@ class ChooserActionFactoryTest {
whenever(chooserRequest.chooserActions).thenReturn(ImmutableList.of(action))
if (includeModifyShare) {
- whenever(chooserRequest.modifyShareAction).thenReturn(testPendingIntent)
+ val modifyShare = ChooserAction.Builder(
+ Icon.createWithResource("", Resources.ID_NULL),
+ modifyShareLabel,
+ testPendingIntent
+ ).build()
+ whenever(chooserRequest.modifyShareAction).thenReturn(modifyShare)
}
return ChooserActionFactory(
context,
chooserRequest,
- flags,
mock<ChooserIntegratedDeviceComponents>(),
logger,
Consumer<Boolean>{},
diff --git a/java/tests/src/com/android/intentresolver/ChooserActivityOverrideData.java b/java/tests/src/com/android/intentresolver/ChooserActivityOverrideData.java
index f0c459e5..ce96ef63 100644
--- a/java/tests/src/com/android/intentresolver/ChooserActivityOverrideData.java
+++ b/java/tests/src/com/android/intentresolver/ChooserActivityOverrideData.java
@@ -24,12 +24,11 @@ import static org.mockito.Mockito.when;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.Cursor;
-import android.graphics.Bitmap;
import android.os.UserHandle;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.CrossProfileIntentsChecker;
-import com.android.intentresolver.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
import com.android.intentresolver.chooser.TargetInfo;
+import com.android.intentresolver.contentpreview.ImageLoader;
import com.android.intentresolver.flags.FeatureFlagRepository;
import com.android.intentresolver.shortcuts.ShortcutLoader;
@@ -55,35 +54,35 @@ public class ChooserActivityOverrideData {
@SuppressWarnings("Since15")
public Function<PackageManager, PackageManager> createPackageManager;
+ public Function<TargetInfo, Boolean> onSafelyStartInternalCallback;
public Function<TargetInfo, Boolean> onSafelyStartCallback;
public Function2<UserHandle, Consumer<ShortcutLoader.Result>, ShortcutLoader>
shortcutLoaderFactory = (userHandle, callback) -> null;
public ChooserActivity.ChooserListController resolverListController;
public ChooserActivity.ChooserListController workResolverListController;
public Boolean isVoiceInteraction;
- public boolean isImageType;
public Cursor resolverCursor;
public boolean resolverForceException;
- public Bitmap previewThumbnail;
+ public ImageLoader imageLoader;
public ChooserActivityLogger chooserActivityLogger;
public int alternateProfileSetting;
public Resources resources;
public UserHandle workProfileUserHandle;
+ public UserHandle cloneProfileUserHandle;
+ public UserHandle tabOwnerUserHandleForLaunch;
public boolean hasCrossProfileIntents;
public boolean isQuietModeEnabled;
public Integer myUserId;
public WorkProfileAvailabilityManager mWorkProfileAvailability;
- public MyUserIdProvider mMyUserIdProvider;
public CrossProfileIntentsChecker mCrossProfileIntentsChecker;
public PackageManager packageManager;
public FeatureFlagRepository featureFlagRepository;
public void reset() {
- onSafelyStartCallback = null;
+ onSafelyStartInternalCallback = null;
isVoiceInteraction = null;
createPackageManager = null;
- previewThumbnail = null;
- isImageType = false;
+ imageLoader = null;
resolverCursor = null;
resolverForceException = false;
resolverListController = mock(ChooserActivity.ChooserListController.class);
@@ -92,6 +91,8 @@ public class ChooserActivityOverrideData {
alternateProfileSetting = 0;
resources = null;
workProfileUserHandle = null;
+ cloneProfileUserHandle = null;
+ tabOwnerUserHandleForLaunch = null;
hasCrossProfileIntents = true;
isQuietModeEnabled = false;
myUserId = null;
@@ -122,13 +123,6 @@ public class ChooserActivityOverrideData {
};
shortcutLoaderFactory = ((userHandle, resultConsumer) -> null);
- mMyUserIdProvider = new MyUserIdProvider() {
- @Override
- public int getMyUserId() {
- return myUserId != null ? myUserId : UserHandle.myUserId();
- }
- };
-
mCrossProfileIntentsChecker = mock(CrossProfileIntentsChecker.class);
when(mCrossProfileIntentsChecker.hasCrossProfileIntents(any(), anyInt(), anyInt()))
.thenAnswer(invocation -> hasCrossProfileIntents);
diff --git a/java/tests/src/com/android/intentresolver/ChooserListAdapterTest.kt b/java/tests/src/com/android/intentresolver/ChooserListAdapterTest.kt
index 58f6b733..4612b430 100644
--- a/java/tests/src/com/android/intentresolver/ChooserListAdapterTest.kt
+++ b/java/tests/src/com/android/intentresolver/ChooserListAdapterTest.kt
@@ -20,16 +20,17 @@ import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.PackageManager.ResolveInfoFlags
+import android.os.UserHandle
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.intentresolver.ChooserListAdapter.LoadDirectShareIconTask
import com.android.intentresolver.chooser.DisplayResolveInfo
import com.android.intentresolver.chooser.SelectableTargetInfo
import com.android.intentresolver.chooser.TargetInfo
+import com.android.intentresolver.icons.TargetDataLoader
import com.android.internal.R
import org.junit.Before
import org.junit.Test
@@ -39,43 +40,43 @@ import org.mockito.Mockito.verify
@RunWith(AndroidJUnit4::class)
class ChooserListAdapterTest {
- private val packageManager = mock<PackageManager> {
- whenever(
- resolveActivity(any(), any<ResolveInfoFlags>())
- ).thenReturn(mock())
- }
- private val context = InstrumentationRegistry.getInstrumentation().getContext()
+ private val userHandle: UserHandle =
+ InstrumentationRegistry.getInstrumentation().targetContext.user
+
+ private val packageManager =
+ mock<PackageManager> {
+ whenever(resolveActivity(any(), any<ResolveInfoFlags>())).thenReturn(mock())
+ }
+ private val context = InstrumentationRegistry.getInstrumentation().context
private val resolverListController = mock<ResolverListController>()
private val chooserActivityLogger = mock<ChooserActivityLogger>()
+ private val mTargetDataLoader = mock<TargetDataLoader>()
- private fun createChooserListAdapter(
- taskProvider: (TargetInfo?) -> LoadDirectShareIconTask
- ) = object : ChooserListAdapter(
+ private val testSubject by lazy {
+ ChooserListAdapter(
context,
emptyList(),
emptyArray(),
emptyList(),
false,
resolverListController,
- null,
+ userHandle,
Intent(),
mock(),
packageManager,
chooserActivityLogger,
mock(),
- 0
- ) {
- override fun createLoadDirectShareIconTask(
- info: SelectableTargetInfo
- ): LoadDirectShareIconTask = taskProvider(info)
- }
+ 0,
+ null,
+ mTargetDataLoader
+ )
+ }
@Before
fun setup() {
// ChooserListAdapter reads DeviceConfig and needs a permission for that.
- InstrumentationRegistry
- .getInstrumentation()
- .getUiAutomation()
+ InstrumentationRegistry.getInstrumentation()
+ .uiAutomation
.adoptShellPermissionIdentity("android.permission.READ_DEVICE_CONFIG")
}
@@ -85,41 +86,56 @@ class ChooserListAdapterTest {
val viewHolder = ResolverListAdapter.ViewHolder(view)
view.tag = viewHolder
val targetInfo = createSelectableTargetInfo()
- val iconTask = mock<LoadDirectShareIconTask>()
- val testSubject = createChooserListAdapter { iconTask }
testSubject.onBindView(view, targetInfo, 0)
- verify(iconTask, times(1)).loadIcon()
+ verify(mTargetDataLoader, times(1)).loadDirectShareIcon(any(), any(), any())
}
@Test
- fun testOnlyOneTaskPerTarget() {
+ fun onBindView_DirectShareTargetIconAndLabelLoadedOnlyOnce() {
val view = createView()
val viewHolderOne = ResolverListAdapter.ViewHolder(view)
view.tag = viewHolderOne
val targetInfo = createSelectableTargetInfo()
- val iconTaskOne = mock<LoadDirectShareIconTask>()
- val testTaskProvider = mock<() -> LoadDirectShareIconTask> {
- whenever(invoke()).thenReturn(iconTaskOne)
- }
- val testSubject = createChooserListAdapter { testTaskProvider.invoke() }
testSubject.onBindView(view, targetInfo, 0)
val viewHolderTwo = ResolverListAdapter.ViewHolder(view)
view.tag = viewHolderTwo
- whenever(testTaskProvider()).thenReturn(mock())
testSubject.onBindView(view, targetInfo, 0)
- verify(iconTaskOne, times(1)).loadIcon()
- verify(testTaskProvider, times(1)).invoke()
+ verify(mTargetDataLoader, times(1)).loadDirectShareIcon(any(), any(), any())
+ }
+
+ @Test
+ fun onBindView_AppTargetIconAndLabelLoadedOnlyOnce() {
+ val view = createView()
+ val viewHolderOne = ResolverListAdapter.ViewHolder(view)
+ view.tag = viewHolderOne
+ val targetInfo =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ Intent(),
+ ResolverDataProvider.createResolveInfo(2, 0, userHandle),
+ null,
+ "extended info",
+ Intent(),
+ /* resolveInfoPresentationGetter= */ null
+ )
+ testSubject.onBindView(view, targetInfo, 0)
+
+ val viewHolderTwo = ResolverListAdapter.ViewHolder(view)
+ view.tag = viewHolderTwo
+
+ testSubject.onBindView(view, targetInfo, 0)
+
+ verify(mTargetDataLoader, times(1)).loadAppTargetIcon(any(), any(), any())
}
private fun createSelectableTargetInfo(): TargetInfo =
SelectableTargetInfo.newSelectableTargetInfo(
/* sourceInfo = */ DisplayResolveInfo.newDisplayResolveInfo(
Intent(),
- ResolverDataProvider.createResolveInfo(2, 0),
+ ResolverDataProvider.createResolveInfo(2, 0, userHandle),
"label",
"extended info",
Intent(),
@@ -128,7 +144,10 @@ class ChooserListAdapterTest {
/* backupResolveInfo = */ mock(),
/* resolvedIntent = */ Intent(),
/* chooserTarget = */ createChooserTarget(
- "Target", 0.5f, ComponentName("pkg", "Class"), "id-1"
+ "Target",
+ 0.5f,
+ ComponentName("pkg", "Class"),
+ "id-1"
),
/* modifiedScore = */ 1f,
/* shortcutInfo = */ createShortcutInfo("id-1", ComponentName("pkg", "Class"), 1),
diff --git a/java/tests/src/com/android/intentresolver/ChooserRefinementManagerTest.kt b/java/tests/src/com/android/intentresolver/ChooserRefinementManagerTest.kt
index 50c37c7f..bd355c86 100644
--- a/java/tests/src/com/android/intentresolver/ChooserRefinementManagerTest.kt
+++ b/java/tests/src/com/android/intentresolver/ChooserRefinementManagerTest.kt
@@ -16,46 +16,227 @@
package com.android.intentresolver
-import android.content.Context
+import android.app.Activity
+import android.app.Application
import android.content.Intent
import android.content.IntentSender
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.os.Message
+import android.os.ResultReceiver
+import androidx.lifecycle.Observer
+import androidx.test.annotation.UiThreadTest
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.intentresolver.ChooserRefinementManager.RefinementCompletion
+import com.android.intentresolver.chooser.ImmutableTargetInfo
import com.android.intentresolver.chooser.TargetInfo
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mockito
-import java.util.function.Consumer
-import org.junit.Assert.assertEquals
@RunWith(AndroidJUnit4::class)
+@UiThreadTest
class ChooserRefinementManagerTest {
- @Test
- fun testMaybeHandleSelection() {
- val intentSender = mock<IntentSender>()
- val refinementManager = ChooserRefinementManager(
- mock<Context>(),
- intentSender,
- Consumer<TargetInfo>{},
- Runnable{})
-
- val intents = listOf(Intent(Intent.ACTION_VIEW), Intent(Intent.ACTION_EDIT))
- val targetInfo = mock<TargetInfo>{
- whenever(allSourceIntents).thenReturn(intents)
+ private val refinementManager = ChooserRefinementManager()
+ private val intentSender = mock<IntentSender>()
+ private val application = mock<Application>()
+ private val exampleSourceIntents =
+ listOf(Intent(Intent.ACTION_VIEW), Intent(Intent.ACTION_EDIT))
+ private val exampleTargetInfo =
+ ImmutableTargetInfo.newBuilder().setAllSourceIntents(exampleSourceIntents).build()
+
+ private val completionObserver =
+ object : Observer<RefinementCompletion> {
+ val failureCountDown = CountDownLatch(1)
+ val successCountDown = CountDownLatch(1)
+ var latestTargetInfo: TargetInfo? = null
+
+ override fun onChanged(completion: RefinementCompletion) {
+ if (completion.consume()) {
+ val targetInfo = completion.targetInfo
+ if (targetInfo == null) {
+ failureCountDown.countDown()
+ } else {
+ latestTargetInfo = targetInfo
+ successCountDown.countDown()
+ }
+ }
+ }
}
- refinementManager.maybeHandleSelection(targetInfo)
+ /** Synchronously executes post() calls. */
+ private class FakeHandler(looper: Looper) : Handler(looper) {
+ override fun sendMessageAtTime(msg: Message, uptimeMillis: Long): Boolean {
+ dispatchMessage(msg)
+ return true
+ }
+ }
+
+ @Before
+ fun setup() {
+ refinementManager.refinementCompletion.observeForever(completionObserver)
+ }
+
+ @Test
+ fun testTypicalRefinementFlow() {
+ assertThat(
+ refinementManager.maybeHandleSelection(
+ exampleTargetInfo,
+ intentSender,
+ application,
+ FakeHandler(Looper.myLooper())
+ )
+ )
+ .isTrue()
val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
- Mockito.verify(intentSender).sendIntent(
- any(), eq(0), intentCaptor.capture(), eq(null), eq(null))
+ Mockito.verify(intentSender)
+ .sendIntent(any(), eq(0), intentCaptor.capture(), eq(null), eq(null))
val intent = intentCaptor.value
- assertEquals(intents[0], intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java))
+ assertThat(intent?.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java))
+ .isEqualTo(exampleSourceIntents[0])
val alternates =
- intent.getParcelableArrayExtra(Intent.EXTRA_ALTERNATE_INTENTS, Intent::class.java)
- assertEquals(1, alternates?.size)
- assertEquals(intents[1], alternates?.get(0))
+ intent?.getParcelableArrayExtra(Intent.EXTRA_ALTERNATE_INTENTS, Intent::class.java)
+ assertThat(alternates?.size).isEqualTo(1)
+ assertThat(alternates?.get(0)).isEqualTo(exampleSourceIntents[1])
+
+ // Complete the refinement
+ val receiver =
+ intent?.getParcelableExtra(Intent.EXTRA_RESULT_RECEIVER, ResultReceiver::class.java)
+ val bundle = Bundle().apply { putParcelable(Intent.EXTRA_INTENT, exampleSourceIntents[0]) }
+ receiver?.send(Activity.RESULT_OK, bundle)
+
+ assertThat(completionObserver.successCountDown.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+ assertThat(completionObserver.latestTargetInfo?.resolvedIntent?.action)
+ .isEqualTo(Intent.ACTION_VIEW)
+ }
+
+ @Test
+ fun testRefinementCancelled() {
+ assertThat(
+ refinementManager.maybeHandleSelection(
+ exampleTargetInfo,
+ intentSender,
+ application,
+ FakeHandler(Looper.myLooper())
+ )
+ )
+ .isTrue()
+
+ val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
+ Mockito.verify(intentSender)
+ .sendIntent(any(), eq(0), intentCaptor.capture(), eq(null), eq(null))
+
+ val intent = intentCaptor.value
+
+ // Complete the refinement
+ val receiver =
+ intent?.getParcelableExtra(Intent.EXTRA_RESULT_RECEIVER, ResultReceiver::class.java)
+ val bundle = Bundle().apply { putParcelable(Intent.EXTRA_INTENT, exampleSourceIntents[0]) }
+ receiver?.send(Activity.RESULT_CANCELED, bundle)
+
+ assertThat(completionObserver.failureCountDown.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+ }
+
+ @Test
+ fun testMaybeHandleSelection_noSourceIntents() {
+ assertThat(
+ refinementManager.maybeHandleSelection(
+ ImmutableTargetInfo.newBuilder().build(),
+ intentSender,
+ application,
+ FakeHandler(Looper.myLooper())
+ )
+ )
+ .isFalse()
+ }
+
+ @Test
+ fun testMaybeHandleSelection_suspended() {
+ val targetInfo =
+ ImmutableTargetInfo.newBuilder()
+ .setAllSourceIntents(exampleSourceIntents)
+ .setIsSuspended(true)
+ .build()
+
+ assertThat(
+ refinementManager.maybeHandleSelection(
+ targetInfo,
+ intentSender,
+ application,
+ FakeHandler(Looper.myLooper())
+ )
+ )
+ .isFalse()
+ }
+
+ @Test
+ fun testMaybeHandleSelection_noIntentSender() {
+ assertThat(
+ refinementManager.maybeHandleSelection(
+ exampleTargetInfo,
+ /* IntentSender */ null,
+ application,
+ FakeHandler(Looper.myLooper())
+ )
+ )
+ .isFalse()
+ }
+
+ @Test
+ fun testConfigurationChangeDuringRefinement() {
+ assertThat(
+ refinementManager.maybeHandleSelection(
+ exampleTargetInfo,
+ intentSender,
+ application,
+ FakeHandler(Looper.myLooper())
+ )
+ )
+ .isTrue()
+
+ refinementManager.onActivityStop(/* config changing = */ true)
+ refinementManager.onActivityResume()
+
+ assertThat(completionObserver.failureCountDown.count).isEqualTo(1)
+ }
+
+ @Test
+ fun testResumeDuringRefinement() {
+ assertThat(
+ refinementManager.maybeHandleSelection(
+ exampleTargetInfo,
+ intentSender,
+ application,
+ FakeHandler(Looper.myLooper()!!)
+ )
+ )
+ .isTrue()
+
+ refinementManager.onActivityStop(/* config changing = */ false)
+ // Resume during refinement but not during a config change, so finish the activity.
+ refinementManager.onActivityResume()
+
+ // Call should be synchronous, don't need to await for this one.
+ assertThat(completionObserver.failureCountDown.count).isEqualTo(0)
+ }
+
+ @Test
+ fun testRefinementCompletion() {
+ val refinementCompletion = RefinementCompletion(exampleTargetInfo)
+ assertThat(refinementCompletion.targetInfo).isEqualTo(exampleTargetInfo)
+ assertThat(refinementCompletion.consume()).isTrue()
+ assertThat(refinementCompletion.targetInfo).isEqualTo(exampleTargetInfo)
+
+ // can only consume once.
+ assertThat(refinementCompletion.consume()).isFalse()
}
}
diff --git a/java/tests/src/com/android/intentresolver/ChooserRequestParametersTest.kt b/java/tests/src/com/android/intentresolver/ChooserRequestParametersTest.kt
new file mode 100644
index 00000000..331d1c21
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/ChooserRequestParametersTest.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.service.chooser.ChooserAction
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ChooserRequestParametersTest {
+ val flags = TestFeatureFlagRepository(mapOf())
+
+ @Test
+ fun testChooserActions() {
+ val actionCount = 3
+ val intent = Intent(Intent.ACTION_SEND)
+ val actions = createChooserActions(actionCount)
+ val chooserIntent =
+ Intent(Intent.ACTION_CHOOSER).apply {
+ putExtra(Intent.EXTRA_INTENT, intent)
+ putExtra(Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS, actions)
+ }
+ val request = ChooserRequestParameters(chooserIntent, "", Uri.EMPTY, flags)
+ assertThat(request.chooserActions).containsExactlyElementsIn(actions).inOrder()
+ }
+
+ @Test
+ fun testChooserActions_empty() {
+ val intent = Intent(Intent.ACTION_SEND)
+ val chooserIntent =
+ Intent(Intent.ACTION_CHOOSER).apply { putExtra(Intent.EXTRA_INTENT, intent) }
+ val request = ChooserRequestParameters(chooserIntent, "", Uri.EMPTY, flags)
+ assertThat(request.chooserActions).isEmpty()
+ }
+
+ @Test
+ fun testChooserActions_tooMany() {
+ val intent = Intent(Intent.ACTION_SEND)
+ val chooserActions = createChooserActions(10)
+ val chooserIntent =
+ Intent(Intent.ACTION_CHOOSER).apply {
+ putExtra(Intent.EXTRA_INTENT, intent)
+ putExtra(Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS, chooserActions)
+ }
+
+ val request = ChooserRequestParameters(chooserIntent, "", Uri.EMPTY, flags)
+
+ val expectedActions = chooserActions.sliceArray(0 until 5)
+ assertThat(request.chooserActions).containsExactlyElementsIn(expectedActions).inOrder()
+ }
+
+ private fun createChooserActions(count: Int): Array<ChooserAction> {
+ return Array(count) { i -> createChooserAction("$i") }
+ }
+
+ private fun createChooserAction(label: CharSequence): ChooserAction {
+ val icon = Icon.createWithContentUri("content://org.package.app/image")
+ val pendingIntent =
+ PendingIntent.getBroadcast(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(),
+ 0,
+ Intent("TESTACTION"),
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ return ChooserAction.Builder(icon, label, pendingIntent).build()
+ }
+}
diff --git a/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java b/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java
index d4ae666b..6ac6b6d3 100644
--- a/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java
+++ b/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java
@@ -29,14 +29,17 @@ import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Bundle;
import android.os.UserHandle;
+import androidx.lifecycle.ViewModelProvider;
+
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.CrossProfileIntentsChecker;
-import com.android.intentresolver.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
import com.android.intentresolver.chooser.DisplayResolveInfo;
import com.android.intentresolver.chooser.TargetInfo;
import com.android.intentresolver.flags.FeatureFlagRepository;
import com.android.intentresolver.grid.ChooserGridAdapter;
+import com.android.intentresolver.icons.TargetDataLoader;
import com.android.intentresolver.shortcuts.ShortcutLoader;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -70,7 +73,8 @@ public class ChooserWrapperActivity
UserHandle userHandle,
Intent targetIntent,
ChooserRequestParameters chooserRequest,
- int maxTargetsPerRow) {
+ int maxTargetsPerRow,
+ TargetDataLoader targetDataLoader) {
PackageManager packageManager =
sOverrides.packageManager == null ? context.getPackageManager()
: sOverrides.packageManager;
@@ -80,14 +84,16 @@ public class ChooserWrapperActivity
initialIntents,
rList,
filterLastUsed,
- resolverListController,
+ createListController(userHandle),
userHandle,
targetIntent,
this,
packageManager,
getChooserActivityLogger(),
chooserRequest,
- maxTargetsPerRow);
+ maxTargetsPerRow,
+ userHandle,
+ targetDataLoader);
}
@Override
@@ -142,14 +148,6 @@ public class ChooserWrapperActivity
}
@Override
- protected MyUserIdProvider createMyUserIdProvider() {
- if (sOverrides.mMyUserIdProvider != null) {
- return sOverrides.mMyUserIdProvider;
- }
- return super.createMyUserIdProvider();
- }
-
- @Override
protected CrossProfileIntentsChecker createCrossProfileIntentsChecker() {
if (sOverrides.mCrossProfileIntentsChecker != null) {
return sOverrides.mCrossProfileIntentsChecker;
@@ -166,12 +164,13 @@ public class ChooserWrapperActivity
}
@Override
- public void safelyStartActivity(TargetInfo cti) {
- if (sOverrides.onSafelyStartCallback != null
- && sOverrides.onSafelyStartCallback.apply(cti)) {
+ public void safelyStartActivityInternal(TargetInfo cti, UserHandle user,
+ @Nullable Bundle options) {
+ if (sOverrides.onSafelyStartInternalCallback != null
+ && sOverrides.onSafelyStartInternalCallback.apply(cti)) {
return;
}
- super.safelyStartActivity(cti);
+ super.safelyStartActivityInternal(cti, user, options);
}
@Override
@@ -199,15 +198,10 @@ public class ChooserWrapperActivity
}
@Override
- protected ImageLoader createPreviewImageLoader() {
- return new TestPreviewImageLoader(
- super.createPreviewImageLoader(),
- () -> sOverrides.previewThumbnail);
- }
-
- @Override
- protected boolean isImageType(String mimeType) {
- return sOverrides.isImageType;
+ protected ViewModelProvider.Factory createPreviewViewModelFactory() {
+ return TestContentPreviewViewModel.Companion.wrap(
+ super.createPreviewViewModelFactory(),
+ sOverrides.imageLoader);
}
@Override
@@ -260,6 +254,14 @@ public class ChooserWrapperActivity
}
@Override
+ protected UserHandle getTabOwnerUserHandleForLaunch() {
+ if (sOverrides.tabOwnerUserHandleForLaunch == null) {
+ return super.getTabOwnerUserHandleForLaunch();
+ }
+ return sOverrides.tabOwnerUserHandleForLaunch;
+ }
+
+ @Override
public Context createContextAsUser(UserHandle user, int flags) {
// return the current context as a work profile doesn't really exist in these tests
return getApplicationContext();
diff --git a/java/tests/src/com/android/intentresolver/ImagePreviewImageLoaderTest.kt b/java/tests/src/com/android/intentresolver/ImagePreviewImageLoaderTest.kt
deleted file mode 100644
index f327e19e..00000000
--- a/java/tests/src/com/android/intentresolver/ImagePreviewImageLoaderTest.kt
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.intentresolver
-
-import android.content.ContentResolver
-import android.content.Context
-import android.content.res.Resources
-import android.net.Uri
-import android.util.Size
-import androidx.lifecycle.Lifecycle
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestCoroutineScheduler
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.resetMain
-import kotlinx.coroutines.test.runTest
-import kotlinx.coroutines.test.setMain
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.mockito.Mockito.never
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-
-@OptIn(ExperimentalCoroutinesApi::class)
-class ImagePreviewImageLoaderTest {
- private val imageSize = Size(300, 300)
- private val uriOne = Uri.parse("content://org.package.app/image-1.png")
- private val uriTwo = Uri.parse("content://org.package.app/image-2.png")
- private val contentResolver = mock<ContentResolver>()
- private val resources = mock<Resources> {
- whenever(getDimensionPixelSize(R.dimen.chooser_preview_image_max_dimen))
- .thenReturn(imageSize.width)
- }
- private val context = mock<Context> {
- whenever(this.resources).thenReturn(this@ImagePreviewImageLoaderTest.resources)
- whenever(this.contentResolver).thenReturn(this@ImagePreviewImageLoaderTest.contentResolver)
- }
- private val scheduler = TestCoroutineScheduler()
- private val lifecycleOwner = TestLifecycleOwner()
- private val dispatcher = UnconfinedTestDispatcher(scheduler)
- private val testSubject = ImagePreviewImageLoader(
- context, lifecycleOwner.lifecycle, 1, dispatcher
- )
-
- @Before
- fun setup() {
- Dispatchers.setMain(dispatcher)
- lifecycleOwner.state = Lifecycle.State.CREATED
- }
-
- @After
- fun cleanup() {
- lifecycleOwner.state = Lifecycle.State.DESTROYED
- Dispatchers.resetMain()
- }
-
- @Test
- fun test_prePopulate() = runTest {
- testSubject.prePopulate(listOf(uriOne, uriTwo))
-
- verify(contentResolver, times(1)).loadThumbnail(uriOne, imageSize, null)
- verify(contentResolver, never()).loadThumbnail(uriTwo, imageSize, null)
-
- testSubject(uriOne)
- verify(contentResolver, times(1)).loadThumbnail(uriOne, imageSize, null)
- }
-
- @Test
- fun test_invoke_return_cached_image() = runTest {
- testSubject(uriOne)
- testSubject(uriOne)
-
- verify(contentResolver, times(1)).loadThumbnail(any(), any(), anyOrNull())
- }
-
- @Test
- fun test_invoke_old_records_evicted_from_the_cache() = runTest {
- testSubject(uriOne)
- testSubject(uriTwo)
- testSubject(uriTwo)
- testSubject(uriOne)
-
- verify(contentResolver, times(2)).loadThumbnail(uriOne, imageSize, null)
- verify(contentResolver, times(1)).loadThumbnail(uriTwo, imageSize, null)
- }
-}
diff --git a/java/tests/src/com/android/intentresolver/ResolverActivityTest.java b/java/tests/src/com/android/intentresolver/ResolverActivityTest.java
index ae1b99f8..7233fd3d 100644
--- a/java/tests/src/com/android/intentresolver/ResolverActivityTest.java
+++ b/java/tests/src/com/android/intentresolver/ResolverActivityTest.java
@@ -33,10 +33,11 @@ import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.fail;
import android.content.Intent;
import android.content.pm.ResolveInfo;
@@ -55,7 +56,8 @@ import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import com.android.intentresolver.widget.ResolverDrawerLayout;
-import com.android.internal.R;
+
+import com.google.android.collect.Lists;
import org.junit.Before;
import org.junit.Ignore;
@@ -72,6 +74,9 @@ import java.util.List;
*/
@RunWith(AndroidJUnit4.class)
public class ResolverActivityTest {
+
+ private static final UserHandle PERSONAL_USER_HANDLE = androidx.test.platform.app
+ .InstrumentationRegistry.getInstrumentation().getTargetContext().getUser();
protected Intent getConcreteIntentForLaunch(Intent clientIntent) {
clientIntent.setClass(
androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getTargetContext(),
@@ -98,26 +103,27 @@ public class ResolverActivityTest {
@Test
public void twoOptionsAndUserSelectsOne() throws InterruptedException {
Intent sendIntent = createSendImageIntent();
- List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2,
+ PERSONAL_USER_HANDLE);
setupResolverControllers(resolvedComponentInfos);
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
- Espresso.registerIdlingResources(activity.getAdapter().getLabelIdlingResource());
+ Espresso.registerIdlingResources(activity.getLabelIdlingResource());
waitForIdle();
assertThat(activity.getAdapter().getCount(), is(2));
ResolveInfo[] chosen = new ResolveInfo[1];
- sOverrides.onSafelyStartCallback = targetInfo -> {
- chosen[0] = targetInfo.getResolveInfo();
+ sOverrides.onSafelyStartInternalCallback = result -> {
+ chosen[0] = result.first.getResolveInfo();
return true;
};
ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
onView(withText(toChoose.activityInfo.name))
.perform(click());
- onView(withId(R.id.button_once))
+ onView(withId(com.android.internal.R.id.button_once))
.perform(click());
waitForIdle();
assertThat(chosen[0], is(toChoose));
@@ -127,19 +133,20 @@ public class ResolverActivityTest {
@Test
public void setMaxHeight() throws Exception {
Intent sendIntent = createSendImageIntent();
- List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2,
+ PERSONAL_USER_HANDLE);
setupResolverControllers(resolvedComponentInfos);
waitForIdle();
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
- final View viewPager = activity.findViewById(R.id.profile_pager);
+ final View viewPager = activity.findViewById(com.android.internal.R.id.profile_pager);
final int initialResolverHeight = viewPager.getHeight();
activity.runOnUiThread(() -> {
ResolverDrawerLayout layout = (ResolverDrawerLayout)
activity.findViewById(
- R.id.contentPanel);
+ com.android.internal.R.id.contentPanel);
((ResolverDrawerLayout.LayoutParams) viewPager.getLayoutParams()).maxHeight
= initialResolverHeight - 1;
// Force a relayout
@@ -153,7 +160,7 @@ public class ResolverActivityTest {
activity.runOnUiThread(() -> {
ResolverDrawerLayout layout = (ResolverDrawerLayout)
activity.findViewById(
- R.id.contentPanel);
+ com.android.internal.R.id.contentPanel);
((ResolverDrawerLayout.LayoutParams) viewPager.getLayoutParams()).maxHeight
= initialResolverHeight + 1;
// Force a relayout
@@ -169,16 +176,18 @@ public class ResolverActivityTest {
@Test
public void setShowAtTopToTrue() throws Exception {
Intent sendIntent = createSendImageIntent();
- List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2,
+ PERSONAL_USER_HANDLE);
setupResolverControllers(resolvedComponentInfos);
waitForIdle();
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
- final View viewPager = activity.findViewById(R.id.profile_pager);
- final View divider = activity.findViewById(R.id.divider);
+ final View viewPager = activity.findViewById(com.android.internal.R.id.profile_pager);
+ final View divider = activity.findViewById(com.android.internal.R.id.divider);
final RelativeLayout profileView =
- (RelativeLayout) activity.findViewById(R.id.profile_button).getParent();
+ (RelativeLayout) activity.findViewById(com.android.internal.R.id.profile_button)
+ .getParent();
assertThat("Drawer should show at bottom by default",
profileView.getBottom() + divider.getHeight() == viewPager.getTop()
&& profileView.getTop() > 0);
@@ -186,7 +195,7 @@ public class ResolverActivityTest {
activity.runOnUiThread(() -> {
ResolverDrawerLayout layout = (ResolverDrawerLayout)
activity.findViewById(
- R.id.contentPanel);
+ com.android.internal.R.id.contentPanel);
layout.setShowAtTop(true);
});
waitForIdle();
@@ -198,7 +207,8 @@ public class ResolverActivityTest {
@Test
public void hasLastChosenActivity() throws Exception {
Intent sendIntent = createSendImageIntent();
- List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2,
+ PERSONAL_USER_HANDLE);
ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
setupResolverControllers(resolvedComponentInfos);
@@ -213,12 +223,12 @@ public class ResolverActivityTest {
assertThat(activity.getAdapter().getPlaceholderCount(), is(1));
ResolveInfo[] chosen = new ResolveInfo[1];
- sOverrides.onSafelyStartCallback = targetInfo -> {
- chosen[0] = targetInfo.getResolveInfo();
+ sOverrides.onSafelyStartInternalCallback = result -> {
+ chosen[0] = result.first.getResolveInfo();
return true;
};
- onView(withId(R.id.button_once)).perform(click());
+ onView(withId(com.android.internal.R.id.button_once)).perform(click());
waitForIdle();
assertThat(chosen[0], is(toChoose));
}
@@ -226,32 +236,35 @@ public class ResolverActivityTest {
@Test
public void hasOtherProfileOneOption() throws Exception {
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10);
- List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
- setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10,
+ PERSONAL_USER_HANDLE);
markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
+ sOverrides.workProfileUserHandle);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
ResolveInfo toChoose = personalResolvedComponentInfos.get(1).getResolveInfoAt(0);
Intent sendIntent = createSendImageIntent();
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
- Espresso.registerIdlingResources(activity.getAdapter().getLabelIdlingResource());
+ Espresso.registerIdlingResources(activity.getLabelIdlingResource());
waitForIdle();
// The other entry is filtered to the last used slot
assertThat(activity.getAdapter().getCount(), is(1));
ResolveInfo[] chosen = new ResolveInfo[1];
- sOverrides.onSafelyStartCallback = targetInfo -> {
- chosen[0] = targetInfo.getResolveInfo();
+ sOverrides.onSafelyStartInternalCallback = result -> {
+ chosen[0] = result.first.getResolveInfo();
return true;
};
// Make a stable copy of the components as the original list may be modified
List<ResolvedComponentInfo> stableCopy =
- createResolvedComponentsForTestWithOtherProfile(2, /* userId= */ 10);
+ createResolvedComponentsForTestWithOtherProfile(2, /* userId= */ 10,
+ PERSONAL_USER_HANDLE);
// We pick the first one as there is another one in the work profile side
onView(first(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name)))
.perform(click());
- onView(withId(R.id.button_once))
+ onView(withId(com.android.internal.R.id.button_once))
.perform(click());
waitForIdle();
assertThat(chosen[0], is(toChoose));
@@ -261,34 +274,34 @@ public class ResolverActivityTest {
public void hasOtherProfileTwoOptionsAndUserSelectsOne() throws Exception {
Intent sendIntent = createSendImageIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(3);
+ createResolvedComponentsForTestWithOtherProfile(3, PERSONAL_USER_HANDLE);
ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
setupResolverControllers(resolvedComponentInfos);
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
- Espresso.registerIdlingResources(activity.getAdapter().getLabelIdlingResource());
+ Espresso.registerIdlingResources(activity.getLabelIdlingResource());
waitForIdle();
// The other entry is filtered to the other profile slot
assertThat(activity.getAdapter().getCount(), is(2));
ResolveInfo[] chosen = new ResolveInfo[1];
- sOverrides.onSafelyStartCallback = targetInfo -> {
- chosen[0] = targetInfo.getResolveInfo();
+ sOverrides.onSafelyStartInternalCallback = result -> {
+ chosen[0] = result.first.getResolveInfo();
return true;
};
// Confirm that the button bar is disabled by default
- onView(withId(R.id.button_once)).check(matches(not(isEnabled())));
+ onView(withId(com.android.internal.R.id.button_once)).check(matches(not(isEnabled())));
// Make a stable copy of the components as the original list may be modified
List<ResolvedComponentInfo> stableCopy =
- createResolvedComponentsForTestWithOtherProfile(2);
+ createResolvedComponentsForTestWithOtherProfile(2, PERSONAL_USER_HANDLE);
onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
.perform(click());
- onView(withId(R.id.button_once)).perform(click());
+ onView(withId(com.android.internal.R.id.button_once)).perform(click());
waitForIdle();
assertThat(chosen[0], is(toChoose));
}
@@ -300,7 +313,7 @@ public class ResolverActivityTest {
// chosen activity.
Intent sendIntent = createSendImageIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(3);
+ createResolvedComponentsForTestWithOtherProfile(3, PERSONAL_USER_HANDLE);
ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
setupResolverControllers(resolvedComponentInfos);
@@ -308,28 +321,28 @@ public class ResolverActivityTest {
.thenReturn(resolvedComponentInfos.get(1).getResolveInfoAt(0));
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
- Espresso.registerIdlingResources(activity.getAdapter().getLabelIdlingResource());
+ Espresso.registerIdlingResources(activity.getLabelIdlingResource());
waitForIdle();
// The other entry is filtered to the other profile slot
assertThat(activity.getAdapter().getCount(), is(2));
ResolveInfo[] chosen = new ResolveInfo[1];
- sOverrides.onSafelyStartCallback = targetInfo -> {
- chosen[0] = targetInfo.getResolveInfo();
+ sOverrides.onSafelyStartInternalCallback = result -> {
+ chosen[0] = result.first.getResolveInfo();
return true;
};
// Confirm that the button bar is disabled by default
- onView(withId(R.id.button_once)).check(matches(not(isEnabled())));
+ onView(withId(com.android.internal.R.id.button_once)).check(matches(not(isEnabled())));
// Make a stable copy of the components as the original list may be modified
List<ResolvedComponentInfo> stableCopy =
- createResolvedComponentsForTestWithOtherProfile(2);
+ createResolvedComponentsForTestWithOtherProfile(2, PERSONAL_USER_HANDLE);
onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
.perform(click());
- onView(withId(R.id.button_once)).perform(click());
+ onView(withId(com.android.internal.R.id.button_once)).perform(click());
waitForIdle();
assertThat(chosen[0], is(toChoose));
}
@@ -342,7 +355,7 @@ public class ResolverActivityTest {
mActivityRule.launchActivity(sendIntent);
waitForIdle();
- onView(withId(R.id.tabs)).check(matches(isDisplayed()));
+ onView(withId(com.android.internal.R.id.tabs)).check(matches(isDisplayed()));
}
@Test
@@ -352,18 +365,20 @@ public class ResolverActivityTest {
mActivityRule.launchActivity(sendIntent);
waitForIdle();
- onView(withId(R.id.tabs)).check(matches(not(isDisplayed())));
+ onView(withId(com.android.internal.R.id.tabs)).check(matches(not(isDisplayed())));
}
@Test
public void testWorkTab_workTabListPopulatedBeforeGoingToTab() throws InterruptedException {
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(3, /* userId = */ 10);
- List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId = */ 10,
+ PERSONAL_USER_HANDLE);
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
+ sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos,
new ArrayList<>(workResolvedComponentInfos));
Intent sendIntent = createSendImageIntent();
- markWorkProfileUserAvailable();
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
waitForIdle();
@@ -376,8 +391,11 @@ public class ResolverActivityTest {
@Test
public void testWorkTab_workTabUsesExpectedAdapter() {
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
- List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10,
+ PERSONAL_USER_HANDLE);
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
+ sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
markWorkProfileUserAvailable();
@@ -393,11 +411,12 @@ public class ResolverActivityTest {
@Test
public void testWorkTab_personalTabUsesExpectedAdapter() {
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(3);
- List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ createResolvedComponentsForTestWithOtherProfile(3, PERSONAL_USER_HANDLE);
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
+ sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
- markWorkProfileUserAvailable();
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
waitForIdle();
@@ -411,8 +430,10 @@ public class ResolverActivityTest {
public void testWorkTab_workProfileHasExpectedNumberOfTargets() throws InterruptedException {
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
- List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10,
+ PERSONAL_USER_HANDLE);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
+ sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
@@ -429,13 +450,15 @@ public class ResolverActivityTest {
public void testWorkTab_selectingWorkTabAppOpensAppInWorkProfile() throws InterruptedException {
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
- List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10,
+ PERSONAL_USER_HANDLE);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
+ sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
ResolveInfo[] chosen = new ResolveInfo[1];
- sOverrides.onSafelyStartCallback = targetInfo -> {
- chosen[0] = targetInfo.getResolveInfo();
+ sOverrides.onSafelyStartInternalCallback = result -> {
+ chosen[0] = result.first.getResolveInfo();
return true;
};
@@ -447,7 +470,7 @@ public class ResolverActivityTest {
onView(first(allOf(withText(workResolvedComponentInfos.get(0)
.getResolveInfoAt(0).activityInfo.applicationInfo.name), isCompletelyDisplayed())))
.perform(click());
- onView(withId(R.id.button_once))
+ onView(withId(com.android.internal.R.id.button_once))
.perform(click());
waitForIdle();
@@ -459,8 +482,9 @@ public class ResolverActivityTest {
throws InterruptedException {
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(1);
- List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ createResolvedComponentsForTestWithOtherProfile(1, PERSONAL_USER_HANDLE);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
+ sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
@@ -477,16 +501,17 @@ public class ResolverActivityTest {
public void testWorkTab_headerIsVisibleInPersonalTab() {
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(1);
- List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ createResolvedComponentsForTestWithOtherProfile(1, PERSONAL_USER_HANDLE);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
+ sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createOpenWebsiteIntent();
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
waitForIdle();
- TextView headerText = activity.findViewById(R.id.title);
+ TextView headerText = activity.findViewById(com.android.internal.R.id.title);
String initialText = headerText.getText().toString();
- assertFalse(initialText.isEmpty(), "Header text is empty.");
+ assertFalse("Header text is empty.", initialText.isEmpty());
assertThat(headerText.getVisibility(), is(View.VISIBLE));
}
@@ -494,14 +519,15 @@ public class ResolverActivityTest {
public void testWorkTab_switchTabs_headerStaysSame() {
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(1);
- List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ createResolvedComponentsForTestWithOtherProfile(1, PERSONAL_USER_HANDLE);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
+ sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createOpenWebsiteIntent();
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
waitForIdle();
- TextView headerText = activity.findViewById(R.id.title);
+ TextView headerText = activity.findViewById(com.android.internal.R.id.title);
String initialText = headerText.getText().toString();
onView(withText(R.string.resolver_work_tab))
.perform(click());
@@ -519,13 +545,15 @@ public class ResolverActivityTest {
throws InterruptedException {
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(3, /* userId= */ 10);
- List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId= */ 10,
+ PERSONAL_USER_HANDLE);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
+ sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
ResolveInfo[] chosen = new ResolveInfo[1];
- sOverrides.onSafelyStartCallback = targetInfo -> {
- chosen[0] = targetInfo.getResolveInfo();
+ sOverrides.onSafelyStartInternalCallback = result -> {
+ chosen[0] = result.first.getResolveInfo();
return true;
};
@@ -539,7 +567,7 @@ public class ResolverActivityTest {
.getResolveInfoAt(0).activityInfo.applicationInfo.name),
isDisplayed())))
.perform(click());
- onView(withId(R.id.button_once))
+ onView(withId(com.android.internal.R.id.button_once))
.perform(click());
waitForIdle();
@@ -551,9 +579,11 @@ public class ResolverActivityTest {
markWorkProfileUserAvailable();
int workProfileTargets = 4;
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10,
+ PERSONAL_USER_HANDLE);
List<ResolvedComponentInfo> workResolvedComponentInfos =
- createResolvedComponentsForTest(workProfileTargets);
+ createResolvedComponentsForTest(workProfileTargets,
+ sOverrides.workProfileUserHandle);
sOverrides.hasCrossProfileIntents = false;
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
@@ -563,7 +593,7 @@ public class ResolverActivityTest {
waitForIdle();
onView(withText(R.string.resolver_work_tab)).perform(click());
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withId(com.android.internal.R.id.contentPanel))
.perform(swipeUp());
onView(withText(R.string.resolver_cross_profile_blocked))
@@ -575,9 +605,11 @@ public class ResolverActivityTest {
markWorkProfileUserAvailable();
int workProfileTargets = 4;
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10,
+ PERSONAL_USER_HANDLE);
List<ResolvedComponentInfo> workResolvedComponentInfos =
- createResolvedComponentsForTest(workProfileTargets);
+ createResolvedComponentsForTest(workProfileTargets,
+ sOverrides.workProfileUserHandle);
sOverrides.isQuietModeEnabled = true;
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
@@ -585,7 +617,7 @@ public class ResolverActivityTest {
mActivityRule.launchActivity(sendIntent);
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withId(com.android.internal.R.id.contentPanel))
.perform(swipeUp());
onView(withText(R.string.resolver_work_tab)).perform(click());
waitForIdle();
@@ -598,16 +630,16 @@ public class ResolverActivityTest {
public void testWorkTab_noWorkAppsAvailable_emptyStateShown() {
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTest(3);
+ createResolvedComponentsForTest(3, PERSONAL_USER_HANDLE);
List<ResolvedComponentInfo> workResolvedComponentInfos =
- createResolvedComponentsForTest(0);
+ createResolvedComponentsForTest(0, sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
mActivityRule.launchActivity(sendIntent);
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withId(com.android.internal.R.id.contentPanel))
.perform(swipeUp());
onView(withText(R.string.resolver_work_tab)).perform(click());
waitForIdle();
@@ -620,9 +652,9 @@ public class ResolverActivityTest {
public void testWorkTab_xProfileOff_noAppsAvailable_workOff_xProfileOffEmptyStateShown() {
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTest(3);
+ createResolvedComponentsForTest(3, PERSONAL_USER_HANDLE);
List<ResolvedComponentInfo> workResolvedComponentInfos =
- createResolvedComponentsForTest(0);
+ createResolvedComponentsForTest(0, sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
@@ -631,7 +663,7 @@ public class ResolverActivityTest {
mActivityRule.launchActivity(sendIntent);
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withId(com.android.internal.R.id.contentPanel))
.perform(swipeUp());
onView(withText(R.string.resolver_work_tab)).perform(click());
waitForIdle();
@@ -644,9 +676,9 @@ public class ResolverActivityTest {
public void testMiniResolver() {
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTest(1);
+ createResolvedComponentsForTest(1, PERSONAL_USER_HANDLE);
List<ResolvedComponentInfo> workResolvedComponentInfos =
- createResolvedComponentsForTest(1);
+ createResolvedComponentsForTest(1, sOverrides.workProfileUserHandle);
// Personal profile only has a browser
personalResolvedComponentInfos.get(0).getResolveInfoAt(0).handleAllWebDataURI = true;
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
@@ -655,16 +687,16 @@ public class ResolverActivityTest {
mActivityRule.launchActivity(sendIntent);
waitForIdle();
- onView(withId(R.id.open_cross_profile)).check(matches(isDisplayed()));
+ onView(withId(com.android.internal.R.id.open_cross_profile)).check(matches(isDisplayed()));
}
@Test
public void testMiniResolver_noCurrentProfileTarget() {
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTest(0);
+ createResolvedComponentsForTest(0, PERSONAL_USER_HANDLE);
List<ResolvedComponentInfo> workResolvedComponentInfos =
- createResolvedComponentsForTest(1);
+ createResolvedComponentsForTest(1, sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
@@ -678,7 +710,8 @@ public class ResolverActivityTest {
private void assertNotMiniResolver() {
try {
- onView(withId(R.id.open_cross_profile)).check(matches(isDisplayed()));
+ onView(withId(com.android.internal.R.id.open_cross_profile))
+ .check(matches(isDisplayed()));
} catch (NoMatchingViewException e) {
return;
}
@@ -689,9 +722,9 @@ public class ResolverActivityTest {
public void testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown() {
markWorkProfileUserAvailable();
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTest(3);
+ createResolvedComponentsForTest(3, PERSONAL_USER_HANDLE);
List<ResolvedComponentInfo> workResolvedComponentInfos =
- createResolvedComponentsForTest(0);
+ createResolvedComponentsForTest(0, sOverrides.workProfileUserHandle);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
@@ -699,7 +732,7 @@ public class ResolverActivityTest {
mActivityRule.launchActivity(sendIntent);
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withId(com.android.internal.R.id.contentPanel))
.perform(swipeUp());
onView(withText(R.string.resolver_work_tab)).perform(click());
waitForIdle();
@@ -709,27 +742,29 @@ public class ResolverActivityTest {
}
@Test
- public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_autolaunch() {
+ public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_doesNotAutoLaunch() {
markWorkProfileUserAvailable();
int workProfileTargets = 4;
List<ResolvedComponentInfo> personalResolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10);
+ createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10,
+ PERSONAL_USER_HANDLE);
List<ResolvedComponentInfo> workResolvedComponentInfos =
- createResolvedComponentsForTest(workProfileTargets);
+ createResolvedComponentsForTest(workProfileTargets,
+ sOverrides.workProfileUserHandle);
sOverrides.hasCrossProfileIntents = false;
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
ResolveInfo[] chosen = new ResolveInfo[1];
- sOverrides.onSafelyStartCallback = targetInfo -> {
- chosen[0] = targetInfo.getResolveInfo();
+ sOverrides.onSafelyStartInternalCallback = result -> {
+ chosen[0] = result.first.getResolveInfo();
return true;
};
mActivityRule.launchActivity(sendIntent);
waitForIdle();
- assertThat(chosen[0], is(personalResolvedComponentInfos.get(1).getResolveInfoAt(0)));
+ assertNull(chosen[0]);
}
@Test
@@ -740,14 +775,14 @@ public class ResolverActivityTest {
// chosen activity.
Intent sendIntent = createSendImageIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
- createResolvedComponentsForTest(2);
+ createResolvedComponentsForTest(2, PERSONAL_USER_HANDLE);
setupResolverControllers(resolvedComponentInfos);
when(sOverrides.resolverListController.getLastChosen())
.thenReturn(resolvedComponentInfos.get(1).getResolveInfoAt(0));
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
- Espresso.registerIdlingResources(activity.getAdapter().getLabelIdlingResource());
+ Espresso.registerIdlingResources(activity.getLabelIdlingResource());
waitForIdle();
// The other entry is filtered to the last used slot
@@ -756,6 +791,200 @@ public class ResolverActivityTest {
assertThat(activity.getAdapter().getPlaceholderCount(), is(2));
}
+ @Test
+ public void testClonedProfilePresent_personalAdapterIsSetWithPersonalProfile() {
+ // enable cloneProfile
+ markCloneProfileUserAvailable();
+ List<ResolvedComponentInfo> resolvedComponentInfos =
+ createResolvedComponentsWithCloneProfileForTest(
+ 3,
+ PERSONAL_USER_HANDLE,
+ sOverrides.cloneProfileUserHandle);
+ setupResolverControllers(resolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+
+ assertThat(activity.getCurrentUserHandle(), is(activity.getPersonalProfileUserHandle()));
+ assertThat(activity.getAdapter().getCount(), is(3));
+ }
+
+ @Test
+ public void testClonedProfilePresent_personalTabUsesExpectedAdapter() {
+ markWorkProfileUserAvailable();
+ // enable cloneProfile
+ markCloneProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsWithCloneProfileForTest(
+ 3,
+ PERSONAL_USER_HANDLE,
+ sOverrides.cloneProfileUserHandle);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4,
+ sOverrides.workProfileUserHandle);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+
+ assertThat(activity.getCurrentUserHandle(), is(activity.getPersonalProfileUserHandle()));
+ assertThat(activity.getAdapter().getCount(), is(3));
+ }
+
+ @Test
+ public void testClonedProfilePresent_layoutWithDefault_neverShown() throws Exception {
+ // enable cloneProfile
+ markCloneProfileUserAvailable();
+ Intent sendIntent = createSendImageIntent();
+ List<ResolvedComponentInfo> resolvedComponentInfos =
+ createResolvedComponentsWithCloneProfileForTest(
+ 2,
+ PERSONAL_USER_HANDLE,
+ sOverrides.cloneProfileUserHandle);
+
+ setupResolverControllers(resolvedComponentInfos);
+ when(sOverrides.resolverListController.getLastChosen())
+ .thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0));
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ Espresso.registerIdlingResources(activity.getLabelIdlingResource());
+ waitForIdle();
+
+ assertThat(activity.getAdapter().hasFilteredItem(), is(false));
+ assertThat(activity.getAdapter().getCount(), is(2));
+ assertThat(activity.getAdapter().getPlaceholderCount(), is(2));
+ }
+
+ @Test
+ public void testClonedProfilePresent_alwaysButtonDisabled() throws Exception {
+ // enable cloneProfile
+ markCloneProfileUserAvailable();
+ Intent sendIntent = createSendImageIntent();
+ List<ResolvedComponentInfo> resolvedComponentInfos =
+ createResolvedComponentsWithCloneProfileForTest(
+ 3,
+ PERSONAL_USER_HANDLE,
+ sOverrides.cloneProfileUserHandle);
+
+ setupResolverControllers(resolvedComponentInfos);
+ when(sOverrides.resolverListController.getLastChosen())
+ .thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0));
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+
+ // Confirm that the button bar is disabled by default
+ onView(withId(com.android.internal.R.id.button_once)).check(matches(not(isEnabled())));
+ onView(withId(com.android.internal.R.id.button_always)).check(matches(not(isEnabled())));
+
+ // Make a stable copy of the components as the original list may be modified
+ List<ResolvedComponentInfo> stableCopy =
+ createResolvedComponentsForTestWithOtherProfile(2, PERSONAL_USER_HANDLE);
+
+ onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
+ .perform(click());
+
+ onView(withId(com.android.internal.R.id.button_once)).check(matches(isEnabled()));
+ onView(withId(com.android.internal.R.id.button_always)).check(matches(not(isEnabled())));
+ }
+
+ @Test
+ public void testClonedProfilePresent_personalProfileActivityIsStartedInCorrectUser()
+ throws Exception {
+ markWorkProfileUserAvailable();
+ // enable cloneProfile
+ markCloneProfileUserAvailable();
+
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsWithCloneProfileForTest(
+ 3,
+ PERSONAL_USER_HANDLE,
+ sOverrides.cloneProfileUserHandle);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(3, sOverrides.workProfileUserHandle);
+ sOverrides.hasCrossProfileIntents = false;
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+ sendIntent.setType("TestType");
+ final UserHandle[] selectedActivityUserHandle = new UserHandle[1];
+ sOverrides.onSafelyStartInternalCallback = result -> {
+ selectedActivityUserHandle[0] = result.second;
+ return true;
+ };
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ onView(first(allOf(withText(personalResolvedComponentInfos.get(0)
+ .getResolveInfoAt(0).activityInfo.applicationInfo.name), isCompletelyDisplayed())))
+ .perform(click());
+ onView(withId(com.android.internal.R.id.button_once))
+ .perform(click());
+ waitForIdle();
+
+ assertThat(selectedActivityUserHandle[0], is(activity.getAdapter().getUserHandle()));
+ }
+
+ @Test
+ public void testClonedProfilePresent_workProfileActivityIsStartedInCorrectUser()
+ throws Exception {
+ markWorkProfileUserAvailable();
+ // enable cloneProfile
+ markCloneProfileUserAvailable();
+
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsWithCloneProfileForTest(
+ 3,
+ PERSONAL_USER_HANDLE,
+ sOverrides.cloneProfileUserHandle);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(3, sOverrides.workProfileUserHandle);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+ sendIntent.setType("TestType");
+ final UserHandle[] selectedActivityUserHandle = new UserHandle[1];
+ sOverrides.onSafelyStartInternalCallback = result -> {
+ selectedActivityUserHandle[0] = result.second;
+ return true;
+ };
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ onView(withText(R.string.resolver_work_tab))
+ .perform(click());
+ waitForIdle();
+ onView(first(allOf(withText(workResolvedComponentInfos.get(0)
+ .getResolveInfoAt(0).activityInfo.applicationInfo.name), isCompletelyDisplayed())))
+ .perform(click());
+ onView(withId(com.android.internal.R.id.button_once))
+ .perform(click());
+ waitForIdle();
+
+ assertThat(selectedActivityUserHandle[0], is(activity.getAdapter().getUserHandle()));
+ }
+
+ @Test
+ public void testClonedProfilePresent_personalProfileResolverComparatorHasCorrectUsers()
+ throws Exception {
+ // enable cloneProfile
+ markCloneProfileUserAvailable();
+ List<ResolvedComponentInfo> resolvedComponentInfos =
+ createResolvedComponentsWithCloneProfileForTest(
+ 3,
+ PERSONAL_USER_HANDLE,
+ sOverrides.cloneProfileUserHandle);
+ setupResolverControllers(resolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ List<UserHandle> result = activity
+ .getResolverRankerServiceUserHandleList(PERSONAL_USER_HANDLE);
+
+ assertThat(result.containsAll(Lists.newArrayList(PERSONAL_USER_HANDLE,
+ sOverrides.cloneProfileUserHandle)), is(true));
+ }
+
private Intent createSendImageIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
@@ -771,36 +1000,56 @@ public class ResolverActivityTest {
return sendIntent;
}
- private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
+ private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults,
+ UserHandle resolvedForUser) {
List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
for (int i = 0; i < numberOfResults; i++) {
- infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i, resolvedForUser));
+ }
+ return infoList;
+ }
+
+ private List<ResolvedComponentInfo> createResolvedComponentsWithCloneProfileForTest(
+ int numberOfResults,
+ UserHandle resolvedForPersonalUser,
+ UserHandle resolvedForClonedUser) {
+ List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
+ for (int i = 0; i < 1; i++) {
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
+ resolvedForPersonalUser));
+ }
+ for (int i = 1; i < numberOfResults; i++) {
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
+ resolvedForClonedUser));
}
return infoList;
}
private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
- int numberOfResults) {
+ int numberOfResults,
+ UserHandle resolvedForUser) {
List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
for (int i = 0; i < numberOfResults; i++) {
if (i == 0) {
- infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i));
+ infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i,
+ resolvedForUser));
} else {
- infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i, resolvedForUser));
}
}
return infoList;
}
private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
- int numberOfResults, int userId) {
+ int numberOfResults, int userId, UserHandle resolvedForUser) {
List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
for (int i = 0; i < numberOfResults; i++) {
if (i == 0) {
infoList.add(
- ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
+ ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId,
+ resolvedForUser));
} else {
- infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i, resolvedForUser));
}
}
return infoList;
@@ -819,6 +1068,10 @@ public class ResolverActivityTest {
setupResolverControllers(personalResolvedComponentInfos, new ArrayList<>());
}
+ private void markCloneProfileUserAvailable() {
+ ResolverWrapperActivity.sOverrides.cloneProfileUserHandle = UserHandle.of(11);
+ }
+
private void setupResolverControllers(
List<ResolvedComponentInfo> personalResolvedComponentInfos,
List<ResolvedComponentInfo> workResolvedComponentInfos) {
diff --git a/java/tests/src/com/android/intentresolver/ResolverDataProvider.java b/java/tests/src/com/android/intentresolver/ResolverDataProvider.java
index b6b32b5a..688dd867 100644
--- a/java/tests/src/com/android/intentresolver/ResolverDataProvider.java
+++ b/java/tests/src/com/android/intentresolver/ResolverDataProvider.java
@@ -43,6 +43,14 @@ public class ResolverDataProvider {
createResolveInfo(i, UserHandle.USER_CURRENT));
}
+ static ResolvedComponentInfo createResolvedComponentInfo(int i,
+ UserHandle resolvedForUser) {
+ return new ResolvedComponentInfo(
+ createComponentName(i),
+ createResolverIntent(i),
+ createResolveInfo(i, UserHandle.USER_CURRENT, resolvedForUser));
+ }
+
static ResolvedComponentInfo createResolvedComponentInfo(
ComponentName componentName, Intent intent) {
return new ResolvedComponentInfo(
@@ -51,6 +59,14 @@ public class ResolverDataProvider {
createResolveInfo(componentName, UserHandle.USER_CURRENT));
}
+ static ResolvedComponentInfo createResolvedComponentInfo(
+ ComponentName componentName, Intent intent, UserHandle resolvedForUser) {
+ return new ResolvedComponentInfo(
+ componentName,
+ intent,
+ createResolveInfo(componentName, UserHandle.USER_CURRENT, resolvedForUser));
+ }
+
static ResolvedComponentInfo createResolvedComponentInfoWithOtherId(int i) {
return new ResolvedComponentInfo(
createComponentName(i),
@@ -58,6 +74,14 @@ public class ResolverDataProvider {
createResolveInfo(i, USER_SOMEONE_ELSE));
}
+ static ResolvedComponentInfo createResolvedComponentInfoWithOtherId(int i,
+ UserHandle resolvedForUser) {
+ return new ResolvedComponentInfo(
+ createComponentName(i),
+ createResolverIntent(i),
+ createResolveInfo(i, USER_SOMEONE_ELSE, resolvedForUser));
+ }
+
static ResolvedComponentInfo createResolvedComponentInfoWithOtherId(int i, int userId) {
return new ResolvedComponentInfo(
createComponentName(i),
@@ -65,6 +89,14 @@ public class ResolverDataProvider {
createResolveInfo(i, userId));
}
+ static ResolvedComponentInfo createResolvedComponentInfoWithOtherId(int i,
+ int userId, UserHandle resolvedForUser) {
+ return new ResolvedComponentInfo(
+ createComponentName(i),
+ createResolverIntent(i),
+ createResolveInfo(i, userId, resolvedForUser));
+ }
+
public static ComponentName createComponentName(int i) {
final String name = "component" + i;
return new ComponentName("foo.bar." + name, name);
@@ -76,6 +108,13 @@ public class ResolverDataProvider {
resolveInfo.targetUserId = userId;
return resolveInfo;
}
+ public static ResolveInfo createResolveInfo(int i, int userId, UserHandle resolvedForUser) {
+ final ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = createActivityInfo(i);
+ resolveInfo.targetUserId = userId;
+ resolveInfo.userHandle = resolvedForUser;
+ return resolveInfo;
+ }
public static ResolveInfo createResolveInfo(ComponentName componentName, int userId) {
final ResolveInfo resolveInfo = new ResolveInfo();
@@ -84,6 +123,15 @@ public class ResolverDataProvider {
return resolveInfo;
}
+ public static ResolveInfo createResolveInfo(ComponentName componentName, int userId,
+ UserHandle resolvedForUser) {
+ final ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = createActivityInfo(componentName);
+ resolveInfo.targetUserId = userId;
+ resolveInfo.userHandle = resolvedForUser;
+ return resolveInfo;
+ }
+
static ActivityInfo createActivityInfo(int i) {
ActivityInfo ai = new ActivityInfo();
ai.name = "activity_name" + i;
diff --git a/java/tests/src/com/android/intentresolver/ResolverWrapperActivity.java b/java/tests/src/com/android/intentresolver/ResolverWrapperActivity.java
index d67b73af..401ede26 100644
--- a/java/tests/src/com/android/intentresolver/ResolverWrapperActivity.java
+++ b/java/tests/src/com/android/intentresolver/ResolverWrapperActivity.java
@@ -21,19 +21,27 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import android.app.usage.UsageStatsManager;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.test.espresso.idling.CountingIdlingResource;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.CrossProfileIntentsChecker;
-import com.android.intentresolver.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
+import com.android.intentresolver.chooser.DisplayResolveInfo;
+import com.android.intentresolver.chooser.SelectableTargetInfo;
import com.android.intentresolver.chooser.TargetInfo;
+import com.android.intentresolver.icons.TargetDataLoader;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Function;
/*
@@ -41,7 +49,9 @@ import java.util.function.Function;
*/
public class ResolverWrapperActivity extends ResolverActivity {
static final OverrideData sOverrides = new OverrideData();
- private UsageStatsManager mUsm;
+
+ private final CountingIdlingResource mLabelIdlingResource =
+ new CountingIdlingResource("LoadLabelTask");
public ResolverWrapperActivity() {
super(/* isIntentPicker= */ true);
@@ -54,11 +64,20 @@ public class ResolverWrapperActivity extends ResolverActivity {
return 1234;
}
+ public CountingIdlingResource getLabelIdlingResource() {
+ return mLabelIdlingResource;
+ }
+
@Override
- public ResolverListAdapter createResolverListAdapter(Context context,
- List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList,
- boolean filterLastUsed, UserHandle userHandle) {
- return new ResolverWrapperAdapter(
+ public ResolverListAdapter createResolverListAdapter(
+ Context context,
+ List<Intent> payloadIntents,
+ Intent[] initialIntents,
+ List<ResolveInfo> rList,
+ boolean filterLastUsed,
+ UserHandle userHandle,
+ TargetDataLoader targetDataLoader) {
+ return new ResolverListAdapter(
context,
payloadIntents,
initialIntents,
@@ -67,15 +86,9 @@ public class ResolverWrapperActivity extends ResolverActivity {
createListController(userHandle),
userHandle,
payloadIntents.get(0), // TODO: extract upstream
- this);
- }
-
- @Override
- protected MyUserIdProvider createMyUserIdProvider() {
- if (sOverrides.mMyUserIdProvider != null) {
- return sOverrides.mMyUserIdProvider;
- }
- return super.createMyUserIdProvider();
+ this,
+ userHandle,
+ new TargetDataLoaderWrapper(targetDataLoader, mLabelIdlingResource));
}
@Override
@@ -94,8 +107,8 @@ public class ResolverWrapperActivity extends ResolverActivity {
return super.createWorkProfileAvailabilityManager();
}
- ResolverWrapperAdapter getAdapter() {
- return (ResolverWrapperAdapter) mMultiProfilePagerAdapter.getActiveListAdapter();
+ ResolverListAdapter getAdapter() {
+ return mMultiProfilePagerAdapter.getActiveListAdapter();
}
ResolverListAdapter getPersonalListAdapter() {
@@ -118,12 +131,13 @@ public class ResolverWrapperActivity extends ResolverActivity {
}
@Override
- public void safelyStartActivity(TargetInfo cti) {
- if (sOverrides.onSafelyStartCallback != null &&
- sOverrides.onSafelyStartCallback.apply(cti)) {
+ public void safelyStartActivityInternal(TargetInfo cti, UserHandle user,
+ @Nullable Bundle options) {
+ if (sOverrides.onSafelyStartInternalCallback != null
+ && sOverrides.onSafelyStartInternalCallback.apply(new Pair<>(cti, user))) {
return;
}
- super.safelyStartActivity(cti);
+ super.safelyStartActivityInternal(cti, user, options);
}
@Override
@@ -152,10 +166,21 @@ public class ResolverWrapperActivity extends ResolverActivity {
}
@Override
+ protected UserHandle getCloneProfileUserHandle() {
+ return sOverrides.cloneProfileUserHandle;
+ }
+
+ @Override
public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
super.startActivityAsUser(intent, options, user);
}
+ @Override
+ protected List<UserHandle> getResolverRankerServiceUserHandleListInternal(UserHandle
+ userHandle) {
+ return super.getResolverRankerServiceUserHandleListInternal(userHandle);
+ }
+
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
@@ -164,25 +189,28 @@ public class ResolverWrapperActivity extends ResolverActivity {
static class OverrideData {
@SuppressWarnings("Since15")
public Function<PackageManager, PackageManager> createPackageManager;
- public Function<TargetInfo, Boolean> onSafelyStartCallback;
+ public Function<Pair<TargetInfo, UserHandle>, Boolean> onSafelyStartInternalCallback;
public ResolverListController resolverListController;
public ResolverListController workResolverListController;
public Boolean isVoiceInteraction;
public UserHandle workProfileUserHandle;
+ public UserHandle cloneProfileUserHandle;
+ public UserHandle tabOwnerUserHandleForLaunch;
public Integer myUserId;
public boolean hasCrossProfileIntents;
public boolean isQuietModeEnabled;
public WorkProfileAvailabilityManager mWorkProfileAvailability;
- public MyUserIdProvider mMyUserIdProvider;
public CrossProfileIntentsChecker mCrossProfileIntentsChecker;
public void reset() {
- onSafelyStartCallback = null;
+ onSafelyStartInternalCallback = null;
isVoiceInteraction = null;
createPackageManager = null;
resolverListController = mock(ResolverListController.class);
workResolverListController = mock(ResolverListController.class);
workProfileUserHandle = null;
+ cloneProfileUserHandle = null;
+ tabOwnerUserHandleForLaunch = null;
myUserId = null;
hasCrossProfileIntents = true;
isQuietModeEnabled = false;
@@ -212,16 +240,55 @@ public class ResolverWrapperActivity extends ResolverActivity {
}
};
- mMyUserIdProvider = new MyUserIdProvider() {
- @Override
- public int getMyUserId() {
- return myUserId != null ? myUserId : UserHandle.myUserId();
- }
- };
-
mCrossProfileIntentsChecker = mock(CrossProfileIntentsChecker.class);
when(mCrossProfileIntentsChecker.hasCrossProfileIntents(any(), anyInt(), anyInt()))
.thenAnswer(invocation -> hasCrossProfileIntents);
}
}
+
+ private static class TargetDataLoaderWrapper extends TargetDataLoader {
+ private final TargetDataLoader mTargetDataLoader;
+ private final CountingIdlingResource mLabelIdlingResource;
+
+ private TargetDataLoaderWrapper(
+ TargetDataLoader targetDataLoader, CountingIdlingResource labelIdlingResource) {
+ mTargetDataLoader = targetDataLoader;
+ mLabelIdlingResource = labelIdlingResource;
+ }
+
+ @Override
+ public void loadAppTargetIcon(
+ @NonNull DisplayResolveInfo info,
+ @NonNull UserHandle userHandle,
+ @NonNull Consumer<Drawable> callback) {
+ mTargetDataLoader.loadAppTargetIcon(info, userHandle, callback);
+ }
+
+ @Override
+ public void loadDirectShareIcon(
+ @NonNull SelectableTargetInfo info,
+ @NonNull UserHandle userHandle,
+ @NonNull Consumer<Drawable> callback) {
+ mTargetDataLoader.loadDirectShareIcon(info, userHandle, callback);
+ }
+
+ @Override
+ public void loadLabel(
+ @NonNull DisplayResolveInfo info,
+ @NonNull Consumer<CharSequence[]> callback) {
+ mLabelIdlingResource.increment();
+ mTargetDataLoader.loadLabel(
+ info,
+ (result) -> {
+ mLabelIdlingResource.decrement();
+ callback.accept(result);
+ });
+ }
+
+ @NonNull
+ @Override
+ public TargetPresentationGetter createPresentationGetter(@NonNull ResolveInfo info) {
+ return mTargetDataLoader.createPresentationGetter(info);
+ }
+ }
}
diff --git a/java/tests/src/com/android/intentresolver/ResolverWrapperAdapter.java b/java/tests/src/com/android/intentresolver/ResolverWrapperAdapter.java
deleted file mode 100644
index a53b41d1..00000000
--- a/java/tests/src/com/android/intentresolver/ResolverWrapperAdapter.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.intentresolver;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
-
-import androidx.test.espresso.idling.CountingIdlingResource;
-
-import com.android.intentresolver.chooser.DisplayResolveInfo;
-
-import java.util.List;
-
-public class ResolverWrapperAdapter extends ResolverListAdapter {
-
- private CountingIdlingResource mLabelIdlingResource =
- new CountingIdlingResource("LoadLabelTask");
-
- public ResolverWrapperAdapter(
- Context context,
- List<Intent> payloadIntents,
- Intent[] initialIntents,
- List<ResolveInfo> rList,
- boolean filterLastUsed,
- ResolverListController resolverListController,
- UserHandle userHandle,
- Intent targetIntent,
- ResolverListCommunicator resolverListCommunicator) {
- super(
- context,
- payloadIntents,
- initialIntents,
- rList,
- filterLastUsed,
- resolverListController,
- userHandle,
- targetIntent,
- resolverListCommunicator,
- false);
- }
-
- public CountingIdlingResource getLabelIdlingResource() {
- return mLabelIdlingResource;
- }
-
- @Override
- protected LoadLabelTask createLoadLabelTask(DisplayResolveInfo info) {
- return new LoadLabelWrapperTask(info);
- }
-
- class LoadLabelWrapperTask extends LoadLabelTask {
-
- protected LoadLabelWrapperTask(DisplayResolveInfo dri) {
- super(dri);
- }
-
- @Override
- protected void onPreExecute() {
- mLabelIdlingResource.increment();
- }
-
- @Override
- protected void onPostExecute(CharSequence[] result) {
- super.onPostExecute(result);
- mLabelIdlingResource.decrement();
- }
- }
-}
diff --git a/java/tests/src/com/android/intentresolver/ShortcutSelectionLogicTest.kt b/java/tests/src/com/android/intentresolver/ShortcutSelectionLogicTest.kt
index a8d6f978..9ddeed84 100644
--- a/java/tests/src/com/android/intentresolver/ShortcutSelectionLogicTest.kt
+++ b/java/tests/src/com/android/intentresolver/ShortcutSelectionLogicTest.kt
@@ -21,10 +21,12 @@ import android.content.Context
import android.content.Intent
import android.content.pm.ResolveInfo
import android.content.pm.ShortcutInfo
+import android.os.UserHandle
import android.service.chooser.ChooserTarget
import com.android.intentresolver.chooser.DisplayResolveInfo
import com.android.intentresolver.chooser.TargetInfo
import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
@@ -35,6 +37,9 @@ private const val CLASS_NAME = "./MainActivity"
@SmallTest
class ShortcutSelectionLogicTest {
+ private val PERSONAL_USER_HANDLE: UserHandle = InstrumentationRegistry
+ .getInstrumentation().getTargetContext().getUser()
+
private val packageTargets = HashMap<String, Array<ChooserTarget>>().apply {
arrayOf(PACKAGE_A, PACKAGE_B).forEach { pkg ->
// shortcuts in reverse priority order
@@ -52,7 +57,7 @@ class ShortcutSelectionLogicTest {
private val baseDisplayInfo = DisplayResolveInfo.newDisplayResolveInfo(
Intent(),
- ResolverDataProvider.createResolveInfo(3, 0),
+ ResolverDataProvider.createResolveInfo(3, 0, PERSONAL_USER_HANDLE),
"label",
"extended info",
Intent(),
@@ -60,7 +65,7 @@ class ShortcutSelectionLogicTest {
private val otherBaseDisplayInfo = DisplayResolveInfo.newDisplayResolveInfo(
Intent(),
- ResolverDataProvider.createResolveInfo(4, 0),
+ ResolverDataProvider.createResolveInfo(4, 0, PERSONAL_USER_HANDLE),
"label 2",
"extended info 2",
Intent(),
diff --git a/java/tests/src/com/android/intentresolver/TestContentPreviewViewModel.kt b/java/tests/src/com/android/intentresolver/TestContentPreviewViewModel.kt
new file mode 100644
index 00000000..d239f612
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/TestContentPreviewViewModel.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewmodel.CreationExtras
+import com.android.intentresolver.contentpreview.BasePreviewViewModel
+import com.android.intentresolver.contentpreview.ImageLoader
+import com.android.intentresolver.contentpreview.PreviewDataProvider
+
+/** A test content preview model that supports image loader override. */
+class TestContentPreviewViewModel(
+ private val viewModel: BasePreviewViewModel,
+ private val imageLoader: ImageLoader? = null,
+) : BasePreviewViewModel() {
+ override fun createOrReuseProvider(
+ chooserRequest: ChooserRequestParameters
+ ): PreviewDataProvider = viewModel.createOrReuseProvider(chooserRequest)
+
+ override fun createOrReuseImageLoader(): ImageLoader =
+ imageLoader ?: viewModel.createOrReuseImageLoader()
+
+ companion object {
+ fun wrap(
+ factory: ViewModelProvider.Factory,
+ imageLoader: ImageLoader?,
+ ): ViewModelProvider.Factory =
+ object : ViewModelProvider.Factory {
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(
+ modelClass: Class<T>,
+ extras: CreationExtras
+ ): T {
+ return TestContentPreviewViewModel(
+ factory.create(modelClass, extras) as BasePreviewViewModel,
+ imageLoader,
+ ) as T
+ }
+ }
+ }
+}
diff --git a/java/tests/src/com/android/intentresolver/TestContentProvider.kt b/java/tests/src/com/android/intentresolver/TestContentProvider.kt
new file mode 100644
index 00000000..b3b53baa
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/TestContentProvider.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver
+
+import android.content.ContentProvider
+import android.content.ContentValues
+import android.database.Cursor
+import android.net.Uri
+
+class TestContentProvider : ContentProvider() {
+ override fun query(
+ uri: Uri,
+ projection: Array<out String>?,
+ selection: String?,
+ selectionArgs: Array<out String>?,
+ sortOrder: String?
+ ): Cursor? = null
+
+ override fun getType(uri: Uri): String?
+ = runCatching {
+ uri.getQueryParameter("mimeType")
+ }.getOrNull()
+
+ override fun getStreamTypes(uri: Uri, mimeTypeFilter: String): Array<String>?
+ = runCatching {
+ uri.getQueryParameter("streamType")?.let { arrayOf(it) }
+ }.getOrNull()
+
+ override fun insert(uri: Uri, values: ContentValues?): Uri? = null
+
+ override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int = 0
+
+ override fun update(
+ uri: Uri,
+ values: ContentValues?,
+ selection: String?,
+ selectionArgs: Array<out String>?
+ ): Int = 0
+
+ override fun onCreate(): Boolean = true
+} \ No newline at end of file
diff --git a/java/tests/src/com/android/intentresolver/TestPreviewImageLoader.kt b/java/tests/src/com/android/intentresolver/TestPreviewImageLoader.kt
index cfe041dd..bf87ed8a 100644
--- a/java/tests/src/com/android/intentresolver/TestPreviewImageLoader.kt
+++ b/java/tests/src/com/android/intentresolver/TestPreviewImageLoader.kt
@@ -18,21 +18,16 @@ package com.android.intentresolver
import android.graphics.Bitmap
import android.net.Uri
+import androidx.lifecycle.Lifecycle
+import com.android.intentresolver.contentpreview.ImageLoader
import java.util.function.Consumer
-internal class TestPreviewImageLoader(
- private val imageLoader: ImageLoader,
- private val imageOverride: () -> Bitmap?
-) : ImageLoader {
- override fun loadImage(uri: Uri, callback: Consumer<Bitmap?>) {
- val override = imageOverride()
- if (override != null) {
- callback.accept(override)
- } else {
- imageLoader.loadImage(uri, callback)
- }
+internal class TestPreviewImageLoader(private val bitmaps: Map<Uri, Bitmap>) : ImageLoader {
+ override fun loadImage(callerLifecycle: Lifecycle, uri: Uri, callback: Consumer<Bitmap?>) {
+ callback.accept(bitmaps[uri])
}
- override suspend fun invoke(uri: Uri): Bitmap? = imageOverride() ?: imageLoader(uri)
+ override suspend fun invoke(uri: Uri, caching: Boolean): Bitmap? = bitmaps[uri]
+
override fun prePopulate(uris: List<Uri>) = Unit
}
diff --git a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
index 9ffd02d4..3ddd4394 100644
--- a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
+++ b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java
@@ -26,6 +26,7 @@ import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.hasSibling;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
@@ -79,6 +80,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
@@ -90,19 +92,21 @@ import android.util.HashedStringCache;
import android.util.Pair;
import android.util.SparseArray;
import android.view.View;
-import android.view.ViewGroup;
+import android.view.WindowManager;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.test.espresso.contrib.RecyclerViewActions;
import androidx.test.espresso.matcher.BoundedDiagnosingMatcher;
+import androidx.test.espresso.matcher.ViewMatchers;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import com.android.intentresolver.chooser.DisplayResolveInfo;
-import com.android.intentresolver.flags.Flags;
+import com.android.intentresolver.contentpreview.ImageLoader;
import com.android.intentresolver.shortcuts.ShortcutLoader;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -125,6 +129,7 @@ import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -155,6 +160,8 @@ public class UnbundledChooserActivityTest {
* --------
*/
+ private static final UserHandle PERSONAL_USER_HANDLE = InstrumentationRegistry
+ .getInstrumentation().getTargetContext().getUser();
private static final Function<PackageManager, PackageManager> DEFAULT_PM = pm -> pm;
private static final Function<PackageManager, PackageManager> NO_APP_PREDICTION_SERVICE_PM =
pm -> {
@@ -164,11 +171,7 @@ public class UnbundledChooserActivityTest {
};
private static final List<BooleanFlag> ALL_FLAGS =
- Arrays.asList(
- Flags.SHARESHEET_CUSTOM_ACTIONS,
- Flags.SHARESHEET_RESELECTION_ACTION,
- Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW,
- Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW);
+ Arrays.asList();
private static final Map<BooleanFlag, Boolean> ALL_FLAGS_OFF =
createAllFlagsOverride(false);
@@ -177,11 +180,20 @@ public class UnbundledChooserActivityTest {
@Parameterized.Parameters
public static Collection packageManagers() {
+ if (ALL_FLAGS.isEmpty()) {
+ // No flags to toggle between, so just two configurations.
+ return Arrays.asList(new Object[][] {
+ // Default PackageManager and all flags off
+ { DEFAULT_PM, ALL_FLAGS_OFF},
+ // No App Prediction Service and all flags off
+ { NO_APP_PREDICTION_SERVICE_PM, ALL_FLAGS_OFF },
+ });
+ }
return Arrays.asList(new Object[][] {
// Default PackageManager and all flags off
- { DEFAULT_PM, ALL_FLAGS_OFF },
+ { DEFAULT_PM, ALL_FLAGS_OFF},
// Default PackageManager and all flags on
- { DEFAULT_PM, ALL_FLAGS_ON },
+ { DEFAULT_PM, ALL_FLAGS_ON},
// No App Prediction Service and all flags off
{ NO_APP_PREDICTION_SERVICE_PM, ALL_FLAGS_OFF },
// No App Prediction Service and all flags on
@@ -350,7 +362,7 @@ public class UnbundledChooserActivityTest {
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "chooser test"));
waitForIdle();
onView(withId(android.R.id.title))
- .check(matches(withText(com.android.internal.R.string.whichSendApplication)));
+ .check(matches(withText(R.string.whichSendApplication)));
}
@Test
@@ -362,7 +374,7 @@ public class UnbundledChooserActivityTest {
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
onView(withId(android.R.id.title))
- .check(matches(withText(com.android.internal.R.string.whichSendApplication)));
+ .check(matches(withText(R.string.whichSendApplication)));
}
@Test
@@ -415,10 +427,12 @@ public class UnbundledChooserActivityTest {
@Test
public void visiblePreviewTitleAndThumbnail() throws InterruptedException {
String previewTitle = "My Content Preview Title";
- Intent sendIntent = createSendTextIntentWithPreview(previewTitle,
- Uri.parse("android.resource://com.android.frameworks.coretests/"
- + R.drawable.test320x240));
- ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
+ Uri uri = Uri.parse(
+ "android.resource://com.android.frameworks.coretests/"
+ + R.drawable.test320x240);
+ Intent sendIntent = createSendTextIntentWithPreview(previewTitle, uri);
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ createImageLoader(uri, createBitmap());
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
setupResolverControllers(resolvedComponentInfos);
@@ -445,7 +459,7 @@ public class UnbundledChooserActivityTest {
onView(withId(com.android.internal.R.id.profile_button)).check(doesNotExist());
ResolveInfo[] chosen = new ResolveInfo[1];
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -472,7 +486,7 @@ public class UnbundledChooserActivityTest {
List<ResolvedComponentInfo> infosToStack = new ArrayList<>();
for (int i = 0; i < 4; i++) {
ResolveInfo resolveInfo = ResolverDataProvider.createResolveInfo(i,
- UserHandle.USER_CURRENT);
+ UserHandle.USER_CURRENT, PERSONAL_USER_HANDLE);
resolveInfo.activityInfo.applicationInfo.name = appName;
resolveInfo.activityInfo.applicationInfo.packageName = packageName;
resolveInfo.activityInfo.packageName = packageName;
@@ -491,7 +505,7 @@ public class UnbundledChooserActivityTest {
assertThat(activity.getAdapter().getCount(), is(6));
ResolveInfo[] chosen = new ResolveInfo[1];
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -522,17 +536,21 @@ public class UnbundledChooserActivityTest {
verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1))
.topK(any(List.class), anyInt());
assertThat(activity.getIsSelected(), is(false));
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
return true;
};
ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
+ DisplayResolveInfo testDri =
+ activity.createTestDisplayResolveInfo(sendIntent, toChoose, "testLabel", "testInfo",
+ sendIntent, /* resolveInfoPresentationGetter */ null);
onView(withText(toChoose.activityInfo.name))
.perform(click());
waitForIdle();
verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1))
- .updateChooserCounts(Mockito.anyString(), anyInt(), Mockito.anyString());
+ .updateChooserCounts(Mockito.anyString(), any(UserHandle.class),
+ Mockito.anyString());
verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1))
- .updateModel(toChoose.activityInfo.getComponentName());
+ .updateModel(testDri);
assertThat(activity.getIsSelected(), is(true));
}
@@ -560,7 +578,7 @@ public class UnbundledChooserActivityTest {
@Test
public void autoLaunchSingleResult() throws InterruptedException {
ResolveInfo[] chosen = new ResolveInfo[1];
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -595,7 +613,7 @@ public class UnbundledChooserActivityTest {
assertThat(activity.getAdapter().getCount(), is(1));
ResolveInfo[] chosen = new ResolveInfo[1];
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -630,7 +648,7 @@ public class UnbundledChooserActivityTest {
assertThat(activity.getAdapter().getCount(), is(2));
ResolveInfo[] chosen = new ResolveInfo[1];
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -661,7 +679,7 @@ public class UnbundledChooserActivityTest {
assertThat(activity.getAdapter().getCount(), is(2));
ResolveInfo[] chosen = new ResolveInfo[1];
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -676,24 +694,21 @@ public class UnbundledChooserActivityTest {
}
@Test
- @RequireFeatureFlags(
- flags = { Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW_NAME },
- values = { true })
- public void testImagePlusTextSharing_ExcludeText() {
- Intent sendIntent = createSendImageIntent(
- Uri.parse("android.resource://com.android.frameworks.coretests/"
- + R.drawable.test320x240));
- ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
- ChooserActivityOverrideData.getInstance().isImageType = true;
+ @Ignore("b/285309527")
+ public void testFilePlusTextSharing_ExcludeText() {
+ Uri uri = createTestContentProviderUri(null, "image/png");
+ Intent sendIntent = createSendImageIntent(uri);
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ createImageLoader(uri, createBitmap());
sendIntent.putExtra(Intent.EXTRA_TEXT, "https://google.com/search?q=google");
List<ResolvedComponentInfo> resolvedComponentInfos = Arrays.asList(
ResolverDataProvider.createResolvedComponentInfo(
new ComponentName("org.imageviewer", "ImageTarget"),
- sendIntent),
+ sendIntent, PERSONAL_USER_HANDLE),
ResolverDataProvider.createResolvedComponentInfo(
new ComponentName("org.textviewer", "UriTarget"),
- new Intent("VIEW_TEXT"))
+ new Intent("VIEW_TEXT"), PERSONAL_USER_HANDLE)
);
setupResolverControllers(resolvedComponentInfos);
@@ -706,8 +721,10 @@ public class UnbundledChooserActivityTest {
.perform(click());
waitForIdle();
+ onView(withId(R.id.content_preview_text)).check(matches(withText("File only")));
+
AtomicReference<Intent> launchedIntentRef = new AtomicReference<>();
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
launchedIntentRef.set(targetInfo.getTargetIntent());
return true;
};
@@ -719,25 +736,22 @@ public class UnbundledChooserActivityTest {
}
@Test
- @RequireFeatureFlags(
- flags = { Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW_NAME },
- values = { true })
- public void testImagePlusTextSharing_RemoveAndAddBackText() {
- Intent sendIntent = createSendImageIntent(
- Uri.parse("android.resource://com.android.frameworks.coretests/"
- + R.drawable.test320x240));
- ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
- ChooserActivityOverrideData.getInstance().isImageType = true;
+ @Ignore("b/285309527")
+ public void testFilePlusTextSharing_RemoveAndAddBackText() {
+ Uri uri = createTestContentProviderUri("application/pdf", "image/png");
+ Intent sendIntent = createSendImageIntent(uri);
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ createImageLoader(uri, createBitmap());
final String text = "https://google.com/search?q=google";
sendIntent.putExtra(Intent.EXTRA_TEXT, text);
List<ResolvedComponentInfo> resolvedComponentInfos = Arrays.asList(
ResolverDataProvider.createResolvedComponentInfo(
new ComponentName("org.imageviewer", "ImageTarget"),
- sendIntent),
+ sendIntent, PERSONAL_USER_HANDLE),
ResolverDataProvider.createResolvedComponentInfo(
new ComponentName("org.textviewer", "UriTarget"),
- new Intent("VIEW_TEXT"))
+ new Intent("VIEW_TEXT"), PERSONAL_USER_HANDLE)
);
setupResolverControllers(resolvedComponentInfos);
@@ -749,12 +763,16 @@ public class UnbundledChooserActivityTest {
.check(matches(isDisplayed()))
.perform(click());
waitForIdle();
+ onView(withId(R.id.content_preview_text)).check(matches(withText("File only")));
+
onView(withId(R.id.include_text_action))
.perform(click());
waitForIdle();
+ onView(withId(R.id.content_preview_text)).check(matches(withText(text)));
+
AtomicReference<Intent> launchedIntentRef = new AtomicReference<>();
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
launchedIntentRef.set(targetInfo.getTargetIntent());
return true;
};
@@ -766,15 +784,12 @@ public class UnbundledChooserActivityTest {
}
@Test
- @RequireFeatureFlags(
- flags = { Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW_NAME },
- values = { true })
- public void testImagePlusTextSharing_TextExclusionDoesNotAffectAlternativeIntent() {
- Intent sendIntent = createSendImageIntent(
- Uri.parse("android.resource://com.android.frameworks.coretests/"
- + R.drawable.test320x240));
- ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
- ChooserActivityOverrideData.getInstance().isImageType = true;
+ @Ignore("b/285309527")
+ public void testFilePlusTextSharing_TextExclusionDoesNotAffectAlternativeIntent() {
+ Uri uri = createTestContentProviderUri("image/png", null);
+ Intent sendIntent = createSendImageIntent(uri);
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ createImageLoader(uri, createBitmap());
sendIntent.putExtra(Intent.EXTRA_TEXT, "https://google.com/search?q=google");
Intent alternativeIntent = createSendTextIntent();
@@ -784,10 +799,10 @@ public class UnbundledChooserActivityTest {
List<ResolvedComponentInfo> resolvedComponentInfos = Arrays.asList(
ResolverDataProvider.createResolvedComponentInfo(
new ComponentName("org.imageviewer", "ImageTarget"),
- sendIntent),
+ sendIntent, PERSONAL_USER_HANDLE),
ResolverDataProvider.createResolvedComponentInfo(
new ComponentName("org.textviewer", "UriTarget"),
- alternativeIntent)
+ alternativeIntent, PERSONAL_USER_HANDLE)
);
setupResolverControllers(resolvedComponentInfos);
@@ -801,7 +816,7 @@ public class UnbundledChooserActivityTest {
waitForIdle();
AtomicReference<Intent> launchedIntentRef = new AtomicReference<>();
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
launchedIntentRef.set(targetInfo.getTargetIntent());
return true;
};
@@ -813,6 +828,40 @@ public class UnbundledChooserActivityTest {
}
@Test
+ @Ignore("b/285309527")
+ public void testImagePlusTextSharing_failedThumbnailAndExcludedText_textChanges() {
+ Uri uri = createTestContentProviderUri("image/png", null);
+ Intent sendIntent = createSendImageIntent(uri);
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ new TestPreviewImageLoader(Collections.emptyMap());
+ sendIntent.putExtra(Intent.EXTRA_TEXT, "https://google.com/search?q=google");
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = Arrays.asList(
+ ResolverDataProvider.createResolvedComponentInfo(
+ new ComponentName("org.imageviewer", "ImageTarget"),
+ sendIntent, PERSONAL_USER_HANDLE),
+ ResolverDataProvider.createResolvedComponentInfo(
+ new ComponentName("org.textviewer", "UriTarget"),
+ new Intent("VIEW_TEXT"), PERSONAL_USER_HANDLE)
+ );
+
+ setupResolverControllers(resolvedComponentInfos);
+
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+
+ onView(withId(R.id.include_text_action))
+ .check(matches(isDisplayed()))
+ .perform(click());
+ waitForIdle();
+
+ onView(withId(R.id.image_view))
+ .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
+ onView(withId(R.id.content_preview_text))
+ .check(matches(allOf(isDisplayed(), withText("Image only"))));
+ }
+
+ @Test
public void copyTextToClipboard() throws Exception {
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -823,8 +872,8 @@ public class UnbundledChooserActivityTest {
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(com.android.internal.R.id.chooser_copy_button)).check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.chooser_copy_button)).perform(click());
+ onView(withId(R.id.copy)).check(matches(isDisplayed()));
+ onView(withId(R.id.copy)).perform(click());
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(
Context.CLIPBOARD_SERVICE);
ClipData clipData = clipboard.getPrimaryClip();
@@ -847,8 +896,8 @@ public class UnbundledChooserActivityTest {
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(com.android.internal.R.id.chooser_copy_button)).check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.chooser_copy_button)).perform(click());
+ onView(withId(R.id.copy)).check(matches(isDisplayed()));
+ onView(withId(R.id.copy)).perform(click());
ChooserActivityLogger logger = activity.getChooserActivityLogger();
verify(logger, times(1)).logActionSelected(eq(ChooserActivityLogger.SELECTION_TYPE_COPY));
@@ -876,13 +925,11 @@ public class UnbundledChooserActivityTest {
@Test @Ignore
- public void testEditImageLogs() throws Exception {
- Intent sendIntent = createSendImageIntent(
- Uri.parse("android.resource://com.android.frameworks.coretests/"
- + R.drawable.test320x240));
-
- ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
- ChooserActivityOverrideData.getInstance().isImageType = true;
+ public void testEditImageLogs() {
+ Uri uri = createTestContentProviderUri("image/png", null);
+ Intent sendIntent = createSendImageIntent(uri);
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ createImageLoader(uri, createBitmap());
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -901,113 +948,63 @@ public class UnbundledChooserActivityTest {
@Test
public void oneVisibleImagePreview() {
- Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
- + R.drawable.test320x240);
+ Uri uri = createTestContentProviderUri("image/png", null);
ArrayList<Uri> uris = new ArrayList<>();
uris.add(uri);
Intent sendIntent = createSendUriIntentWithPreview(uris);
- ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
- ChooserActivityOverrideData.getInstance().isImageType = true;
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ createImageLoader(uri, createWideBitmap());
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
setupResolverControllers(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(com.android.internal.R.id.content_preview_image_area))
+ onView(withId(R.id.scrollable_image_preview))
.check((view, exception) -> {
if (exception != null) {
throw exception;
}
- ViewGroup parent = (ViewGroup) view;
- ArrayList<View> visibleViews = new ArrayList<>();
- for (int i = 0, count = parent.getChildCount(); i < count; i++) {
- View child = parent.getChildAt(i);
- if (child.getVisibility() == View.VISIBLE) {
- visibleViews.add(child);
- }
- }
- assertThat(visibleViews.size(), is(1));
+ RecyclerView recyclerView = (RecyclerView) view;
+ assertThat(recyclerView.getAdapter().getItemCount(), is(1));
+ assertThat(recyclerView.getChildCount(), is(1));
+ View imageView = recyclerView.getChildAt(0);
+ Rect rect = new Rect();
+ boolean isPartiallyVisible = imageView.getGlobalVisibleRect(rect);
assertThat(
- "image preview view is fully visible",
- isDisplayed().matches(visibleViews.get(0)));
+ "image preview view is not fully visible",
+ isPartiallyVisible
+ && rect.width() == imageView.getWidth()
+ && rect.height() == imageView.getHeight());
});
}
@Test
- @RequireFeatureFlags(
- flags = { Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW_NAME },
- values = { false })
- public void twoVisibleImagePreview() {
- Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
- + R.drawable.test320x240);
+ public void allThumbnailsFailedToLoad_hidePreview() {
+ Uri uri = createTestContentProviderUri("image/jpg", null);
ArrayList<Uri> uris = new ArrayList<>();
uris.add(uri);
uris.add(uri);
Intent sendIntent = createSendUriIntentWithPreview(uris);
- ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
- ChooserActivityOverrideData.getInstance().isImageType = true;
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ new TestPreviewImageLoader(Collections.emptyMap());
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
setupResolverControllers(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(com.android.internal.R.id.content_preview_image_1_large))
- .check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.content_preview_image_2_large))
- .check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.content_preview_image_2_small))
- .check(matches(not(isDisplayed())));
- onView(withId(com.android.internal.R.id.content_preview_image_3_small))
- .check(matches(not(isDisplayed())));
- }
-
- @Test
- @RequireFeatureFlags(
- flags = { Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW_NAME },
- values = { false })
- public void threeOrMoreVisibleImagePreview() {
- Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
- + R.drawable.test320x240);
-
- ArrayList<Uri> uris = new ArrayList<>();
- uris.add(uri);
- uris.add(uri);
- uris.add(uri);
- uris.add(uri);
- uris.add(uri);
-
- Intent sendIntent = createSendUriIntentWithPreview(uris);
- ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
- ChooserActivityOverrideData.getInstance().isImageType = true;
-
- List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
-
- setupResolverControllers(resolvedComponentInfos);
- mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
- waitForIdle();
- onView(withId(com.android.internal.R.id.content_preview_image_1_large))
- .check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.content_preview_image_2_large))
- .check(matches(not(isDisplayed())));
- onView(withId(com.android.internal.R.id.content_preview_image_2_small))
- .check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.content_preview_image_3_small))
- .check(matches(isDisplayed()));
+ onView(withId(R.id.scrollable_image_preview))
+ .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
}
@Test
- @RequireFeatureFlags(
- flags = { Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW_NAME },
- values = { true })
public void testManyVisibleImagePreview_ScrollableImagePreview() {
- Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
- + R.drawable.test320x240);
+ Uri uri = createTestContentProviderUri("image/png", null);
ArrayList<Uri> uris = new ArrayList<>();
uris.add(uri);
@@ -1022,15 +1019,15 @@ public class UnbundledChooserActivityTest {
uris.add(uri);
Intent sendIntent = createSendUriIntentWithPreview(uris);
- ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
- ChooserActivityOverrideData.getInstance().isImageType = true;
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ createImageLoader(uri, createBitmap());
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
setupResolverControllers(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(com.android.internal.R.id.content_preview_image_area))
+ onView(withId(R.id.scrollable_image_preview))
.perform(RecyclerViewActions.scrollToLastPosition())
.check((view, exception) -> {
if (exception != null) {
@@ -1042,12 +1039,8 @@ public class UnbundledChooserActivityTest {
}
@Test
- @RequireFeatureFlags(
- flags = { Flags.SHARESHEET_IMAGE_AND_TEXT_PREVIEW_NAME },
- values = { true })
public void testImageAndTextPreview() {
- final Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
- + R.drawable.test320x240);
+ final Uri uri = createTestContentProviderUri("image/png", null);
final String sharedText = "text-" + System.currentTimeMillis();
ArrayList<Uri> uris = new ArrayList<>();
@@ -1055,8 +1048,8 @@ public class UnbundledChooserActivityTest {
Intent sendIntent = createSendUriIntentWithPreview(uris);
sendIntent.putExtra(Intent.EXTRA_TEXT, sharedText);
- ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
- ChooserActivityOverrideData.getInstance().isImageType = true;
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ createImageLoader(uri, createBitmap());
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -1068,6 +1061,38 @@ public class UnbundledChooserActivityTest {
}
@Test
+ public void testTextPreviewWhenTextIsSharedWithMultipleImages() {
+ final Uri uri = createTestContentProviderUri("image/png", null);
+ final String sharedText = "text-" + System.currentTimeMillis();
+
+ ArrayList<Uri> uris = new ArrayList<>();
+ uris.add(uri);
+ uris.add(uri);
+
+ Intent sendIntent = createSendUriIntentWithPreview(uris);
+ sendIntent.putExtra(Intent.EXTRA_TEXT, sharedText);
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ createImageLoader(uri, createBitmap());
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(
+ ChooserActivityOverrideData
+ .getInstance()
+ .resolverListController
+ .getResolversForIntentAsUser(
+ Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class),
+ Mockito.any(UserHandle.class)))
+ .thenReturn(resolvedComponentInfos);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ onView(withText(sharedText)).check(matches(isDisplayed()));
+ }
+
+ @Test
public void testOnCreateLogging() {
Intent sendIntent = createSendTextIntent();
sendIntent.setType(TEST_MIME_TYPE);
@@ -1127,15 +1152,14 @@ public class UnbundledChooserActivityTest {
@Test
public void testImagePreviewLogging() {
- Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
- + R.drawable.test320x240);
+ Uri uri = createTestContentProviderUri("image/png", null);
ArrayList<Uri> uris = new ArrayList<>();
uris.add(uri);
Intent sendIntent = createSendUriIntentWithPreview(uris);
- ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap();
- ChooserActivityOverrideData.getInstance().isImageType = true;
+ ChooserActivityOverrideData.getInstance().imageLoader =
+ createImageLoader(uri, createBitmap());
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -1162,12 +1186,9 @@ public class UnbundledChooserActivityTest {
setupResolverControllers(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(com.android.internal.R.id.content_preview_filename))
- .check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.content_preview_filename))
- .check(matches(withText("app.pdf")));
- onView(withId(com.android.internal.R.id.content_preview_file_icon))
- .check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf")));
+ onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
}
@@ -1187,12 +1208,11 @@ public class UnbundledChooserActivityTest {
setupResolverControllers(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(com.android.internal.R.id.content_preview_filename))
- .check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.content_preview_filename))
- .check(matches(withText("app.pdf + 2 files")));
- onView(withId(com.android.internal.R.id.content_preview_file_icon))
- .check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf")));
+ onView(withId(R.id.content_preview_more_files)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_more_files)).check(matches(withText("+ 2 more files")));
+ onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
}
@Test
@@ -1211,12 +1231,9 @@ public class UnbundledChooserActivityTest {
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(com.android.internal.R.id.content_preview_filename))
- .check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.content_preview_filename))
- .check(matches(withText("app.pdf")));
- onView(withId(com.android.internal.R.id.content_preview_file_icon))
- .check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf")));
+ onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
}
@Test
@@ -1242,12 +1259,11 @@ public class UnbundledChooserActivityTest {
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(com.android.internal.R.id.content_preview_filename))
- .check(matches(isDisplayed()));
- onView(withId(com.android.internal.R.id.content_preview_filename))
- .check(matches(withText("app.pdf + 1 file")));
- onView(withId(com.android.internal.R.id.content_preview_file_icon))
- .check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf")));
+ onView(withId(R.id.content_preview_more_files)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_more_files)).check(matches(withText("+ 1 more file")));
+ onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
}
@Test
@@ -1271,8 +1287,12 @@ public class UnbundledChooserActivityTest {
waitForIdle();
final DisplayResolveInfo testDri =
- activity.createTestDisplayResolveInfo(sendIntent,
- ResolverDataProvider.createResolveInfo(3, 0), "testLabel", "testInfo", sendIntent,
+ activity.createTestDisplayResolveInfo(
+ sendIntent,
+ ResolverDataProvider.createResolveInfo(3, 0, PERSONAL_USER_HANDLE),
+ "testLabel",
+ "testInfo",
+ sendIntent,
/* resolveInfoPresentationGetter */ null);
final ChooserListAdapter adapter = activity.getAdapter();
@@ -1305,7 +1325,7 @@ public class UnbundledChooserActivityTest {
// verify that ShortcutLoader was queried
ArgumentCaptor<DisplayResolveInfo[]> appTargets =
ArgumentCaptor.forClass(DisplayResolveInfo[].class);
- verify(shortcutLoaders.get(0).first, times(1)).queryShortcuts(appTargets.capture());
+ verify(shortcutLoaders.get(0).first, times(1)).updateAppTargets(appTargets.capture());
// send shortcuts
assertThat(
@@ -1386,7 +1406,7 @@ public class UnbundledChooserActivityTest {
// verify that ShortcutLoader was queried
ArgumentCaptor<DisplayResolveInfo[]> appTargets =
ArgumentCaptor.forClass(DisplayResolveInfo[].class);
- verify(shortcutLoaders.get(0).first, times(1)).queryShortcuts(appTargets.capture());
+ verify(shortcutLoaders.get(0).first, times(1)).updateAppTargets(appTargets.capture());
// send shortcuts
assertThat(
@@ -1471,7 +1491,7 @@ public class UnbundledChooserActivityTest {
// verify that ShortcutLoader was queried
ArgumentCaptor<DisplayResolveInfo[]> appTargets =
ArgumentCaptor.forClass(DisplayResolveInfo[].class);
- verify(shortcutLoaders.get(0).first, times(1)).queryShortcuts(appTargets.capture());
+ verify(shortcutLoaders.get(0).first, times(1)).updateAppTargets(appTargets.capture());
// send shortcuts
assertThat(
@@ -1546,7 +1566,7 @@ public class UnbundledChooserActivityTest {
// verify that ShortcutLoader was queried
ArgumentCaptor<DisplayResolveInfo[]> appTargets =
ArgumentCaptor.forClass(DisplayResolveInfo[].class);
- verify(shortcutLoaders.get(0).first, times(1)).queryShortcuts(appTargets.capture());
+ verify(shortcutLoaders.get(0).first, times(1)).updateAppTargets(appTargets.capture());
// send shortcuts
assertThat(
@@ -1611,7 +1631,8 @@ public class UnbundledChooserActivityTest {
// We need app targets for direct targets to get displayed
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
- setupResolverControllers(resolvedComponentInfos);
+ setupResolverControllers(resolvedComponentInfos, resolvedComponentInfos);
+ markWorkProfileUserAvailable();
// set caller-provided target
Intent chooserIntent = Intent.createChooser(createSendTextIntent(), null);
@@ -1638,7 +1659,7 @@ public class UnbundledChooserActivityTest {
// verify that ShortcutLoader was queried
ArgumentCaptor<DisplayResolveInfo[]> appTargets =
ArgumentCaptor.forClass(DisplayResolveInfo[].class);
- verify(shortcutLoaders.get(0).first, times(1)).queryShortcuts(appTargets.capture());
+ verify(shortcutLoaders.get(0).first, times(1)).updateAppTargets(appTargets.capture());
// send shortcuts
assertThat(
@@ -1667,12 +1688,20 @@ public class UnbundledChooserActivityTest {
"The display label must match",
activeAdapter.getItem(0).getDisplayLabel(),
is(callerTargetLabel));
+
+ // Switch to work profile and ensure that the target *doesn't* show up there.
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+
+ for (int i = 0; i < activity.getWorkListAdapter().getCount(); i++) {
+ assertThat(
+ "Chooser target should not show up in opposite profile",
+ activity.getWorkListAdapter().getItem(i).getDisplayLabel(),
+ not(callerTargetLabel));
+ }
}
@Test
- @RequireFeatureFlags(
- flags = { Flags.SHARESHEET_CUSTOM_ACTIONS_NAME },
- values = { true })
public void testLaunchWithCustomAction() throws InterruptedException {
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
setupResolverControllers(resolvedComponentInfos);
@@ -1716,9 +1745,6 @@ public class UnbundledChooserActivityTest {
}
@Test
- @RequireFeatureFlags(
- flags = { Flags.SHARESHEET_RESELECTION_ACTION_NAME },
- values = { true })
public void testLaunchWithShareModification() throws InterruptedException {
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
setupResolverControllers(resolvedComponentInfos);
@@ -1726,13 +1752,17 @@ public class UnbundledChooserActivityTest {
Context testContext = InstrumentationRegistry.getInstrumentation().getContext();
final String modifyShareAction = "test-broadcast-receiver-action";
Intent chooserIntent = Intent.createChooser(createSendTextIntent(), null);
+ String label = "modify share";
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ testContext,
+ 123,
+ new Intent(modifyShareAction),
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);
+ ChooserAction action = new ChooserAction.Builder(Icon.createWithBitmap(
+ createBitmap()), label, pendingIntent).build();
chooserIntent.putExtra(
Intent.EXTRA_CHOOSER_MODIFY_SHARE_ACTION,
- PendingIntent.getBroadcast(
- testContext,
- 123,
- new Intent(modifyShareAction),
- PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT));
+ action);
// Start activity
mActivityRule.launchActivity(chooserIntent);
waitForIdle();
@@ -1747,7 +1777,7 @@ public class UnbundledChooserActivityTest {
testContext.registerReceiver(testReceiver, new IntentFilter(modifyShareAction));
try {
- onView(withText(R.string.select_text)).perform(click());
+ onView(withText(label)).perform(click());
broadcastInvoked.await();
} finally {
testContext.unregisterReceiver(testReceiver);
@@ -1810,7 +1840,7 @@ public class UnbundledChooserActivityTest {
// Create direct share target
List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
resolvedComponentInfos.get(14).getResolveInfoAt(0).activityInfo.packageName);
- ResolveInfo ri = ResolverDataProvider.createResolveInfo(16, 0);
+ ResolveInfo ri = ResolverDataProvider.createResolveInfo(16, 0, PERSONAL_USER_HANDLE);
// Start activity
final IChooserWrapper wrapper = (IChooserWrapper)
@@ -1943,7 +1973,7 @@ public class UnbundledChooserActivityTest {
Intent sendIntent = createSendTextIntent();
sendIntent.setType(TEST_MIME_TYPE);
ResolveInfo[] chosen = new ResolveInfo[1];
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -2099,7 +2129,7 @@ public class UnbundledChooserActivityTest {
onView(withId(com.android.internal.R.id.profile_button)).check(doesNotExist());
ResolveInfo[] chosen = new ResolveInfo[1];
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -2139,7 +2169,7 @@ public class UnbundledChooserActivityTest {
ArgumentCaptor<DisplayResolveInfo[]> appTargets =
ArgumentCaptor.forClass(DisplayResolveInfo[].class);
verify(shortcutLoaders.get(0).first, times(1))
- .queryShortcuts(appTargets.capture());
+ .updateAppTargets(appTargets.capture());
// send shortcuts
assertThat(
@@ -2220,7 +2250,7 @@ public class UnbundledChooserActivityTest {
ArgumentCaptor<DisplayResolveInfo[]> appTargets =
ArgumentCaptor.forClass(DisplayResolveInfo[].class);
verify(shortcutLoaders.get(0).first, times(1))
- .queryShortcuts(appTargets.capture());
+ .updateAppTargets(appTargets.capture());
// send shortcuts
List<ChooserTarget> serviceTargets = createDirectShareTargets(
@@ -2315,7 +2345,7 @@ public class UnbundledChooserActivityTest {
}
@Test
- public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_autolaunch() {
+ public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_doesNotAutoLaunch() {
markWorkProfileUserAvailable();
int workProfileTargets = 4;
List<ResolvedComponentInfo> personalResolvedComponentInfos =
@@ -2326,7 +2356,7 @@ public class UnbundledChooserActivityTest {
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendTextIntent();
ResolveInfo[] chosen = new ResolveInfo[1];
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -2334,7 +2364,7 @@ public class UnbundledChooserActivityTest {
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "Test"));
waitForIdle();
- assertThat(chosen[0], is(personalResolvedComponentInfos.get(1).getResolveInfoAt(0)));
+ assertNull(chosen[0]);
}
@Test
@@ -2345,7 +2375,7 @@ public class UnbundledChooserActivityTest {
Intent chooserIntent = createChooserIntent(createSendTextIntent(),
new Intent[] {new Intent("action.fake")});
ResolveInfo[] chosen = new ResolveInfo[1];
- ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
+ ChooserActivityOverrideData.getInstance().onSafelyStartInternalCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
return true;
};
@@ -2473,7 +2503,7 @@ public class UnbundledChooserActivityTest {
new Intent[] {new Intent("action.fake")});
ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class);
ResolveInfo ri = ResolverDataProvider.createResolveInfo(0,
- UserHandle.USER_CURRENT);
+ UserHandle.USER_CURRENT, PERSONAL_USER_HANDLE);
when(
ChooserActivityOverrideData
.getInstance()
@@ -2515,12 +2545,52 @@ public class UnbundledChooserActivityTest {
.perform(swipeUp());
waitForIdle();
- verify(personalProfileShortcutLoader, times(1)).queryShortcuts(any());
+ verify(personalProfileShortcutLoader, times(1)).updateAppTargets(any());
onView(withText(R.string.resolver_work_tab)).perform(click());
waitForIdle();
- verify(workProfileShortcutLoader, times(1)).queryShortcuts(any());
+ verify(workProfileShortcutLoader, times(1)).updateAppTargets(any());
+ }
+
+ @Test
+ public void testClonedProfilePresent_personalAdapterIsSetWithPersonalProfile() {
+ // enable cloneProfile
+ markCloneProfileUserAvailable();
+ List<ResolvedComponentInfo> resolvedComponentInfos =
+ createResolvedComponentsWithCloneProfileForTest(
+ 3,
+ PERSONAL_USER_HANDLE,
+ ChooserActivityOverrideData.getInstance().cloneProfileUserHandle);
+ setupResolverControllers(resolvedComponentInfos);
+ Intent sendIntent = createSendTextIntent();
+
+ final IChooserWrapper activity = (IChooserWrapper) mActivityRule
+ .launchActivity(Intent.createChooser(sendIntent, "personalProfileTest"));
+ waitForIdle();
+
+ assertThat(activity.getPersonalListAdapter().getUserHandle(), is(PERSONAL_USER_HANDLE));
+ assertThat(activity.getAdapter().getCount(), is(3));
+ }
+
+ @Test
+ public void testClonedProfilePresent_personalTabUsesExpectedAdapter() {
+ markWorkProfileUserAvailable();
+ markCloneProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(
+ 4);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType(TEST_MIME_TYPE);
+
+
+ final IChooserWrapper activity = (IChooserWrapper)
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "multi tab test"));
+ waitForIdle();
+
+ assertThat(activity.getCurrentUserHandle(), is(PERSONAL_USER_HANDLE));
}
private Intent createChooserIntent(Intent intent, Intent[] initialIntents) {
@@ -2557,6 +2627,7 @@ public class UnbundledChooserActivityTest {
ri.activityInfo.packageName = "fake.package.name";
ri.activityInfo.applicationInfo = new ApplicationInfo();
ri.activityInfo.applicationInfo.packageName = "fake.package.name";
+ ri.userHandle = UserHandle.CURRENT;
return ri;
}
@@ -2581,6 +2652,21 @@ public class UnbundledChooserActivityTest {
return sendIntent;
}
+ private Uri createTestContentProviderUri(
+ @Nullable String mimeType, @Nullable String streamType) {
+ String packageName =
+ InstrumentationRegistry.getInstrumentation().getContext().getPackageName();
+ Uri.Builder builder = Uri.parse("content://" + packageName + "/image.png")
+ .buildUpon();
+ if (mimeType != null) {
+ builder.appendQueryParameter("mimeType", mimeType);
+ }
+ if (streamType != null) {
+ builder.appendQueryParameter("streamType", streamType);
+ }
+ return builder.build();
+ }
+
private Intent createSendTextIntentWithPreview(String title, Uri imageThumbnail) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
@@ -2618,7 +2704,23 @@ public class UnbundledChooserActivityTest {
private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
for (int i = 0; i < numberOfResults; i++) {
- infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i, PERSONAL_USER_HANDLE));
+ }
+ return infoList;
+ }
+
+ private List<ResolvedComponentInfo> createResolvedComponentsWithCloneProfileForTest(
+ int numberOfResults,
+ UserHandle resolvedForPersonalUser,
+ UserHandle resolvedForClonedUser) {
+ List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
+ for (int i = 0; i < 1; i++) {
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
+ resolvedForPersonalUser));
+ }
+ for (int i = 1; i < numberOfResults; i++) {
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
+ resolvedForClonedUser));
}
return infoList;
}
@@ -2628,9 +2730,11 @@ public class UnbundledChooserActivityTest {
List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
for (int i = 0; i < numberOfResults; i++) {
if (i == 0) {
- infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i));
+ infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i,
+ PERSONAL_USER_HANDLE));
} else {
- infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
+ PERSONAL_USER_HANDLE));
}
}
return infoList;
@@ -2642,9 +2746,11 @@ public class UnbundledChooserActivityTest {
for (int i = 0; i < numberOfResults; i++) {
if (i == 0) {
infoList.add(
- ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
+ ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId,
+ PERSONAL_USER_HANDLE));
} else {
- infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i,
+ PERSONAL_USER_HANDLE));
}
}
return infoList;
@@ -2654,7 +2760,8 @@ public class UnbundledChooserActivityTest {
int numberOfResults, int userId) {
List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
for (int i = 0; i < numberOfResults; i++) {
- infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
+ infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId,
+ PERSONAL_USER_HANDLE));
}
return infoList;
}
@@ -2686,8 +2793,22 @@ public class UnbundledChooserActivityTest {
}
private Bitmap createBitmap() {
- int width = 200;
- int height = 200;
+ return createBitmap(200, 200);
+ }
+
+ private Bitmap createWideBitmap() {
+ WindowManager windowManager = InstrumentationRegistry.getInstrumentation()
+ .getTargetContext()
+ .getSystemService(WindowManager.class);
+ int width = 3000;
+ if (windowManager != null) {
+ Rect bounds = windowManager.getMaximumWindowMetrics().getBounds();
+ width = bounds.width() + 200;
+ }
+ return createBitmap(width, 100);
+ }
+
+ private Bitmap createBitmap(int width, int height) {
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
@@ -2733,6 +2854,10 @@ public class UnbundledChooserActivityTest {
ChooserActivityOverrideData.getInstance().workProfileUserHandle = UserHandle.of(10);
}
+ private void markCloneProfileUserAvailable() {
+ ChooserActivityOverrideData.getInstance().cloneProfileUserHandle = UserHandle.of(11);
+ }
+
private void setupResolverControllers(
List<ResolvedComponentInfo> personalResolvedComponentInfos) {
setupResolverControllers(personalResolvedComponentInfos, new ArrayList<>());
@@ -2839,4 +2964,8 @@ public class UnbundledChooserActivityTest {
};
return shortcutLoaders;
}
+
+ private static ImageLoader createImageLoader(Uri uri, Bitmap bitmap) {
+ return new TestPreviewImageLoader(Collections.singletonMap(uri, bitmap));
+ }
}
diff --git a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityWorkProfileTest.java b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityWorkProfileTest.java
index 87dc1b9d..92bccb7d 100644
--- a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityWorkProfileTest.java
+++ b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityWorkProfileTest.java
@@ -49,7 +49,6 @@ import androidx.test.espresso.NoMatchingViewException;
import androidx.test.rule.ActivityTestRule;
import com.android.intentresolver.UnbundledChooserActivityWorkProfileTest.TestCase.Tab;
-import com.android.internal.R;
import junit.framework.AssertionFailedError;
@@ -99,7 +98,7 @@ public class UnbundledChooserActivityWorkProfileTest {
public void testBlocker() {
setUpPersonalAndWorkComponentInfos();
sOverrides.hasCrossProfileIntents = mTestCase.hasCrossProfileIntents();
- sOverrides.myUserId = mTestCase.getMyUserHandle().getIdentifier();
+ sOverrides.tabOwnerUserHandleForLaunch = mTestCase.getMyUserHandle();
launchActivity(mTestCase.getIsSendAction());
switchToTab(mTestCase.getTab());
@@ -242,19 +241,21 @@ public class UnbundledChooserActivityWorkProfileTest {
}
private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
- int numberOfResults, int userId) {
+ int numberOfResults, int userId, UserHandle resolvedForUser) {
List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
for (int i = 0; i < numberOfResults; i++) {
infoList.add(
- ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
+ ResolverDataProvider
+ .createResolvedComponentInfoWithOtherId(i, userId, resolvedForUser));
}
return infoList;
}
- private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
+ private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults,
+ UserHandle resolvedForUser) {
List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
for (int i = 0; i < numberOfResults; i++) {
- infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+ infoList.add(ResolverDataProvider.createResolvedComponentInfo(i, resolvedForUser));
}
return infoList;
}
@@ -264,9 +265,9 @@ public class UnbundledChooserActivityWorkProfileTest {
int workProfileTargets = 4;
List<ResolvedComponentInfo> personalResolvedComponentInfos =
createResolvedComponentsForTestWithOtherProfile(3,
- /* userId */ WORK_USER_HANDLE.getIdentifier());
+ /* userId */ WORK_USER_HANDLE.getIdentifier(), PERSONAL_USER_HANDLE);
List<ResolvedComponentInfo> workResolvedComponentInfos =
- createResolvedComponentsForTest(workProfileTargets);
+ createResolvedComponentsForTest(workProfileTargets, WORK_USER_HANDLE);
setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
}
@@ -356,7 +357,7 @@ public class UnbundledChooserActivityWorkProfileTest {
}
});
- onView(withId(R.id.contentPanel))
+ onView(withId(com.android.internal.R.id.contentPanel))
.perform(swipeUp());
waitForIdle();
}
diff --git a/java/tests/src/com/android/intentresolver/chooser/ImmutableTargetInfoTest.kt b/java/tests/src/com/android/intentresolver/chooser/ImmutableTargetInfoTest.kt
index dff1e5ae..504cfd97 100644
--- a/java/tests/src/com/android/intentresolver/chooser/ImmutableTargetInfoTest.kt
+++ b/java/tests/src/com/android/intentresolver/chooser/ImmutableTargetInfoTest.kt
@@ -30,14 +30,18 @@ import com.android.intentresolver.ResolverActivity
import com.android.intentresolver.ResolverDataProvider
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import androidx.test.platform.app.InstrumentationRegistry
class ImmutableTargetInfoTest {
+ private val PERSONAL_USER_HANDLE: UserHandle = InstrumentationRegistry
+ .getInstrumentation().getTargetContext().getUser()
+
private val resolvedIntent = Intent("resolved")
private val targetIntent = Intent("target")
private val referrerFillInIntent = Intent("referrer_fillin")
private val resolvedComponentName = ComponentName("resolved", "component")
private val chooserTargetComponentName = ComponentName("chooser", "target")
- private val resolveInfo = ResolverDataProvider.createResolveInfo(1, 0)
+ private val resolveInfo = ResolverDataProvider.createResolveInfo(1, 0, PERSONAL_USER_HANDLE)
private val displayLabel: CharSequence = "Display Label"
private val extendedInfo: CharSequence = "Extended Info"
private val displayIconHolder: TargetInfo.IconHolder = mock()
@@ -45,14 +49,14 @@ class ImmutableTargetInfoTest {
private val sourceIntent2 = Intent("source2")
private val displayTarget1 = DisplayResolveInfo.newDisplayResolveInfo(
Intent("display1"),
- ResolverDataProvider.createResolveInfo(2, 0),
+ ResolverDataProvider.createResolveInfo(2, 0, PERSONAL_USER_HANDLE),
"display1 label",
"display1 extended info",
Intent("display1_resolved"),
/* resolveInfoPresentationGetter= */ null)
private val displayTarget2 = DisplayResolveInfo.newDisplayResolveInfo(
Intent("display2"),
- ResolverDataProvider.createResolveInfo(3, 0),
+ ResolverDataProvider.createResolveInfo(3, 0, PERSONAL_USER_HANDLE),
"display2 label",
"display2 extended info",
Intent("display2_resolved"),
@@ -66,7 +70,7 @@ class ImmutableTargetInfoTest {
UserHandle.CURRENT)
private val displayResolveInfo = DisplayResolveInfo.newDisplayResolveInfo(
Intent("displayresolve"),
- ResolverDataProvider.createResolveInfo(5, 0),
+ ResolverDataProvider.createResolveInfo(5, 0, PERSONAL_USER_HANDLE),
"displayresolve label",
"displayresolve extended info",
Intent("display_resolved"),
diff --git a/java/tests/src/com/android/intentresolver/chooser/TargetInfoTest.kt b/java/tests/src/com/android/intentresolver/chooser/TargetInfoTest.kt
index 3d832cc9..f9d3dd96 100644
--- a/java/tests/src/com/android/intentresolver/chooser/TargetInfoTest.kt
+++ b/java/tests/src/com/android/intentresolver/chooser/TargetInfoTest.kt
@@ -41,6 +41,9 @@ import org.mockito.Mockito.times
import org.mockito.Mockito.verify
class TargetInfoTest {
+ private val PERSONAL_USER_HANDLE: UserHandle = InstrumentationRegistry
+ .getInstrumentation().getTargetContext().getUser()
+
private val context = InstrumentationRegistry.getInstrumentation().getContext()
@Before
@@ -81,7 +84,7 @@ class TargetInfoTest {
val resolvedIntent = Intent()
val baseDisplayInfo = DisplayResolveInfo.newDisplayResolveInfo(
resolvedIntent,
- ResolverDataProvider.createResolveInfo(1, 0),
+ ResolverDataProvider.createResolveInfo(1, 0, PERSONAL_USER_HANDLE),
"label",
"extended info",
resolvedIntent,
@@ -190,7 +193,7 @@ class TargetInfoTest {
intent.putExtra(Intent.EXTRA_TEXT, "testing intent sending")
intent.setType("text/plain")
- val resolveInfo = ResolverDataProvider.createResolveInfo(3, 0)
+ val resolveInfo = ResolverDataProvider.createResolveInfo(3, 0, PERSONAL_USER_HANDLE)
val targetInfo = DisplayResolveInfo.newDisplayResolveInfo(
intent,
@@ -268,7 +271,7 @@ class TargetInfoTest {
intent.putExtra(Intent.EXTRA_TEXT, "testing intent sending")
intent.setType("text/plain")
- val resolveInfo = ResolverDataProvider.createResolveInfo(3, 0)
+ val resolveInfo = ResolverDataProvider.createResolveInfo(3, 0, PERSONAL_USER_HANDLE)
val firstTargetInfo = DisplayResolveInfo.newDisplayResolveInfo(
intent,
resolveInfo,
diff --git a/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt b/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt
index d870a8c2..9bfd2052 100644
--- a/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt
+++ b/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt
@@ -16,188 +16,131 @@
package com.android.intentresolver.contentpreview
-import android.content.ClipDescription
-import android.content.ContentInterface
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
-import com.android.intentresolver.ImageLoader
-import com.android.intentresolver.TestFeatureFlagRepository
+import androidx.lifecycle.Lifecycle
+import com.android.intentresolver.any
import com.android.intentresolver.contentpreview.ChooserContentPreviewUi.ActionFactory
-import com.android.intentresolver.flags.Flags
import com.android.intentresolver.mock
import com.android.intentresolver.whenever
import com.android.intentresolver.widget.ActionRow
import com.android.intentresolver.widget.ImagePreviewView
import com.google.common.truth.Truth.assertThat
+import java.util.function.Consumer
import org.junit.Test
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import java.util.function.Consumer
-private const val PROVIDER_NAME = "org.pkg.app"
class ChooserContentPreviewUiTest {
- private val contentResolver = mock<ContentInterface>()
- private val imageClassifier = ChooserContentPreviewUi.ImageMimeTypeClassifier { mimeType ->
- mimeType != null && ClipDescription.compareMimeTypes(mimeType, "image/*")
- }
- private val imageLoader = object : ImageLoader {
- override fun loadImage(uri: Uri, callback: Consumer<Bitmap?>) {
- callback.accept(null)
+ private val lifecycle = mock<Lifecycle>()
+ private val previewData = mock<PreviewDataProvider>()
+ private val headlineGenerator = mock<HeadlineGenerator>()
+ private val imageLoader =
+ object : ImageLoader {
+ override fun loadImage(
+ callerLifecycle: Lifecycle,
+ uri: Uri,
+ callback: Consumer<Bitmap?>,
+ ) {
+ callback.accept(null)
+ }
+ override fun prePopulate(uris: List<Uri>) = Unit
+ override suspend fun invoke(uri: Uri, caching: Boolean): Bitmap? = null
+ }
+ private val actionFactory =
+ object : ActionFactory {
+ override fun getCopyButtonRunnable(): Runnable? = null
+ override fun getEditButtonRunnable(): Runnable? = null
+ override fun createCustomActions(): List<ActionRow.Action> = emptyList()
+ override fun getModifyShareAction(): ActionRow.Action? = null
+ override fun getExcludeSharedTextAction(): Consumer<Boolean> = Consumer<Boolean> {}
}
- override fun prePopulate(uris: List<Uri>) = Unit
- override suspend fun invoke(uri: Uri): Bitmap? = null
- }
- private val actionFactory = object : ActionFactory {
- override fun createCopyButton() = ActionRow.Action(label = "Copy", icon = null) {}
- override fun createEditButton(): ActionRow.Action? = null
- override fun createNearbyButton(): ActionRow.Action? = null
- override fun createCustomActions(): List<ActionRow.Action> = emptyList()
- override fun getModifyShareAction(): Runnable? = null
- override fun getExcludeSharedTextAction(): Consumer<Boolean> = Consumer<Boolean> {}
- }
private val transitionCallback = mock<ImagePreviewView.TransitionElementStatusCallback>()
- private val featureFlagRepository = TestFeatureFlagRepository(
- mapOf(
- Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW to true
- )
- )
@Test
- fun test_ChooserContentPreview_non_send_intent_action_to_text_preview() {
- val targetIntent = Intent(Intent.ACTION_VIEW)
- val testSubject = ChooserContentPreviewUi(
- targetIntent,
- contentResolver,
- imageClassifier,
- imageLoader,
- actionFactory,
- transitionCallback,
- featureFlagRepository
- )
+ fun test_textPreviewType_useTextPreviewUi() {
+ whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_TEXT)
+ val testSubject =
+ ChooserContentPreviewUi(
+ lifecycle,
+ previewData,
+ Intent(Intent.ACTION_VIEW),
+ imageLoader,
+ actionFactory,
+ transitionCallback,
+ headlineGenerator,
+ )
assertThat(testSubject.preferredContentPreview)
.isEqualTo(ContentPreviewType.CONTENT_PREVIEW_TEXT)
+ assertThat(testSubject.mContentPreviewUi).isInstanceOf(TextContentPreviewUi::class.java)
verify(transitionCallback, times(1)).onAllTransitionElementsReady()
}
@Test
- fun test_ChooserContentPreview_text_mime_type_to_text_preview() {
- val targetIntent = Intent(Intent.ACTION_SEND).apply {
- type = "text/plain"
- putExtra(Intent.EXTRA_TEXT, "Text Extra")
- }
- val testSubject = ChooserContentPreviewUi(
- targetIntent,
- contentResolver,
- imageClassifier,
- imageLoader,
- actionFactory,
- transitionCallback,
- featureFlagRepository
- )
+ fun test_filePreviewType_useFilePreviewUi() {
+ whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_FILE)
+ val testSubject =
+ ChooserContentPreviewUi(
+ lifecycle,
+ previewData,
+ Intent(Intent.ACTION_SEND),
+ imageLoader,
+ actionFactory,
+ transitionCallback,
+ headlineGenerator,
+ )
assertThat(testSubject.preferredContentPreview)
- .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_TEXT)
+ .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE)
+ assertThat(testSubject.mContentPreviewUi).isInstanceOf(FileContentPreviewUi::class.java)
verify(transitionCallback, times(1)).onAllTransitionElementsReady()
}
@Test
- fun test_ChooserContentPreview_single_image_uri_to_image_preview() {
- val uri = Uri.parse("content://$PROVIDER_NAME/test.png")
- val targetIntent = Intent(Intent.ACTION_SEND).apply {
- putExtra(Intent.EXTRA_STREAM, uri)
- }
- whenever(contentResolver.getType(uri)).thenReturn("image/png")
- val testSubject = ChooserContentPreviewUi(
- targetIntent,
- contentResolver,
- imageClassifier,
- imageLoader,
- actionFactory,
- transitionCallback,
- featureFlagRepository
- )
- assertThat(testSubject.preferredContentPreview)
- .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
- verify(transitionCallback, never()).onAllTransitionElementsReady()
- }
-
- @Test
- fun test_ChooserContentPreview_single_non_image_uri_to_file_preview() {
- val uri = Uri.parse("content://$PROVIDER_NAME/test.pdf")
- val targetIntent = Intent(Intent.ACTION_SEND).apply {
- putExtra(Intent.EXTRA_STREAM, uri)
- }
- whenever(contentResolver.getType(uri)).thenReturn("application/pdf")
- val testSubject = ChooserContentPreviewUi(
- targetIntent,
- contentResolver,
- imageClassifier,
- imageLoader,
- actionFactory,
- transitionCallback,
- featureFlagRepository
- )
- assertThat(testSubject.preferredContentPreview)
- .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE)
+ fun test_imagePreviewTypeWithText_useFilePlusTextPreviewUi() {
+ val uri = Uri.parse("content://org.pkg.app/img.png")
+ whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
+ whenever(previewData.uriCount).thenReturn(2)
+ whenever(previewData.firstFileInfo)
+ .thenReturn(FileInfo.Builder(uri).withPreviewUri(uri).withMimeType("image/png").build())
+ val testSubject =
+ ChooserContentPreviewUi(
+ lifecycle,
+ previewData,
+ Intent(Intent.ACTION_SEND).apply { putExtra(Intent.EXTRA_TEXT, "Shared text") },
+ imageLoader,
+ actionFactory,
+ transitionCallback,
+ headlineGenerator,
+ )
+ assertThat(testSubject.mContentPreviewUi)
+ .isInstanceOf(FilesPlusTextContentPreviewUi::class.java)
+ verify(previewData, times(1)).getFileMetadataForImagePreview(any(), any())
verify(transitionCallback, times(1)).onAllTransitionElementsReady()
}
@Test
- fun test_ChooserContentPreview_multiple_image_uri_to_image_preview() {
- val uri1 = Uri.parse("content://$PROVIDER_NAME/test.png")
- val uri2 = Uri.parse("content://$PROVIDER_NAME/test.jpg")
- val targetIntent = Intent(Intent.ACTION_SEND_MULTIPLE).apply {
- putExtra(
- Intent.EXTRA_STREAM,
- ArrayList<Uri>().apply {
- add(uri1)
- add(uri2)
- }
+ fun test_imagePreviewTypeWithoutText_useImagePreviewUi() {
+ val uri = Uri.parse("content://org.pkg.app/img.png")
+ whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
+ whenever(previewData.uriCount).thenReturn(2)
+ whenever(previewData.firstFileInfo)
+ .thenReturn(FileInfo.Builder(uri).withPreviewUri(uri).withMimeType("image/png").build())
+ val testSubject =
+ ChooserContentPreviewUi(
+ lifecycle,
+ previewData,
+ Intent(Intent.ACTION_SEND),
+ imageLoader,
+ actionFactory,
+ transitionCallback,
+ headlineGenerator,
)
- }
- whenever(contentResolver.getType(uri1)).thenReturn("image/png")
- whenever(contentResolver.getType(uri2)).thenReturn("image/jpeg")
- val testSubject = ChooserContentPreviewUi(
- targetIntent,
- contentResolver,
- imageClassifier,
- imageLoader,
- actionFactory,
- transitionCallback,
- featureFlagRepository
- )
assertThat(testSubject.preferredContentPreview)
.isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
+ assertThat(testSubject.mContentPreviewUi).isInstanceOf(UnifiedContentPreviewUi::class.java)
+ verify(previewData, times(1)).getFileMetadataForImagePreview(any(), any())
verify(transitionCallback, never()).onAllTransitionElementsReady()
}
-
- @Test
- fun test_ChooserContentPreview_some_non_image_uri_to_file_preview() {
- val uri1 = Uri.parse("content://$PROVIDER_NAME/test.png")
- val uri2 = Uri.parse("content://$PROVIDER_NAME/test.pdf")
- val targetIntent = Intent(Intent.ACTION_SEND_MULTIPLE).apply {
- putExtra(
- Intent.EXTRA_STREAM,
- ArrayList<Uri>().apply {
- add(uri1)
- add(uri2)
- }
- )
- }
- whenever(contentResolver.getType(uri1)).thenReturn("image/png")
- whenever(contentResolver.getType(uri2)).thenReturn("application/pdf")
- val testSubject = ChooserContentPreviewUi(
- targetIntent,
- contentResolver,
- imageClassifier,
- imageLoader,
- actionFactory,
- transitionCallback,
- featureFlagRepository
- )
- assertThat(testSubject.preferredContentPreview)
- .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE)
- verify(transitionCallback, times(1)).onAllTransitionElementsReady()
- }
}
diff --git a/java/tests/src/com/android/intentresolver/contentpreview/ContentPreviewUiTest.kt b/java/tests/src/com/android/intentresolver/contentpreview/ContentPreviewUiTest.kt
new file mode 100644
index 00000000..6db53a9e
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/contentpreview/ContentPreviewUiTest.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import com.android.intentresolver.widget.ScrollableImagePreviewView.PreviewType
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class ContentPreviewUiTest {
+ @Test
+ fun testPreviewTypes() {
+ val typeClassifier =
+ object : MimeTypeClassifier {
+ override fun isImageType(type: String?) = (type == "image")
+ override fun isVideoType(type: String?) = (type == "video")
+ }
+
+ assertThat(ContentPreviewUi.getPreviewType(typeClassifier, "image"))
+ .isEqualTo(PreviewType.Image)
+ assertThat(ContentPreviewUi.getPreviewType(typeClassifier, "video"))
+ .isEqualTo(PreviewType.Video)
+ assertThat(ContentPreviewUi.getPreviewType(typeClassifier, "other"))
+ .isEqualTo(PreviewType.File)
+ assertThat(ContentPreviewUi.getPreviewType(typeClassifier, null))
+ .isEqualTo(PreviewType.File)
+ }
+}
diff --git a/java/tests/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImplTest.kt b/java/tests/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImplTest.kt
new file mode 100644
index 00000000..a65280e5
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/contentpreview/HeadlineGeneratorImplTest.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Test
+import org.junit.runner.RunWith
+import com.google.common.truth.Truth.assertThat
+
+@RunWith(AndroidJUnit4::class)
+class HeadlineGeneratorImplTest {
+ @Test
+ fun testHeadlineGeneration() {
+ val generator = HeadlineGeneratorImpl(
+ InstrumentationRegistry.getInstrumentation().getTargetContext())
+ val str = "Some string"
+ val url = "http://www.google.com"
+
+ assertThat(generator.getTextHeadline(str)).isEqualTo("Sharing text")
+ assertThat(generator.getTextHeadline(url)).isEqualTo("Sharing link")
+
+ assertThat(generator.getImagesWithTextHeadline(str, 1)).isEqualTo("Sharing image with text")
+ assertThat(generator.getImagesWithTextHeadline(url, 1)).isEqualTo("Sharing image with link")
+ assertThat(generator.getImagesWithTextHeadline(str, 5)).isEqualTo("Sharing 5 images with text")
+ assertThat(generator.getImagesWithTextHeadline(url, 5)).isEqualTo("Sharing 5 images with link")
+
+ assertThat(generator.getVideosWithTextHeadline(str, 1)).isEqualTo("Sharing video with text")
+ assertThat(generator.getVideosWithTextHeadline(url, 1)).isEqualTo("Sharing video with link")
+ assertThat(generator.getVideosWithTextHeadline(str, 5)).isEqualTo("Sharing 5 videos with text")
+ assertThat(generator.getVideosWithTextHeadline(url, 5)).isEqualTo("Sharing 5 videos with link")
+
+ assertThat(generator.getFilesWithTextHeadline(str, 1)).isEqualTo("Sharing file with text")
+ assertThat(generator.getFilesWithTextHeadline(url, 1)).isEqualTo("Sharing file with link")
+ assertThat(generator.getFilesWithTextHeadline(str, 5)).isEqualTo("Sharing 5 files with text")
+ assertThat(generator.getFilesWithTextHeadline(url, 5)).isEqualTo("Sharing 5 files with link")
+
+ assertThat(generator.getImagesHeadline(1)).isEqualTo("Sharing image")
+ assertThat(generator.getImagesHeadline(4)).isEqualTo("Sharing 4 images")
+
+ assertThat(generator.getVideosHeadline(1)).isEqualTo("Sharing video")
+ assertThat(generator.getVideosHeadline(4)).isEqualTo("Sharing 4 videos")
+
+ assertThat(generator.getFilesHeadline(1)).isEqualTo("Sharing 1 file")
+ assertThat(generator.getFilesHeadline(4)).isEqualTo("Sharing 4 files")
+ }
+}
diff --git a/java/tests/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoaderTest.kt b/java/tests/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoaderTest.kt
new file mode 100644
index 00000000..6e57c289
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoaderTest.kt
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import android.content.ContentResolver
+import android.graphics.Bitmap
+import android.net.Uri
+import android.util.Size
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.coroutineScope
+import com.android.intentresolver.TestLifecycleOwner
+import com.android.intentresolver.any
+import com.android.intentresolver.anyOrNull
+import com.android.intentresolver.mock
+import com.android.intentresolver.whenever
+import com.google.common.truth.Truth.assertThat
+import java.util.ArrayDeque
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit.MILLISECONDS
+import java.util.concurrent.TimeUnit.SECONDS
+import java.util.concurrent.atomic.AtomicInteger
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Runnable
+import kotlinx.coroutines.async
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.plus
+import kotlinx.coroutines.sync.Semaphore
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestCoroutineScheduler
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.test.setMain
+import kotlinx.coroutines.yield
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class ImagePreviewImageLoaderTest {
+ private val imageSize = Size(300, 300)
+ private val uriOne = Uri.parse("content://org.package.app/image-1.png")
+ private val uriTwo = Uri.parse("content://org.package.app/image-2.png")
+ private val bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+ private val contentResolver =
+ mock<ContentResolver> {
+ whenever(loadThumbnail(any(), any(), anyOrNull())).thenReturn(bitmap)
+ }
+ private val lifecycleOwner = TestLifecycleOwner()
+ private val dispatcher = UnconfinedTestDispatcher()
+ private lateinit var testSubject: ImagePreviewImageLoader
+
+ @Before
+ fun setup() {
+ Dispatchers.setMain(dispatcher)
+ lifecycleOwner.state = Lifecycle.State.CREATED
+ // create test subject after we've updated the lifecycle dispatcher
+ testSubject =
+ ImagePreviewImageLoader(
+ lifecycleOwner.lifecycle.coroutineScope + dispatcher,
+ imageSize.width,
+ contentResolver,
+ cacheSize = 1,
+ )
+ }
+
+ @After
+ fun cleanup() {
+ lifecycleOwner.state = Lifecycle.State.DESTROYED
+ Dispatchers.resetMain()
+ }
+
+ @Test
+ fun prePopulate_cachesImagesUpToTheCacheSize() = runTest {
+ testSubject.prePopulate(listOf(uriOne, uriTwo))
+
+ verify(contentResolver, times(1)).loadThumbnail(uriOne, imageSize, null)
+ verify(contentResolver, never()).loadThumbnail(uriTwo, imageSize, null)
+
+ testSubject(uriOne)
+ verify(contentResolver, times(1)).loadThumbnail(uriOne, imageSize, null)
+ }
+
+ @Test
+ fun invoke_returnCachedImageWhenCalledTwice() = runTest {
+ testSubject(uriOne)
+ testSubject(uriOne)
+
+ verify(contentResolver, times(1)).loadThumbnail(any(), any(), anyOrNull())
+ }
+
+ @Test
+ fun invoke_whenInstructed_doesNotCache() = runTest {
+ testSubject(uriOne, false)
+ testSubject(uriOne, false)
+
+ verify(contentResolver, times(2)).loadThumbnail(any(), any(), anyOrNull())
+ }
+
+ @Test
+ fun invoke_overlappedRequests_Deduplicate() = runTest {
+ val scheduler = TestCoroutineScheduler()
+ val dispatcher = StandardTestDispatcher(scheduler)
+ val testSubject =
+ ImagePreviewImageLoader(
+ lifecycleOwner.lifecycle.coroutineScope + dispatcher,
+ imageSize.width,
+ contentResolver,
+ cacheSize = 1,
+ )
+ coroutineScope {
+ launch(start = UNDISPATCHED) { testSubject(uriOne, false) }
+ launch(start = UNDISPATCHED) { testSubject(uriOne, false) }
+ scheduler.advanceUntilIdle()
+ }
+
+ verify(contentResolver, times(1)).loadThumbnail(any(), any(), anyOrNull())
+ }
+
+ @Test
+ fun invoke_oldRecordsEvictedFromTheCache() = runTest {
+ testSubject(uriOne)
+ testSubject(uriTwo)
+ testSubject(uriTwo)
+ testSubject(uriOne)
+
+ verify(contentResolver, times(2)).loadThumbnail(uriOne, imageSize, null)
+ verify(contentResolver, times(1)).loadThumbnail(uriTwo, imageSize, null)
+ }
+
+ @Test
+ fun invoke_doNotCacheNulls() = runTest {
+ whenever(contentResolver.loadThumbnail(any(), any(), anyOrNull())).thenReturn(null)
+ testSubject(uriOne)
+ testSubject(uriOne)
+
+ verify(contentResolver, times(2)).loadThumbnail(uriOne, imageSize, null)
+ }
+
+ @Test(expected = CancellationException::class)
+ fun invoke_onClosedImageLoaderScope_throwsCancellationException() = runTest {
+ lifecycleOwner.state = Lifecycle.State.DESTROYED
+ testSubject(uriOne)
+ }
+
+ @Test(expected = CancellationException::class)
+ fun invoke_imageLoaderScopeClosedMidflight_throwsCancellationException() = runTest {
+ val scheduler = TestCoroutineScheduler()
+ val dispatcher = StandardTestDispatcher(scheduler)
+ val testSubject =
+ ImagePreviewImageLoader(
+ lifecycleOwner.lifecycle.coroutineScope + dispatcher,
+ imageSize.width,
+ contentResolver,
+ cacheSize = 1,
+ )
+ coroutineScope {
+ val deferred = async(start = UNDISPATCHED) { testSubject(uriOne, false) }
+ lifecycleOwner.state = Lifecycle.State.DESTROYED
+ scheduler.advanceUntilIdle()
+ deferred.await()
+ }
+ }
+
+ @Test
+ fun invoke_multipleCallsWithDifferentCacheInstructions_cachingPrevails() = runTest {
+ val scheduler = TestCoroutineScheduler()
+ val dispatcher = StandardTestDispatcher(scheduler)
+ val testSubject =
+ ImagePreviewImageLoader(
+ lifecycleOwner.lifecycle.coroutineScope + dispatcher,
+ imageSize.width,
+ contentResolver,
+ cacheSize = 1,
+ )
+ coroutineScope {
+ launch(start = UNDISPATCHED) { testSubject(uriOne, false) }
+ launch(start = UNDISPATCHED) { testSubject(uriOne, true) }
+ scheduler.advanceUntilIdle()
+ }
+ testSubject(uriOne, true)
+
+ verify(contentResolver, times(1)).loadThumbnail(uriOne, imageSize, null)
+ }
+
+ @Test
+ fun invoke_semaphoreGuardsContentResolverCalls() = runTest {
+ val contentResolver =
+ mock<ContentResolver> {
+ whenever(loadThumbnail(any(), any(), anyOrNull()))
+ .thenThrow(SecurityException("test"))
+ }
+ val acquireCount = AtomicInteger()
+ val releaseCount = AtomicInteger()
+ val testSemaphore =
+ object : Semaphore {
+ override val availablePermits: Int
+ get() = error("Unexpected invocation")
+
+ override suspend fun acquire() {
+ acquireCount.getAndIncrement()
+ }
+
+ override fun tryAcquire(): Boolean {
+ error("Unexpected invocation")
+ }
+
+ override fun release() {
+ releaseCount.getAndIncrement()
+ }
+ }
+
+ val testSubject =
+ ImagePreviewImageLoader(
+ lifecycleOwner.lifecycle.coroutineScope + dispatcher,
+ imageSize.width,
+ contentResolver,
+ cacheSize = 1,
+ testSemaphore,
+ )
+ testSubject(uriOne, false)
+
+ verify(contentResolver, times(1)).loadThumbnail(uriOne, imageSize, null)
+ assertThat(acquireCount.get()).isEqualTo(1)
+ assertThat(releaseCount.get()).isEqualTo(1)
+ }
+
+ @Test
+ fun invoke_semaphoreIsReleasedAfterContentResolverFailure() = runTest {
+ val semaphoreDeferred = CompletableDeferred<Unit>()
+ val releaseCount = AtomicInteger()
+ val testSemaphore =
+ object : Semaphore {
+ override val availablePermits: Int
+ get() = error("Unexpected invocation")
+
+ override suspend fun acquire() {
+ semaphoreDeferred.await()
+ }
+
+ override fun tryAcquire(): Boolean {
+ error("Unexpected invocation")
+ }
+
+ override fun release() {
+ releaseCount.getAndIncrement()
+ }
+ }
+
+ val testSubject =
+ ImagePreviewImageLoader(
+ lifecycleOwner.lifecycle.coroutineScope + dispatcher,
+ imageSize.width,
+ contentResolver,
+ cacheSize = 1,
+ testSemaphore,
+ )
+ launch(start = UNDISPATCHED) { testSubject(uriOne, false) }
+
+ verify(contentResolver, never()).loadThumbnail(any(), any(), anyOrNull())
+
+ semaphoreDeferred.complete(Unit)
+
+ verify(contentResolver, times(1)).loadThumbnail(uriOne, imageSize, null)
+ assertThat(releaseCount.get()).isEqualTo(1)
+ }
+
+ @Test
+ fun invoke_multipleSimultaneousCalls_limitOnNumberOfSimultaneousOutgoingCallsIsRespected() {
+ val requestCount = 4
+ val thumbnailCallsCdl = CountDownLatch(requestCount)
+ val pendingThumbnailCalls = ArrayDeque<CountDownLatch>()
+ val contentResolver =
+ mock<ContentResolver> {
+ whenever(loadThumbnail(any(), any(), anyOrNull())).thenAnswer {
+ val latch = CountDownLatch(1)
+ synchronized(pendingThumbnailCalls) { pendingThumbnailCalls.offer(latch) }
+ thumbnailCallsCdl.countDown()
+ latch.await()
+ bitmap
+ }
+ }
+ val name = "LoadImage"
+ val maxSimultaneousRequests = 2
+ val threadsStartedCdl = CountDownLatch(requestCount)
+ val dispatcher = NewThreadDispatcher(name) { threadsStartedCdl.countDown() }
+ val testSubject =
+ ImagePreviewImageLoader(
+ lifecycleOwner.lifecycle.coroutineScope + dispatcher + CoroutineName(name),
+ imageSize.width,
+ contentResolver,
+ cacheSize = 1,
+ maxSimultaneousRequests,
+ )
+ runTest {
+ repeat(requestCount) {
+ launch { testSubject(Uri.parse("content://org.pkg.app/image-$it.png")) }
+ }
+ yield()
+ // wait for all requests to be dispatched
+ assertThat(threadsStartedCdl.await(5, SECONDS)).isTrue()
+
+ assertThat(thumbnailCallsCdl.await(100, MILLISECONDS)).isFalse()
+ synchronized(pendingThumbnailCalls) {
+ assertThat(pendingThumbnailCalls.size).isEqualTo(maxSimultaneousRequests)
+ }
+
+ pendingThumbnailCalls.poll()?.countDown()
+ assertThat(thumbnailCallsCdl.await(100, MILLISECONDS)).isFalse()
+ synchronized(pendingThumbnailCalls) {
+ assertThat(pendingThumbnailCalls.size).isEqualTo(maxSimultaneousRequests)
+ }
+
+ pendingThumbnailCalls.poll()?.countDown()
+ assertThat(thumbnailCallsCdl.await(100, MILLISECONDS)).isTrue()
+ synchronized(pendingThumbnailCalls) {
+ assertThat(pendingThumbnailCalls.size).isEqualTo(maxSimultaneousRequests)
+ }
+ for (cdl in pendingThumbnailCalls) {
+ cdl.countDown()
+ }
+ }
+ }
+}
+
+private class NewThreadDispatcher(
+ private val coroutineName: String,
+ private val launchedCallback: () -> Unit
+) : CoroutineDispatcher() {
+ override fun isDispatchNeeded(context: CoroutineContext): Boolean = true
+
+ override fun dispatch(context: CoroutineContext, block: Runnable) {
+ Thread {
+ if (coroutineName == context[CoroutineName.Key]?.name) {
+ launchedCallback()
+ }
+ block.run()
+ }
+ .start()
+ }
+}
diff --git a/java/tests/src/com/android/intentresolver/contentpreview/PreviewDataProviderTest.kt b/java/tests/src/com/android/intentresolver/contentpreview/PreviewDataProviderTest.kt
new file mode 100644
index 00000000..145b89ad
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/contentpreview/PreviewDataProviderTest.kt
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import android.content.ContentInterface
+import android.content.Intent
+import android.database.MatrixCursor
+import android.media.MediaMetadata
+import android.net.Uri
+import android.provider.DocumentsContract
+import androidx.lifecycle.Lifecycle
+import com.android.intentresolver.TestLifecycleOwner
+import com.android.intentresolver.mock
+import com.android.intentresolver.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.any
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class PreviewDataProviderTest {
+ private val contentResolver = mock<ContentInterface>()
+ private val mimeTypeClassifier = DefaultMimeTypeClassifier
+
+ private val lifecycleOwner = TestLifecycleOwner()
+ private val dispatcher = UnconfinedTestDispatcher()
+
+ @Before
+ fun setup() {
+ Dispatchers.setMain(dispatcher)
+ lifecycleOwner.state = Lifecycle.State.CREATED
+ }
+
+ @After
+ fun cleanup() {
+ lifecycleOwner.state = Lifecycle.State.DESTROYED
+ Dispatchers.resetMain()
+ }
+
+ @Test
+ fun test_nonSendIntentAction_resolvesToTextPreviewUiSynchronously() {
+ val targetIntent = Intent(Intent.ACTION_VIEW)
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_TEXT)
+ verify(contentResolver, never()).getType(any())
+ }
+
+ @Test
+ fun test_sendSingleTextFileWithoutPreview_resolvesToFilePreviewUi() {
+ val uri = Uri.parse("content://org.pkg.app/notes.txt")
+ val targetIntent = Intent(Intent.ACTION_SEND)
+ .apply {
+ putExtra(Intent.EXTRA_STREAM, uri)
+ type = "text/plain"
+ }
+ whenever(contentResolver.getType(uri)).thenReturn("text/plain")
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE)
+ assertThat(testSubject.uriCount).isEqualTo(1)
+ assertThat(testSubject.firstFileInfo?.uri).isEqualTo(uri)
+ verify(contentResolver, times(1)).getType(any())
+ }
+
+ @Test
+ fun test_sendIntentWithoutUris_resolvesToTextPreviewUiSynchronously() {
+ val targetIntent = Intent(Intent.ACTION_SEND)
+ .apply {
+ type = "image/png"
+ }
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_TEXT)
+ verify(contentResolver, never()).getType(any())
+ }
+
+ @Test
+ fun test_sendSingleImage_resolvesToImagePreviewUi() {
+ val uri = Uri.parse("content://org.pkg.app/image.png")
+ val targetIntent = Intent(Intent.ACTION_SEND)
+ .apply {
+ putExtra(Intent.EXTRA_STREAM, uri)
+ }
+ whenever(contentResolver.getType(uri)).thenReturn("image/png")
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
+ assertThat(testSubject.uriCount).isEqualTo(1)
+ assertThat(testSubject.firstFileInfo?.uri).isEqualTo(uri)
+ assertThat(testSubject.firstFileInfo?.previewUri).isEqualTo(uri)
+ verify(contentResolver, times(1)).getType(any())
+ }
+
+ @Test
+ fun test_sendSingleNonImage_resolvesToFilePreviewUi() {
+ val uri = Uri.parse("content://org.pkg.app/paper.pdf")
+ val targetIntent = Intent(Intent.ACTION_SEND)
+ .apply {
+ putExtra(Intent.EXTRA_STREAM, uri)
+ }
+ whenever(contentResolver.getType(uri)).thenReturn("application/pdf")
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE)
+ assertThat(testSubject.uriCount).isEqualTo(1)
+ assertThat(testSubject.firstFileInfo?.uri).isEqualTo(uri)
+ assertThat(testSubject.firstFileInfo?.previewUri).isNull()
+ verify(contentResolver, times(1)).getType(any())
+ }
+
+ @Test
+ fun test_sendSingleImageWithFailingGetType_resolvesToFilePreviewUi() {
+ val uri = Uri.parse("content://org.pkg.app/image.png")
+ val targetIntent =
+ Intent(Intent.ACTION_SEND)
+ .apply {
+ type = "image/png"
+ putExtra(Intent.EXTRA_STREAM, uri)
+ }
+ whenever(contentResolver.getType(uri)).thenThrow(SecurityException("test failure"))
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE)
+ assertThat(testSubject.uriCount).isEqualTo(1)
+ assertThat(testSubject.firstFileInfo?.uri).isEqualTo(uri)
+ assertThat(testSubject.firstFileInfo?.previewUri).isNull()
+ verify(contentResolver, times(1)).getType(any())
+ }
+
+ @Test
+ fun test_sendSingleImageWithFailingMetadata_resolvesToFilePreviewUi() {
+ val uri = Uri.parse("content://org.pkg.app/image.png")
+ val targetIntent =
+ Intent(Intent.ACTION_SEND)
+ .apply {
+ type = "image/png"
+ putExtra(Intent.EXTRA_STREAM, uri)
+ }
+ whenever(contentResolver.getStreamTypes(uri, "*/*"))
+ .thenThrow(SecurityException("test failure"))
+ whenever(contentResolver.query(uri, METADATA_COLUMNS, null, null))
+ .thenThrow(SecurityException("test failure"))
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE)
+ assertThat(testSubject.uriCount).isEqualTo(1)
+ assertThat(testSubject.firstFileInfo?.uri).isEqualTo(uri)
+ assertThat(testSubject.firstFileInfo?.previewUri).isNull()
+ verify(contentResolver, times(1)).getType(any())
+ }
+
+ @Test
+ fun test_SingleNonImageUriWithImageTypeInGetStreamTypes_useImagePreviewUi() {
+ val uri = Uri.parse("content://org.pkg.app/paper.pdf")
+ val targetIntent = Intent(Intent.ACTION_SEND)
+ .apply {
+ putExtra(Intent.EXTRA_STREAM, uri)
+ }
+ whenever(contentResolver.getStreamTypes(uri, "*/*"))
+ .thenReturn(arrayOf("application/pdf", "image/png"))
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
+ assertThat(testSubject.uriCount).isEqualTo(1)
+ assertThat(testSubject.firstFileInfo?.uri).isEqualTo(uri)
+ assertThat(testSubject.firstFileInfo?.previewUri).isEqualTo(uri)
+ verify(contentResolver, times(1)).getType(any())
+ }
+
+ @Test
+ fun test_SingleNonImageUriWithThumbnailFlag_useImagePreviewUi() {
+ testMetadataToImagePreview(
+ columns = arrayOf(DocumentsContract.Document.COLUMN_FLAGS),
+ values =
+ arrayOf(
+ DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL or
+ DocumentsContract.Document.FLAG_SUPPORTS_METADATA
+ )
+ )
+ }
+
+ @Test
+ fun test_SingleNonImageUriWithMetadataIconUri_useImagePreviewUi() {
+ testMetadataToImagePreview(
+ columns = arrayOf(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI),
+ values = arrayOf("content://org.pkg.app/test.pdf?thumbnail"),
+ )
+ }
+
+ private fun testMetadataToImagePreview(columns: Array<String>, values: Array<Any>) {
+ val uri = Uri.parse("content://org.pkg.app/test.pdf")
+ val targetIntent = Intent(Intent.ACTION_SEND)
+ .apply {
+ putExtra(Intent.EXTRA_STREAM, uri)
+ }
+ whenever(contentResolver.getType(uri)).thenReturn("application/pdf")
+ whenever(contentResolver.query(uri, METADATA_COLUMNS, null, null))
+ .thenReturn(MatrixCursor(columns).apply { addRow(values) })
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
+ assertThat(testSubject.uriCount).isEqualTo(1)
+ assertThat(testSubject.firstFileInfo?.uri).isEqualTo(uri)
+ assertThat(testSubject.firstFileInfo?.previewUri).isNotNull()
+ verify(contentResolver, times(1)).getType(any())
+ }
+
+ @Test
+ fun test_multipleImageUri_useImagePreviewUi() {
+ val uri1 = Uri.parse("content://org.pkg.app/test.png")
+ val uri2 = Uri.parse("content://org.pkg.app/test.jpg")
+ val targetIntent =
+ Intent(Intent.ACTION_SEND_MULTIPLE)
+ .apply {
+ putExtra(
+ Intent.EXTRA_STREAM,
+ ArrayList<Uri>().apply {
+ add(uri1)
+ add(uri2)
+ }
+ )
+ }
+ whenever(contentResolver.getType(uri1)).thenReturn("image/png")
+ whenever(contentResolver.getType(uri2)).thenReturn("image/jpeg")
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
+ assertThat(testSubject.uriCount).isEqualTo(2)
+ assertThat(testSubject.firstFileInfo?.uri).isEqualTo(uri1)
+ assertThat(testSubject.firstFileInfo?.previewUri).isEqualTo(uri1)
+ // preview type can be determined by the first URI type
+ verify(contentResolver, times(1)).getType(any())
+ }
+
+ @Test
+ fun test_SomeImageUri_useImagePreviewUi() {
+ val uri1 = Uri.parse("content://org.pkg.app/test.png")
+ val uri2 = Uri.parse("content://org.pkg.app/test.pdf")
+ whenever(contentResolver.getType(uri1)).thenReturn("image/png")
+ whenever(contentResolver.getType(uri2)).thenReturn("application/pdf")
+ val targetIntent =
+ Intent(Intent.ACTION_SEND_MULTIPLE)
+ .apply {
+ putExtra(
+ Intent.EXTRA_STREAM,
+ ArrayList<Uri>().apply {
+ add(uri1)
+ add(uri2)
+ }
+ )
+ }
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
+ assertThat(testSubject.uriCount).isEqualTo(2)
+ assertThat(testSubject.firstFileInfo?.uri).isEqualTo(uri1)
+ assertThat(testSubject.firstFileInfo?.previewUri).isEqualTo(uri1)
+ // preview type can be determined by the first URI type
+ verify(contentResolver, times(1)).getType(any())
+ }
+
+ @Test
+ fun test_someNonImageUriWithPreview_useImagePreviewUi() {
+ val uri1 = Uri.parse("content://org.pkg.app/test.mp4")
+ val uri2 = Uri.parse("content://org.pkg.app/test.pdf")
+ val targetIntent =
+ Intent(Intent.ACTION_SEND_MULTIPLE)
+ .apply {
+ putExtra(
+ Intent.EXTRA_STREAM,
+ ArrayList<Uri>().apply {
+ add(uri1)
+ add(uri2)
+ }
+ )
+ }
+ whenever(contentResolver.getType(uri1)).thenReturn("video/mpeg4")
+ whenever(contentResolver.getStreamTypes(uri1, "*/*")).thenReturn(arrayOf("image/png"))
+ whenever(contentResolver.getType(uri2)).thenReturn("application/pdf")
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
+ assertThat(testSubject.uriCount).isEqualTo(2)
+ assertThat(testSubject.firstFileInfo?.uri).isEqualTo(uri1)
+ assertThat(testSubject.firstFileInfo?.previewUri).isEqualTo(uri1)
+ verify(contentResolver, times(2)).getType(any())
+ }
+
+ @Test
+ fun test_allNonImageUrisWithoutPreview_useFilePreviewUi() {
+ val uri1 = Uri.parse("content://org.pkg.app/test.html")
+ val uri2 = Uri.parse("content://org.pkg.app/test.pdf")
+ val targetIntent =
+ Intent(Intent.ACTION_SEND_MULTIPLE)
+ .apply {
+ putExtra(
+ Intent.EXTRA_STREAM,
+ ArrayList<Uri>().apply {
+ add(uri1)
+ add(uri2)
+ }
+ )
+ }
+ whenever(contentResolver.getType(uri1)).thenReturn("text/html")
+ whenever(contentResolver.getType(uri2)).thenReturn("application/pdf")
+ val testSubject =
+ PreviewDataProvider(targetIntent, contentResolver, mimeTypeClassifier, dispatcher)
+
+ assertThat(testSubject.previewType).isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE)
+ assertThat(testSubject.uriCount).isEqualTo(2)
+ assertThat(testSubject.firstFileInfo?.uri).isEqualTo(uri1)
+ assertThat(testSubject.firstFileInfo?.previewUri).isNull()
+ verify(contentResolver, times(2)).getType(any())
+ }
+}
diff --git a/java/tests/src/com/android/intentresolver/model/AbstractResolverComparatorTest.java b/java/tests/src/com/android/intentresolver/model/AbstractResolverComparatorTest.java
index 006f3b2d..5f0ead7b 100644
--- a/java/tests/src/com/android/intentresolver/model/AbstractResolverComparatorTest.java
+++ b/java/tests/src/com/android/intentresolver/model/AbstractResolverComparatorTest.java
@@ -28,6 +28,9 @@ import android.os.Message;
import androidx.test.InstrumentationRegistry;
import com.android.intentresolver.ResolvedComponentInfo;
+import com.android.intentresolver.chooser.TargetInfo;
+
+import com.google.android.collect.Lists;
import org.junit.Test;
@@ -37,51 +40,82 @@ public class AbstractResolverComparatorTest {
@Test
public void testPinned() {
- ResolvedComponentInfo r1 = new ResolvedComponentInfo(
- new ComponentName("package", "class"), new Intent(), new ResolveInfo()
- );
+ ResolvedComponentInfo r1 = createResolvedComponentInfo(
+ new ComponentName("package", "class"));
r1.setPinned(true);
- ResolvedComponentInfo r2 = new ResolvedComponentInfo(
- new ComponentName("zackage", "zlass"), new Intent(), new ResolveInfo()
- );
+ ResolvedComponentInfo r2 = createResolvedComponentInfo(
+ new ComponentName("zackage", "zlass"));
Context context = InstrumentationRegistry.getTargetContext();
- AbstractResolverComparator comparator = getTestComparator(context);
+ AbstractResolverComparator comparator = getTestComparator(context, null);
assertEquals("Pinned ranks over unpinned", -1, comparator.compare(r1, r2));
assertEquals("Unpinned ranks under pinned", 1, comparator.compare(r2, r1));
}
-
@Test
public void testBothPinned() {
- ResolveInfo pmInfo1 = new ResolveInfo();
- pmInfo1.activityInfo = new ActivityInfo();
- pmInfo1.activityInfo.packageName = "aaa";
-
- ResolvedComponentInfo r1 = new ResolvedComponentInfo(
- new ComponentName("package", "class"), new Intent(), pmInfo1);
+ ResolvedComponentInfo r1 = createResolvedComponentInfo(
+ new ComponentName("package", "class"));
r1.setPinned(true);
- ResolveInfo pmInfo2 = new ResolveInfo();
- pmInfo2.activityInfo = new ActivityInfo();
- pmInfo2.activityInfo.packageName = "zzz";
- ResolvedComponentInfo r2 = new ResolvedComponentInfo(
- new ComponentName("zackage", "zlass"), new Intent(), pmInfo2);
+ ResolvedComponentInfo r2 = createResolvedComponentInfo(
+ new ComponentName("zackage", "zlass"));
r2.setPinned(true);
Context context = InstrumentationRegistry.getTargetContext();
- AbstractResolverComparator comparator = getTestComparator(context);
+ AbstractResolverComparator comparator = getTestComparator(context, null);
assertEquals("Both pinned should rank alphabetically", -1, comparator.compare(r1, r2));
}
- private AbstractResolverComparator getTestComparator(Context context) {
+ @Test
+ public void testPromoteToFirst() {
+ ComponentName promoteToFirst = new ComponentName("promoted-package", "class");
+ ResolvedComponentInfo r1 = createResolvedComponentInfo(promoteToFirst);
+
+ ResolvedComponentInfo r2 = createResolvedComponentInfo(
+ new ComponentName("package", "class"));
+
+ Context context = InstrumentationRegistry.getTargetContext();
+ AbstractResolverComparator comparator = getTestComparator(context, promoteToFirst);
+
+ assertEquals("PromoteToFirst ranks over non-cemented", -1, comparator.compare(r1, r2));
+ assertEquals("Non-cemented ranks under PromoteToFirst", 1, comparator.compare(r2, r1));
+ }
+
+ @Test
+ public void testPromoteToFirstOverPinned() {
+ ComponentName cementedComponent = new ComponentName("promoted-package", "class");
+ ResolvedComponentInfo r1 = createResolvedComponentInfo(cementedComponent);
+
+ ResolvedComponentInfo r2 = createResolvedComponentInfo(
+ new ComponentName("package", "class"));
+ r2.setPinned(true);
+
+ Context context = InstrumentationRegistry.getTargetContext();
+ AbstractResolverComparator comparator = getTestComparator(context, cementedComponent);
+
+ assertEquals("PromoteToFirst ranks over pinned", -1, comparator.compare(r1, r2));
+ assertEquals("Pinned ranks under PromoteToFirst", 1, comparator.compare(r2, r1));
+ }
+
+ private ResolvedComponentInfo createResolvedComponentInfo(ComponentName component) {
+ ResolveInfo info = new ResolveInfo();
+ info.activityInfo = new ActivityInfo();
+ info.activityInfo.packageName = component.getPackageName();
+ info.activityInfo.name = component.getClassName();
+ return new ResolvedComponentInfo(component, new Intent(), info);
+ }
+
+ private AbstractResolverComparator getTestComparator(
+ Context context, ComponentName promoteToFirst) {
Intent intent = new Intent();
AbstractResolverComparator testComparator =
- new AbstractResolverComparator(context, intent) {
+ new AbstractResolverComparator(context, intent,
+ Lists.newArrayList(context.getUser()), promoteToFirst) {
@Override
int compare(ResolveInfo lhs, ResolveInfo rhs) {
@@ -94,7 +128,7 @@ public class AbstractResolverComparatorTest {
void doCompute(List<ResolvedComponentInfo> targets) {}
@Override
- public float getScore(ComponentName name) {
+ public float getScore(TargetInfo targetInfo) {
return 0;
}
diff --git a/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt b/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt
index 0c817cb2..742aac71 100644
--- a/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt
+++ b/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt
@@ -26,7 +26,9 @@ import android.content.pm.PackageManager.ApplicationInfoFlags
import android.content.pm.ShortcutManager
import android.os.UserHandle
import android.os.UserManager
+import androidx.lifecycle.Lifecycle
import androidx.test.filters.SmallTest
+import com.android.intentresolver.TestLifecycleOwner
import com.android.intentresolver.any
import com.android.intentresolver.argumentCaptor
import com.android.intentresolver.capture
@@ -36,19 +38,27 @@ import com.android.intentresolver.createShareShortcutInfo
import com.android.intentresolver.createShortcutInfo
import com.android.intentresolver.mock
import com.android.intentresolver.whenever
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestCoroutineScheduler
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.setMain
+import org.junit.After
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
+import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import java.util.concurrent.Executor
import java.util.function.Consumer
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
class ShortcutLoaderTest {
private val appInfo = ApplicationInfo().apply {
@@ -58,7 +68,7 @@ class ShortcutLoaderTest {
private val pm = mock<PackageManager> {
whenever(getApplicationInfo(any(), any<ApplicationInfoFlags>())).thenReturn(appInfo)
}
- val userManager = mock<UserManager> {
+ private val userManager = mock<UserManager> {
whenever(isUserRunning(any<UserHandle>())).thenReturn(true)
whenever(isUserUnlocked(any<UserHandle>())).thenReturn(true)
whenever(isQuietModeEnabled(any<UserHandle>())).thenReturn(false)
@@ -68,32 +78,46 @@ class ShortcutLoaderTest {
whenever(createContextAsUser(any(), anyInt())).thenReturn(this)
whenever(getSystemService(Context.USER_SERVICE)).thenReturn(userManager)
}
- private val executor = ImmediateExecutor()
+ private val scheduler = TestCoroutineScheduler()
+ private val dispatcher = UnconfinedTestDispatcher(scheduler)
+ private val lifecycleOwner = TestLifecycleOwner()
private val intentFilter = mock<IntentFilter>()
private val appPredictor = mock<ShortcutLoader.AppPredictorProxy>()
private val callback = mock<Consumer<ShortcutLoader.Result>>()
+ private val componentName = ComponentName("pkg", "Class")
+ private val appTarget = mock<DisplayResolveInfo> {
+ whenever(resolvedComponentName).thenReturn(componentName)
+ }
+ private val appTargets = arrayOf(appTarget)
+ private val matchingShortcutInfo = createShortcutInfo("id-0", componentName, 1)
+
+ @Before
+ fun setup() {
+ Dispatchers.setMain(dispatcher)
+ lifecycleOwner.state = Lifecycle.State.CREATED
+ }
+
+ @After
+ fun cleanup() {
+ lifecycleOwner.state = Lifecycle.State.DESTROYED
+ Dispatchers.resetMain()
+ }
@Test
- fun test_queryShortcuts_result_consistency_with_AppPredictor() {
- val componentName = ComponentName("pkg", "Class")
- val appTarget = mock<DisplayResolveInfo> {
- whenever(resolvedComponentName).thenReturn(componentName)
- }
- val appTargets = arrayOf(appTarget)
+ fun test_loadShortcutsWithAppPredictor_resultIntegrity() {
val testSubject = ShortcutLoader(
context,
+ lifecycleOwner.lifecycle,
appPredictor,
UserHandle.of(0),
true,
intentFilter,
- executor,
- executor,
+ dispatcher,
callback
)
- testSubject.queryShortcuts(appTargets)
+ testSubject.updateAppTargets(appTargets)
- val matchingShortcutInfo = createShortcutInfo("id-0", componentName, 1)
val matchingAppTarget = createAppTarget(matchingShortcutInfo)
val shortcuts = listOf(
matchingAppTarget,
@@ -130,13 +154,7 @@ class ShortcutLoaderTest {
}
@Test
- fun test_queryShortcuts_result_consistency_with_ShortcutManager() {
- val componentName = ComponentName("pkg", "Class")
- val appTarget = mock<DisplayResolveInfo> {
- whenever(resolvedComponentName).thenReturn(componentName)
- }
- val appTargets = arrayOf(appTarget)
- val matchingShortcutInfo = createShortcutInfo("id-0", componentName, 1)
+ fun test_loadShortcutsWithShortcutManager_resultIntegrity() {
val shortcutManagerResult = listOf(
ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName),
// mismatching shortcut
@@ -148,16 +166,16 @@ class ShortcutLoaderTest {
whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager)
val testSubject = ShortcutLoader(
context,
+ lifecycleOwner.lifecycle,
null,
UserHandle.of(0),
true,
intentFilter,
- executor,
- executor,
+ dispatcher,
callback
)
- testSubject.queryShortcuts(appTargets)
+ testSubject.updateAppTargets(appTargets)
val resultCaptor = argumentCaptor<ShortcutLoader.Result>()
verify(callback, times(1)).accept(capture(resultCaptor))
@@ -181,13 +199,7 @@ class ShortcutLoaderTest {
}
@Test
- fun test_queryShortcuts_falls_back_to_ShortcutManager_on_empty_reply() {
- val componentName = ComponentName("pkg", "Class")
- val appTarget = mock<DisplayResolveInfo> {
- whenever(resolvedComponentName).thenReturn(componentName)
- }
- val appTargets = arrayOf(appTarget)
- val matchingShortcutInfo = createShortcutInfo("id-0", componentName, 1)
+ fun test_appPredictorReturnsEmptyList_fallbackToShortcutManager() {
val shortcutManagerResult = listOf(
ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName),
// mismatching shortcut
@@ -199,16 +211,16 @@ class ShortcutLoaderTest {
whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager)
val testSubject = ShortcutLoader(
context,
+ lifecycleOwner.lifecycle,
appPredictor,
UserHandle.of(0),
true,
intentFilter,
- executor,
- executor,
+ dispatcher,
callback
)
- testSubject.queryShortcuts(appTargets)
+ testSubject.updateAppTargets(appTargets)
verify(appPredictor, times(1)).requestPredictionUpdate()
val appPredictorCallbackCaptor = argumentCaptor<AppPredictor.Callback>()
@@ -238,32 +250,154 @@ class ShortcutLoaderTest {
}
@Test
- fun test_queryShortcuts_do_not_call_services_for_not_running_work_profile() {
+ fun test_appPredictor_requestPredictionUpdateFailure_fallbackToShortcutManager() {
+ val shortcutManagerResult = listOf(
+ ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName),
+ // mismatching shortcut
+ createShareShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1)
+ )
+ val shortcutManager = mock<ShortcutManager> {
+ whenever(getShareTargets(intentFilter)).thenReturn(shortcutManagerResult)
+ }
+ whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager)
+ whenever(appPredictor.requestPredictionUpdate())
+ .thenThrow(IllegalStateException("Test exception"))
+ val testSubject = ShortcutLoader(
+ context,
+ lifecycleOwner.lifecycle,
+ appPredictor,
+ UserHandle.of(0),
+ true,
+ intentFilter,
+ dispatcher,
+ callback
+ )
+
+ testSubject.updateAppTargets(appTargets)
+
+ verify(appPredictor, times(1)).requestPredictionUpdate()
+
+ val resultCaptor = argumentCaptor<ShortcutLoader.Result>()
+ verify(callback, times(1)).accept(capture(resultCaptor))
+
+ val result = resultCaptor.value
+ assertFalse("An ShortcutManager result is expected", result.isFromAppPredictor)
+ assertArrayEquals("Wrong input app targets in the result", appTargets, result.appTargets)
+ assertEquals("Wrong shortcut count", 1, result.shortcutsByApp.size)
+ assertEquals("Wrong app target", appTarget, result.shortcutsByApp[0].appTarget)
+ for (shortcut in result.shortcutsByApp[0].shortcuts) {
+ assertTrue(
+ "AppTargets are not expected the cache of a ShortcutManager result",
+ result.directShareAppTargetCache.isEmpty()
+ )
+ assertEquals(
+ "Wrong ShortcutInfo in the cache",
+ matchingShortcutInfo,
+ result.directShareShortcutInfoCache[shortcut]
+ )
+ }
+ }
+
+ @Test
+ fun test_ShortcutLoader_shortcutsRequestedIndependentlyFromAppTargets() {
+ ShortcutLoader(
+ context,
+ lifecycleOwner.lifecycle,
+ appPredictor,
+ UserHandle.of(0),
+ true,
+ intentFilter,
+ dispatcher,
+ callback
+ )
+
+ verify(appPredictor, times(1)).requestPredictionUpdate()
+ verify(callback, never()).accept(any())
+ }
+
+ @Test
+ fun test_ShortcutLoader_noResultsWithoutAppTargets() {
+ val shortcutManagerResult = listOf(
+ ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName),
+ // mismatching shortcut
+ createShareShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1)
+ )
+ val shortcutManager = mock<ShortcutManager> {
+ whenever(getShareTargets(intentFilter)).thenReturn(shortcutManagerResult)
+ }
+ whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager)
+ val testSubject = ShortcutLoader(
+ context,
+ lifecycleOwner.lifecycle,
+ null,
+ UserHandle.of(0),
+ true,
+ intentFilter,
+ dispatcher,
+ callback
+ )
+
+ verify(shortcutManager, times(1)).getShareTargets(any())
+ verify(callback, never()).accept(any())
+
+ testSubject.reset()
+
+ verify(shortcutManager, times(2)).getShareTargets(any())
+ verify(callback, never()).accept(any())
+
+ testSubject.updateAppTargets(appTargets)
+
+ verify(shortcutManager, times(2)).getShareTargets(any())
+ verify(callback, times(1)).accept(any())
+ }
+
+ @Test
+ fun test_OnLifecycleDestroyed_unsubscribeFromAppPredictor() {
+ ShortcutLoader(
+ context,
+ lifecycleOwner.lifecycle,
+ appPredictor,
+ UserHandle.of(0),
+ true,
+ intentFilter,
+ dispatcher,
+ callback
+ )
+
+ verify(appPredictor, never()).unregisterPredictionUpdates(any())
+
+ lifecycleOwner.state = Lifecycle.State.DESTROYED
+
+ verify(appPredictor, times(1)).unregisterPredictionUpdates(any())
+ }
+
+ @Test
+ fun test_workProfileNotRunning_doNotCallServices() {
testDisabledWorkProfileDoNotCallSystem(isUserRunning = false)
}
@Test
- fun test_queryShortcuts_do_not_call_services_for_locked_work_profile() {
+ fun test_workProfileLocked_doNotCallServices() {
testDisabledWorkProfileDoNotCallSystem(isUserUnlocked = false)
}
@Test
- fun test_queryShortcuts_do_not_call_services_if_quite_mode_is_enabled_for_work_profile() {
+ fun test_workProfileQuiteModeEnabled_doNotCallServices() {
testDisabledWorkProfileDoNotCallSystem(isQuietModeEnabled = true)
}
@Test
- fun test_queryShortcuts_call_services_for_not_running_main_profile() {
+ fun test_mainProfileNotRunning_callServicesAnyway() {
testAlwaysCallSystemForMainProfile(isUserRunning = false)
}
@Test
- fun test_queryShortcuts_call_services_for_locked_main_profile() {
+ fun test_mainProfileLocked_callServicesAnyway() {
testAlwaysCallSystemForMainProfile(isUserUnlocked = false)
}
@Test
- fun test_queryShortcuts_call_services_if_quite_mode_is_enabled_for_main_profile() {
+ fun test_mainProfileQuiteModeEnabled_callServicesAnyway() {
testAlwaysCallSystemForMainProfile(isQuietModeEnabled = true)
}
@@ -283,16 +417,16 @@ class ShortcutLoaderTest {
val callback = mock<Consumer<ShortcutLoader.Result>>()
val testSubject = ShortcutLoader(
context,
+ lifecycleOwner.lifecycle,
appPredictor,
userHandle,
false,
intentFilter,
- executor,
- executor,
+ dispatcher,
callback
)
- testSubject.queryShortcuts(arrayOf<DisplayResolveInfo>(mock()))
+ testSubject.updateAppTargets(arrayOf<DisplayResolveInfo>(mock()))
verify(appPredictor, never()).requestPredictionUpdate()
}
@@ -313,23 +447,17 @@ class ShortcutLoaderTest {
val callback = mock<Consumer<ShortcutLoader.Result>>()
val testSubject = ShortcutLoader(
context,
+ lifecycleOwner.lifecycle,
appPredictor,
userHandle,
true,
intentFilter,
- executor,
- executor,
+ dispatcher,
callback
)
- testSubject.queryShortcuts(arrayOf<DisplayResolveInfo>(mock()))
+ testSubject.updateAppTargets(arrayOf<DisplayResolveInfo>(mock()))
verify(appPredictor, times(1)).requestPredictionUpdate()
}
}
-
-private class ImmediateExecutor : Executor {
- override fun execute(r: Runnable) {
- r.run()
- }
-}
diff --git a/java/tests/src/com/android/intentresolver/util/UriFiltersTest.kt b/java/tests/src/com/android/intentresolver/util/UriFiltersTest.kt
new file mode 100644
index 00000000..18218064
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/util/UriFiltersTest.kt
@@ -0,0 +1,95 @@
+package com.android.intentresolver.util
+
+import android.app.PendingIntent
+import android.content.IIntentReceiver
+import android.content.IIntentSender
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.Binder
+import android.os.Bundle
+import android.os.IBinder
+import android.os.UserHandle
+import android.service.chooser.ChooserAction
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class UriFiltersTest {
+
+ @Test
+ fun uri_ownedByCurrentUser_noUserId() {
+ val uri = Uri.parse("content://media/images/12345")
+ assertTrue("Uri without userId should always return true", uri.ownedByCurrentUser)
+ }
+
+ @Test
+ fun uri_ownedByCurrentUser_selfUserId() {
+ val uri = Uri.parse("content://${UserHandle.myUserId()}@media/images/12345")
+ assertTrue("Uri with own userId should return true", uri.ownedByCurrentUser)
+ }
+
+ @Test
+ fun uri_ownedByCurrentUser_otherUserId() {
+ val otherUserId = UserHandle.myUserId() + 10
+ val uri = Uri.parse("content://${otherUserId}@media/images/12345")
+ assertFalse("Uri with other userId should return false", uri.ownedByCurrentUser)
+ }
+
+ @Test
+ fun chooserAction_hasValidIcon_bitmap() =
+ smallBitmap().use {
+ val icon = Icon.createWithBitmap(it)
+ val action = actionWithIcon(icon)
+ assertTrue("No uri, assumed valid", hasValidIcon(action))
+ }
+
+ @Test
+ fun chooserAction_hasValidIcon_uri() {
+ val icon = Icon.createWithContentUri("content://provider/content/12345")
+ assertTrue("No userId in uri, uri is valid", hasValidIcon(actionWithIcon(icon)))
+ }
+ @Test
+ fun chooserAction_hasValidIcon_uri_unowned() {
+ val userId = UserHandle.myUserId() + 10
+ val icon = Icon.createWithContentUri("content://${userId}@provider/content/12345")
+ assertFalse("uri userId references a different user", hasValidIcon(actionWithIcon(icon)))
+ }
+
+ private fun smallBitmap() = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
+
+ private fun mockAction(): PendingIntent {
+ return PendingIntent(
+ object : IIntentSender {
+ override fun asBinder(): IBinder = Binder()
+ override fun send(
+ code: Int,
+ intent: Intent?,
+ resolvedType: String?,
+ whitelistToken: IBinder?,
+ finishedReceiver: IIntentReceiver?,
+ requiredPermission: String?,
+ options: Bundle?
+ ) {
+ /* empty */
+ }
+ }
+ )
+ }
+
+ private fun actionWithIcon(icon: Icon): ChooserAction {
+ return ChooserAction.Builder(icon, "", mockAction()).build()
+ }
+
+ /** Unconditionally recycles the [Bitmap] after running the given block */
+ private fun Bitmap.use(block: (Bitmap) -> Unit) =
+ try {
+ block(this)
+ } finally {
+ recycle()
+ }
+}
diff --git a/java/tests/src/com/android/intentresolver/widget/BatchPreviewLoaderTest.kt b/java/tests/src/com/android/intentresolver/widget/BatchPreviewLoaderTest.kt
new file mode 100644
index 00000000..e65cba5f
--- /dev/null
+++ b/java/tests/src/com/android/intentresolver/widget/BatchPreviewLoaderTest.kt
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.widget
+
+import android.graphics.Bitmap
+import android.net.Uri
+import com.android.intentresolver.captureMany
+import com.android.intentresolver.mock
+import com.android.intentresolver.widget.ScrollableImagePreviewView.BatchPreviewLoader
+import com.android.intentresolver.widget.ScrollableImagePreviewView.Preview
+import com.android.intentresolver.widget.ScrollableImagePreviewView.PreviewType
+import com.android.intentresolver.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.atLeast
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class BatchPreviewLoaderTest {
+ private val dispatcher = UnconfinedTestDispatcher()
+ private val testScope = CoroutineScope(dispatcher)
+ private val onCompletion = mock<() -> Unit>()
+ private val onReset = mock<(Int) -> Unit>()
+ private val onUpdate = mock<(List<Preview>) -> Unit>()
+
+ @Before
+ fun setup() {
+ Dispatchers.setMain(dispatcher)
+ }
+
+ @After
+ fun cleanup() {
+ testScope.cancel()
+ Dispatchers.resetMain()
+ }
+
+ @Test
+ fun test_allImagesWithinViewPort_oneUpdate() {
+ val imageLoader = TestImageLoader(testScope)
+ val uriOne = createUri(1)
+ val uriTwo = createUri(2)
+ imageLoader.setUriLoadingOrder(succeed(uriTwo), succeed(uriOne))
+ val testSubject =
+ BatchPreviewLoader(
+ imageLoader,
+ previews(uriOne, uriTwo),
+ 0,
+ onReset,
+ onUpdate,
+ onCompletion
+ )
+ testSubject.loadAspectRatios(200) { _, _, _ -> 100 }
+ dispatcher.scheduler.advanceUntilIdle()
+
+ verify(onCompletion, times(1)).invoke()
+ verify(onReset, times(1)).invoke(2)
+ val list = withArgCaptor { verify(onUpdate, times(1)).invoke(capture()) }.map { it.uri }
+ assertThat(list).containsExactly(uriOne, uriTwo).inOrder()
+ }
+
+ @Test
+ fun test_allImagesWithinViewPortOneFailed_failedPreviewIsNotUpdated() {
+ val imageLoader = TestImageLoader(testScope)
+ val uriOne = createUri(1)
+ val uriTwo = createUri(2)
+ val uriThree = createUri(3)
+ imageLoader.setUriLoadingOrder(succeed(uriThree), fail(uriTwo), succeed(uriOne))
+ val testSubject =
+ BatchPreviewLoader(
+ imageLoader,
+ previews(uriOne, uriTwo, uriThree),
+ 0,
+ onReset,
+ onUpdate,
+ onCompletion
+ )
+ testSubject.loadAspectRatios(200) { _, _, _ -> 100 }
+ dispatcher.scheduler.advanceUntilIdle()
+
+ verify(onCompletion, times(1)).invoke()
+ verify(onReset, times(1)).invoke(3)
+ val list = withArgCaptor { verify(onUpdate, times(1)).invoke(capture()) }.map { it.uri }
+ assertThat(list).containsExactly(uriOne, uriThree).inOrder()
+ }
+
+ @Test
+ fun test_imagesLoadedNotInOrder_updatedInOrder() {
+ val imageLoader = TestImageLoader(testScope)
+ val uris = Array(10) { createUri(it) }
+ val loadingOrder =
+ Array(uris.size) { i ->
+ val uriIdx =
+ when {
+ i % 2 == 1 -> i - 1
+ i % 2 == 0 && i < uris.size - 1 -> i + 1
+ else -> i
+ }
+ succeed(uris[uriIdx])
+ }
+ imageLoader.setUriLoadingOrder(*loadingOrder)
+ val testSubject =
+ BatchPreviewLoader(imageLoader, previews(*uris), 0, onReset, onUpdate, onCompletion)
+ testSubject.loadAspectRatios(200) { _, _, _ -> 100 }
+ dispatcher.scheduler.advanceUntilIdle()
+
+ verify(onCompletion, times(1)).invoke()
+ verify(onReset, times(1)).invoke(uris.size)
+ val list =
+ captureMany { verify(onUpdate, atLeast(1)).invoke(capture()) }
+ .fold(ArrayList<Preview>()) { acc, update -> acc.apply { addAll(update) } }
+ .map { it.uri }
+ assertThat(list).containsExactly(*uris).inOrder()
+ }
+
+ @Test
+ fun test_imagesLoadedNotInOrderSomeFailed_updatedInOrder() {
+ val imageLoader = TestImageLoader(testScope)
+ val uris = Array(10) { createUri(it) }
+ val loadingOrder =
+ Array(uris.size) { i ->
+ val uriIdx =
+ when {
+ i % 2 == 1 -> i - 1
+ i % 2 == 0 && i < uris.size - 1 -> i + 1
+ else -> i
+ }
+ if (uriIdx % 2 == 0) fail(uris[uriIdx]) else succeed(uris[uriIdx])
+ }
+ val expectedUris = Array(uris.size / 2) { createUri(it * 2 + 1) }
+ imageLoader.setUriLoadingOrder(*loadingOrder)
+ val testSubject =
+ BatchPreviewLoader(imageLoader, previews(*uris), 0, onReset, onUpdate, onCompletion)
+ testSubject.loadAspectRatios(200) { _, _, _ -> 100 }
+ dispatcher.scheduler.advanceUntilIdle()
+
+ verify(onCompletion, times(1)).invoke()
+ verify(onReset, times(1)).invoke(uris.size)
+ val list =
+ captureMany { verify(onUpdate, atLeast(1)).invoke(capture()) }
+ .fold(ArrayList<Preview>()) { acc, update -> acc.apply { addAll(update) } }
+ .map { it.uri }
+ assertThat(list).containsExactly(*expectedUris).inOrder()
+ }
+
+ private fun createUri(idx: Int): Uri = Uri.parse("content://org.pkg.app/image-$idx.png")
+
+ private fun fail(uri: Uri) = uri to false
+ private fun succeed(uri: Uri) = uri to true
+ private fun previews(vararg uris: Uri) =
+ uris.fold(ArrayList<Preview>(uris.size)) { acc, uri ->
+ acc.apply { add(Preview(PreviewType.Image, uri, editAction = null)) }
+ }
+}
+
+private class TestImageLoader(scope: CoroutineScope) : suspend (Uri, Boolean) -> Bitmap? {
+ private val loadingOrder = ArrayDeque<Pair<Uri, Boolean>>()
+ private val pendingRequests = LinkedHashMap<Uri, CompletableDeferred<Bitmap?>>()
+ private val flow = MutableSharedFlow<Unit>(replay = 1)
+ private val bitmap by lazy { Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888) }
+
+ init {
+ scope.launch {
+ flow.collect {
+ while (true) {
+ val (nextUri, isLoaded) = loadingOrder.firstOrNull() ?: break
+ val deferred = pendingRequests.remove(nextUri) ?: break
+ loadingOrder.removeFirst()
+ deferred.complete(if (isLoaded) bitmap else null)
+ }
+ if (loadingOrder.isEmpty()) {
+ pendingRequests.forEach { (uri, deferred) -> deferred.complete(bitmap) }
+ pendingRequests.clear()
+ }
+ }
+ }
+ }
+
+ fun setUriLoadingOrder(vararg uris: Pair<Uri, Boolean>) {
+ loadingOrder.clear()
+ loadingOrder.addAll(uris)
+ }
+
+ override suspend fun invoke(uri: Uri, cache: Boolean): Bitmap? {
+ val deferred = pendingRequests.getOrPut(uri) { CompletableDeferred() }
+ flow.tryEmit(Unit)
+ return deferred.await()
+ }
+}