diff options
| author | 2023-08-14 15:42:50 -0700 | |
|---|---|---|
| committer | 2023-08-14 15:42:50 -0700 | |
| commit | 80bfff1f0eef6db4e061d9892450737e110bad59 (patch) | |
| tree | e586dfb61c90c1aec759f551cbac857895edaf83 /java | |
| parent | a0c4477fdbbae9857ead667a5227c3d93d9d3167 (diff) | |
| parent | 5e86e4846a4326b05fa747eaf7f1ba0fa89cd623 (diff) | |
Merge Android U (ab/10368041)
Bug: 291102124
Merged-In: If40fe5329a6f3835d1edaebdef2ff47a947a9943
Change-Id: Ide948ae0ca758570ba7dae69fdcaa6c066522a20
Diffstat (limited to 'java')
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() + } +} |