diff options
87 files changed, 1031 insertions, 660 deletions
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..cfd3a77a --- /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="#60000000" + android:endColor="#00000000" /> +</shape> diff --git a/java/res/drawable/content_preview_badge_bg.xml b/java/res/drawable/content_preview_badge_bg.xml index 7f7a1c6f..5ed53dc3 100644 --- a/java/res/drawable/content_preview_badge_bg.xml +++ b/java/res/drawable/content_preview_badge_bg.xml @@ -14,14 +14,15 @@ ~ 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="1" - android:centerY="0" - android:gradientRadius="@dimen/chooser_preview_image_height_tall" + android:centerX="0.5" + android:centerY="0.5" + android:gradientRadius="23dp" android:startColor="#60000000" android:endColor="#00000000" /> </shape> diff --git a/java/res/drawable/ic_file_video.xml b/java/res/drawable/ic_file_video.xml index d25b9ed0..ec6e290b 100644 --- a/java/res/drawable/ic_file_video.xml +++ b/java/res/drawable/ic_file_video.xml @@ -23,5 +23,5 @@ <path android:fillColor="@android:color/white" - android:pathData="M2 16C1.45 16 0.975 15.8083 0.575 15.425C0.191667 15.025 5.96046e-08 14.55 5.96046e-08 14V2C5.96046e-08 1.45 0.191667 0.983333 0.575 0.599998C0.975 0.199999 1.45 -9.53674e-07 2 -9.53674e-07H14C14.55 -9.53674e-07 15.0167 0.199999 15.4 0.599998C15.8 0.983333 16 1.45 16 2V6.5L20 2.5V13.5L16 9.5V14C16 14.55 15.8 15.025 15.4 15.425C15.0167 15.8083 14.55 16 14 16H2ZM2 14H14V2H2V14ZM2 14V2V14Z"/> + 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/layout-h480dp/image_preview_image_item.xml b/java/res/layout-h480dp/image_preview_image_item.xml new file mode 100644 index 00000000..52f88ea0 --- /dev/null +++ b/java/res/layout-h480dp/image_preview_image_item.xml @@ -0,0 +1,53 @@ +<!-- + ~ 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" + 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" /> + + <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:layout_marginEnd="6dp" + android:layout_marginTop="6dp" + android:tint="@android:color/white" + android:layout_gravity="top|end" /> + </FrameLayout> +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/java/res/layout/chooser_headline_row.xml b/java/res/layout/chooser_headline_row.xml index 8bee807a..e1668d25 100644 --- a/java/res/layout/chooser_headline_row.xml +++ b/java/res/layout/chooser_headline_row.xml @@ -22,6 +22,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingHorizontal="@dimen/chooser_edge_margin_normal" + android:layout_marginBottom="16dp" > <TextView android:id="@+id/headline" @@ -35,7 +36,6 @@ style="@style/TextAppearance.ChooserDefault" android:fontFamily="@androidprv:string/config_headlineFontFamily" android:textSize="18sp" - android:paddingBottom="16dp" /> <androidx.constraintlayout.widget.Barrier @@ -55,7 +55,6 @@ android:ellipsize="end" android:visibility="gone" android:paddingTop="3dp" - android:paddingBottom="16dp" style="@style/TextAppearance.ChooserDefault" android:drawableEnd="@drawable/chevron_right" /> @@ -67,6 +66,8 @@ 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" diff --git a/java/res/layout/image_preview_image_item.xml b/java/res/layout/image_preview_image_item.xml index 52f88ea0..3f534831 100644 --- a/java/res/layout/image_preview_image_item.xml +++ b/java/res/layout/image_preview_image_item.xml @@ -14,21 +14,21 @@ ~ limitations under the License. --> +<!-- 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" xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="wrap_content" - android:layout_height="@dimen/chooser_preview_image_height_tall"> + android:layout_width="46dp" + android:layout_height="46dp"> <com.android.intentresolver.widget.RoundedRectImageView android:id="@+id/image" - android:layout_width="0dp" + android:layout_width="match_parent" 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" /> + app:radius="8dp" /> <FrameLayout android:id="@+id/badge_frame" @@ -45,9 +45,7 @@ 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" /> + android:layout_gravity="center" /> </FrameLayout> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml index 383e812d..bdbe0de9 100644 --- a/java/res/values-am/strings.xml +++ b/java/res/values-am/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{ቪድዮ ከአገናኝ ጋር በማጋራት ላይ}one{# ቪድዮ ከአገናኝ ጋር በማጋራት ላይ}other{# ቪድዮዎችን ከአገናኝ ጋር በማጋራት ላይ}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{ፋይልን ከጽሑፍ ጋር በማጋራት ላይ}one{# ፋይልን ከጽሑፍ ጋር በማጋራት ላይ}other{# ፋይሎችን ከጽሑፍ ጋር በማጋራት ላይ}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{ፋይልን ከአገናኝ ጋር በማጋራት ላይ}one{# ፋይልን ከአገናኝ ጋር በማጋራት ላይ}other{# ፋይሎችን ከአገናኝ ጋር በማጋራት ላይ}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{ምስል ብቻ}one{ምስል ብቻ}other{ምስሎች ብቻ}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{ቪድዮ ብቻ}one{ቪድዮ ብቻ}other{ቪድዮዎች ብቻ}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{ፋይል ብቻ}one{ፋይል ብቻ}other{ፋይሎች ብቻ}}"</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> diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml index 5a7e115c..df1abf13 100644 --- a/java/res/values-ar/strings.xml +++ b/java/res/values-ar/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{مشاركة فيديو واحد ورابط}zero{مشاركة # فيديو ورابط}two{مشاركة فيديوهَين ورابط}few{مشاركة # فيديوهات ورابط}many{مشاركة # فيديو ورابط}other{مشاركة # فيديو ورابط}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{مشاركة ملف واحد ونص}zero{مشاركة # ملف ونص}two{مشاركة # ملفَّين ونص}few{مشاركة # ملفات ونص}many{مشاركة # ملفًا ونص}other{مشاركة # ملف ونص}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{مشاركة ملف واحد ورابط}zero{مشاركة # ملف ورابط}two{مشاركة ملفَّين ورابط}few{مشاركة # ملفات ورابط}many{مشاركة # ملفًا ورابط}other{مشاركة # ملف ورابط}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{الصورة فقط}zero{الصور فقط}two{الصورتان فقط}few{الصور فقط}many{الصور فقط}other{الصور فقط}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{الفيديو فقط}zero{الفيديوهات فقط}two{الفيديوهان فقط}few{الفيديوهات فقط}many{الفيديوهات فقط}other{الفيديوهات فقط}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{الملف فقط}zero{الملفات فقط}two{الملفان فقط}few{الملفات فقط}many{الملفات فقط}other{الملفات فقط}}"</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> diff --git a/java/res/values-az/strings.xml b/java/res/values-az/strings.xml index 5d4d5a10..4cae65f6 100644 --- a/java/res/values-az/strings.xml +++ b/java/res/values-az/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Link olan video paylaşılır}other{Link olan # video paylaşılır}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Mətn olan fayl paylaşılır}other{Mətn olan # fayl paylaşılır}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Link olan fayl paylaşılır}other{Link olan # fayl paylaşılır}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Yalnız şəkil}other{Yalnız şəkillər}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Yalnız video}other{Yalnız videolar}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Yalnız fayl}other{Yalnız fayllar}}"</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> diff --git a/java/res/values-b+sr+Latn/strings.xml b/java/res/values-b+sr+Latn/strings.xml index eaa4b753..50b67a77 100644 --- a/java/res/values-b+sr+Latn/strings.xml +++ b/java/res/values-b+sr+Latn/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Deli se video sa linkom}one{Deli se # video sa linkom}few{Dele se # video snimka sa linkom}other{Deli se # video snimaka sa linkom}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Deli se fajl sa tekstom}one{Deli se # fajl sa tekstom}few{Dele se # fajla sa tekstom}other{Deli se # fajlova sa tekstom}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Deli se fajl sa linkom}one{Deli se # fajl sa linkom}few{Dele se # fajla sa linkom}other{Deli se # fajlova sa linkom}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Samo slika}one{Samo slike}few{Samo slike}other{Samo slike}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Samo video}one{Samo video snimci}few{Samo video snimci}other{Samo video snimci}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Samo fajl}one{Samo fajlovi}few{Samo fajlovi}other{Samo fajlovi}}"</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> @@ -85,7 +82,7 @@ <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="7115260573975624516">"Poslovne aplikacije su pauzirane"</string> - <string name="resolver_switch_on_work" msgid="8678893259344318807">"Opozovi pauzu"</string> + <string name="resolver_switch_on_work" msgid="8678893259344318807">"Ponovo aktiviraj"</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> diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml index 4a8ea5c9..e2fb4315 100644 --- a/java/res/values-be/strings.xml +++ b/java/res/values-be/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Абагульванне відэа са спасылкай}one{Абагульванне # відэа са спасылкай}few{Абагульванне # відэа са спасылкай}many{Абагульванне # відэа са спасылкай}other{Абагульванне # відэа са спасылкай}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Абагульванне файла з тэкстам}one{Абагульванне # файла з тэкстам}few{Абагульванне # файлаў з тэкстам}many{Абагульванне # файлаў з тэкстам}other{Абагульванне # файла з тэкстам}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Абагульванне файла са спасылкай}one{Абагульванне # файла са спасылкай}few{Абагульванне # файлаў са спасылкай}many{Абагульванне # файлаў са спасылкай}other{Абагульванне # файла са спасылкай}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Толькі відарыс}one{Толькі відарысы}few{Толькі відарысы}many{Толькі відарысы}other{Толькі відарысы}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Толькі відэа}one{Толькі відэа}few{Толькі відэа}many{Толькі відэа}other{Толькі відэа}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Толькі файл}one{Толькі файлы}few{Толькі файлы}many{Толькі файлы}other{Толькі файлы}}"</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> diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml index f9ad2f01..dd5e032b 100644 --- a/java/res/values-bg/strings.xml +++ b/java/res/values-bg/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Споделяне на видеоклипа чрез връзка}other{Споделяне на # видеоклипа чрез връзка}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Споделяне на файла чрез SMS съобщение}other{Споделяне на # файла чрез SMS съобщение}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Споделяне на файла чрез връзка}other{Споделяне на # файла чрез връзка}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Само изображение}other{Само изображения}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Само видеоклип}other{Само видеоклипове}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Само файл}other{Само файлове}}"</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> diff --git a/java/res/values-bs/strings.xml b/java/res/values-bs/strings.xml index da00d589..25dd634a 100644 --- a/java/res/values-bs/strings.xml +++ b/java/res/values-bs/strings.xml @@ -82,7 +82,7 @@ <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="7115260573975624516">"Poslovne aplikacije su pauzirane"</string> - <string name="resolver_switch_on_work" msgid="8678893259344318807">"Prekini pauzu"</string> + <string name="resolver_switch_on_work" msgid="8678893259344318807">"Ponovo pokreni"</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> diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml index 643fdabe..07aeb9a2 100644 --- a/java/res/values-ca/strings.xml +++ b/java/res/values-ca/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{S\'està compartint el vídeo amb un enllaç}many{S\'estan compartint # de vídeos amb un enllaç}other{S\'estan compartint # vídeos amb un enllaç}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{S\'està compartint el fitxer amb text}many{S\'estan compartint # de fitxers amb text}other{S\'estan compartint # fitxers amb text}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{S\'està compartint el fitxer amb un enllaç}many{S\'estan compartint # de fitxers amb un enllaç}other{S\'estan compartint # fitxers amb un enllaç}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Només imatge}many{Només imatges}other{Només imatges}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Només vídeo}many{Només vídeos}other{Només vídeos}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Només fitxer}many{Només fitxers}other{Només fitxers}}"</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> diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml index cf46be45..1a974d62 100644 --- a/java/res/values-cs/strings.xml +++ b/java/res/values-cs/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Sdílení videa s odkazem}few{Sdílení # videí s odkazem}many{Sdílení # videa s odkazem}other{Sdílení # videí s odkazem}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Sdílení souboru s textem}few{Sdílení # souborů s textem}many{Sdílení # souboru s textem}other{Sdílení # souborů s textem}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Sdílení souboru s odkazem}few{Sdílení # souborů s odkazem}many{Sdílení # souboru s odkazem}other{Sdílení # souborů s odkazem}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Pouze obrázek}few{Pouze obrázky}many{Pouze obrázky}other{Pouze obrázky}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Pouze video}few{Pouze videa}many{Pouze videa}other{Pouze videa}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Pouze soubor}few{Pouze soubory}many{Pouze soubory}other{Pouze soubory}}"</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> diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml index 2c41cbc8..cb6dc54e 100644 --- a/java/res/values-da/strings.xml +++ b/java/res/values-da/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Deler video med et link}one{Deler # video med et link}other{Deler # videoer med et link}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Deler fil med tekst}one{Deler # fil med tekst}other{Deler # filer med tekst}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Deler fil med et link}one{Deler # fil med et link}other{Deler # filer med et link}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Kun billedet}one{Kun billedet}other{Kun billeder}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Kun video}one{Kun video}other{Kun videoer}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Kun filen}one{Kun filen}other{Kun filer}}"</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> diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml index ca1eb878..3e549f4c 100644 --- a/java/res/values-de/strings.xml +++ b/java/res/values-de/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Video wird per Link geteilt}other{# Videos werden per Link geteilt}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Datei wird per SMS geteilt}other{# Dateien werden per SMS geteilt}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Datei wird per Link geteilt}other{# Dateien werden per Link geteilt}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Nur Bild}other{Nur Bilder}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Nur Video}other{Nur Videos}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Nur Datei}other{Nur Dateien}}"</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> diff --git a/java/res/values-en-rAU/strings.xml b/java/res/values-en-rAU/strings.xml index cd9a9f10..9d7239c9 100644 --- a/java/res/values-en-rAU/strings.xml +++ b/java/res/values-en-rAU/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Sharing video with link}other{Sharing # videos with link}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Sharing file with text}other{Sharing # files with text}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Sharing file with link}other{Sharing # files with link}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Image only}other{Images only}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Video only}other{Videos only}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{File only}other{Files only}}"</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> diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml index cd9a9f10..9d7239c9 100644 --- a/java/res/values-en-rGB/strings.xml +++ b/java/res/values-en-rGB/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Sharing video with link}other{Sharing # videos with link}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Sharing file with text}other{Sharing # files with text}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Sharing file with link}other{Sharing # files with link}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Image only}other{Images only}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Video only}other{Videos only}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{File only}other{Files only}}"</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> diff --git a/java/res/values-en-rIN/strings.xml b/java/res/values-en-rIN/strings.xml index cd9a9f10..9d7239c9 100644 --- a/java/res/values-en-rIN/strings.xml +++ b/java/res/values-en-rIN/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Sharing video with link}other{Sharing # videos with link}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Sharing file with text}other{Sharing # files with text}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Sharing file with link}other{Sharing # files with link}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Image only}other{Images only}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Video only}other{Videos only}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{File only}other{Files only}}"</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> diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml index bcaed2f5..ca5b3e2d 100644 --- a/java/res/values-es-rUS/strings.xml +++ b/java/res/values-es-rUS/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Compartir video con vínculo}many{Compartir # de videos con vínculo}other{Compartir # videos con vínculo}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Compartir archivo con texto}many{Compartir # de archivos con texto}other{Compartir # archivos con texto}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Compartir archivo con vínculo}many{Compartir # de archivos con vínculo}other{Compartir # archivos con vínculo}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Solo imagen}many{Solo imágenes}other{Solo imágenes}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Solo video}many{Solo videos}other{Solo videos}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Solo archivo}many{Solo archivos}other{Solo archivos}}"</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> diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml index a555c43a..c825934a 100644 --- a/java/res/values-es/strings.xml +++ b/java/res/values-es/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Compartiendo vídeo con enlace}many{Compartiendo # vídeos con enlace}other{Compartiendo # vídeos con enlace}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Compartiendo archivo con mensaje de texto}many{Compartiendo # archivos con mensaje de texto}other{Compartiendo # archivos con mensaje de texto}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Compartiendo archivo con enlace}many{Compartiendo # archivos con enlace}other{Compartiendo # archivos con enlace}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Solo imagen}many{Solo imágenes}other{Solo imágenes}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Solo vídeo}many{Solo vídeos}other{Solo vídeos}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Solo archivo}many{Solo archivos}other{Solo archivos}}"</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> diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml index dbd82dc8..0bf8a480 100644 --- a/java/res/values-et/strings.xml +++ b/java/res/values-et/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Linki sisaldava video jagamine}other{# linki sisaldava video jagamine}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Teksti sisaldava faili jagamine}other{# teksti sisaldava faili jagamine}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Linki sisaldava faili jagamine}other{# linki sisaldava faili jagamine}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Ainult pilt}other{Ainult pildid}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Ainult video}other{Ainult videod}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Ainult fail}other{Ainult failid}}"</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> diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml index 71499c70..849afc4b 100644 --- a/java/res/values-fi/strings.xml +++ b/java/res/values-fi/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Videota ja linkkiä jaetaan}other{# videota ja linkkiä jaetaan}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Tiedostoa ja tekstiä jaetaan}other{# tiedostoa ja tekstiä jaetaan}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Tiedostoa ja linkkiä jaetaan}other{# tiedostoa ja linkkiä jaetaan}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Vain kuva}other{Vain kuvat}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Vain video}other{Vain videot}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Vain tiedostot}other{Vain tiedostot}}"</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> diff --git a/java/res/values-fr-rCA/strings.xml b/java/res/values-fr-rCA/strings.xml index b487ff62..b310e6ec 100644 --- a/java/res/values-fr-rCA/strings.xml +++ b/java/res/values-fr-rCA/strings.xml @@ -60,24 +60,15 @@ <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_files" msgid="1275646542246028823">"{count,plural, =1{Partage de # fichier en cours…}one{Partage de # fichier en cours…}many{Partage de # de fichiers en cours…}other{Partage de # fichiers en cours…}}"</string> - <!-- no translation found for sharing_images_with_text (9005717434461730242) --> - <skip /> - <!-- no translation found for sharing_images_with_link (8907893266387877733) --> - <skip /> - <!-- no translation found for sharing_videos_with_text (4169898442482118146) --> - <skip /> - <!-- no translation found for sharing_videos_with_link (6383290441403042321) --> - <skip /> - <!-- no translation found for sharing_files_with_text (7331187260405018080) --> - <skip /> - <!-- no translation found for sharing_files_with_link (6052797122358827239) --> - <skip /> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_with_text" msgid="9005717434461730242">"{count,plural, =1{Partage d\'une image avec du texte}one{Partage de # image avec du texte}many{Partage de # d\'images avec du texte}other{Partage de # images avec du texte}}"</string> + <string name="sharing_images_with_link" msgid="8907893266387877733">"{count,plural, =1{Partage d\'une image avec un lien}one{Partage de # image avec un lien}many{Partage de # d\'images avec un lien}other{Partage de # images avec un lien}}"</string> + <string name="sharing_videos_with_text" msgid="4169898442482118146">"{count,plural, =1{Partage d\'une vidéo avec du texte}one{Partage de # vidéo avec du texte}many{Partage de # de vidéos avec du texte}other{Partage de # vidéos avec du texte}}"</string> + <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Partage d\'une vidéo avec un lien}one{Partage de # vidéo avec un lien}many{Partage de # de vidéos avec un lien}other{Partage de # vidéos avec un lien}}"</string> + <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Partage d\'un fichier avec du texte}one{Partage de # fichier avec du texte}many{Partage de # de fichiers avec du texte}other{Partage de # fichiers avec du texte}}"</string> + <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Partage d\'un fichier avec un lien}one{Partage de # fichier avec un lien}many{Partage de # de fichiers avec un lien}other{Partage de # fichiers avec un lien}}"</string> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Image uniquement}one{Image uniquement}many{Images uniquement}other{Images uniquement}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Vidéo uniquement}one{Vidéo uniquement}many{Vidéos uniquement}other{Vidéos uniquement}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Fichier uniquement}one{Fichier uniquement}many{Fichiers uniquement}other{Fichiers uniquement}}"</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> diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index 5f36eccd..25a11356 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Partager 1 vidéo avec un lien}one{Partager # vidéo avec un lien}many{Partager # vidéos avec un lien}other{Partager # vidéos avec un lien}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Partager 1 fichier avec du texte}one{Partager # fichier avec du texte}many{Partager # fichiers avec du texte}other{Partager # fichiers avec du texte}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Partager 1 fichier avec un lien}one{Partager # fichier avec un lien}many{Partager # fichiers avec un lien}other{Partager # fichiers avec un lien}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Image uniquement}one{Image uniquement}many{Images uniquement}other{Images uniquement}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Vidéo uniquement}one{Vidéo uniquement}many{Vidéos uniquement}other{Vidéos uniquement}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Fichier uniquement}one{Fichier uniquement}many{Fichiers uniquement}other{Fichiers uniquement}}"</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> diff --git a/java/res/values-gl/strings.xml b/java/res/values-gl/strings.xml index 632fed98..37515886 100644 --- a/java/res/values-gl/strings.xml +++ b/java/res/values-gl/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Compartindo vídeo con ligazón}other{Compartindo # vídeos con ligazón}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Compartindo ficheiro con texto}other{Compartindo # ficheiros con texto}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Compartindo ficheiro con ligazón}other{Compartindo # ficheiros con ligazón}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Só a imaxe}other{Só as imaxes}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Só o vídeo}other{Só os vídeos}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Só o ficheiro}other{Só os ficheiros}}"</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> diff --git a/java/res/values-h480dp/dimens.xml b/java/res/values-h480dp/dimens.xml index 369a32b8..a9419eda 100644 --- a/java/res/values-h480dp/dimens.xml +++ b/java/res/values-h480dp/dimens.xml @@ -23,7 +23,7 @@ <dimen name="chooser_preview_width">-1px</dimen> <dimen name="chooser_view_spacing">18dp</dimen> - <dimen name="chooser_action_max_width">80dp</dimen> + <dimen name="chooser_action_max_width">100dp</dimen> <dimen name="chooser_preview_image_height_tall">192dp</dimen> <dimen name="grid_padding_top">10dp</dimen> <dimen name="width_text_image_preview_size">56dp</dimen> diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml index b90f8edc..0e569647 100644 --- a/java/res/values-hu/strings.xml +++ b/java/res/values-hu/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Videó megosztása linkkel}other{# videó megosztása linkkel}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Fájl megosztása szöveggel}other{# fájl megosztása szöveggel}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Fájl megosztása linkkel}other{# fájl megosztása linkkel}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Csak kép}other{Csak képek}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Csak videó}other{Csak videók}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Csak fájl}other{Csak fájlok}}"</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> diff --git a/java/res/values-hy/strings.xml b/java/res/values-hy/strings.xml index 87f46bf1..c5740f46 100644 --- a/java/res/values-hy/strings.xml +++ b/java/res/values-hy/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Տեսանյութի ուղարկում հղման միջոցով}one{# տեսանյութի ուղարկում հղման միջոցով}other{# տեսանյութի ուղարկում հղման միջոցով}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Ֆայլի ուղարկում տեքստային հաղորդագրության միջոցով}one{# ֆայլի ուղարկում տեքստային հաղորդագրության միջոցով}other{# ֆայլի ուղարկում տեքստային հաղորդագրության միջոցով}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Ֆայլի ուղարկում հղման միջոցով}one{# ֆայլի ուղարկում հղման միջոցով}other{# ֆայլի ուղարկում հղման միջոցով}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Միայն պատկերը}one{Միայն պատկերը}other{Միայն պատկերները}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Միայն տեսանյութը}one{Միայն տեսանյութը}other{Միայն տեսանյութերը}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Միայն ֆայլը}one{Միայն ֆայլը}other{Միայն ֆայլերը}}"</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> diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml index 93e1598e..2c39b135 100644 --- a/java/res/values-in/strings.xml +++ b/java/res/values-in/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Membagikan video dengan link}other{Membagikan # video dengan link}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Membagikan file dengan teks}other{Membagikan # file dengan teks}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Membagikan file dengan link}other{Membagikan # file dengan link}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Khusus gambar}other{Khusus gambar}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Khusus video}other{Khusus video}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Khusus file}other{Khusus file}}"</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> diff --git a/java/res/values-is/strings.xml b/java/res/values-is/strings.xml index 89a4dcb3..b252960e 100644 --- a/java/res/values-is/strings.xml +++ b/java/res/values-is/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Deilir myndskeiði með tengli}one{Deilir # myndskeiði með tengli}other{Deilir # myndskeiðum með tengli}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Deilir skrá með texta}one{Deilir # skrá með texta}other{Deilir # skrám með texta}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Deilir skrá með tengli}one{Deilir # skrá með tengli}other{Deilir # skrám með tengli}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Eingöngu mynd}one{Eingöngu myndir}other{Eingöngu myndir}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Eingöngu myndskeið}one{Eingöngu myndskeið}other{Eingöngu myndskeið}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Eingöngu skrá}one{Eingöngu skrár}other{Eingöngu skrár}}"</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> diff --git a/java/res/values-kk/strings.xml b/java/res/values-kk/strings.xml index aac3eff4..10af8e73 100644 --- a/java/res/values-kk/strings.xml +++ b/java/res/values-kk/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Сілтемесі бар бейне жіберу}other{Сілтемесі бар # бейне жіберу}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Мәтіні бар файл жіберу}other{Мәтіні бар # файл жіберу}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Сілтемесі бар файл жіберу}other{Сілтемесі бар # файл жіберу}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Тек сурет}other{Тек суреттер}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Тек бейне}other{Тек бейнелер}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Тек файл}other{Тек файлдар}}"</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> diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml index 6d04e842..c02fcda9 100644 --- a/java/res/values-ko/strings.xml +++ b/java/res/values-ko/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{링크로 동영상 공유 중}other{링크로 동영상 #개 공유 중}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{텍스트로 파일 공유 중}other{텍스트로 파일 #개 공유 중}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{링크로 파일 공유 중}other{링크로 파일 #개 공유 중}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{이미지만}other{이미지만}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{동영상만}other{동영상만}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{파일만}other{파일만}}"</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> diff --git a/java/res/values-ky/strings.xml b/java/res/values-ky/strings.xml index a50913f6..5ed8a4cf 100644 --- a/java/res/values-ky/strings.xml +++ b/java/res/values-ky/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Видеону шилтеме менен жөнөтүү}other{# видеону шилтеме менен жөнөтүү}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Файлды текст менен жөнөтүү}other{# файлды текст менен жөнөтүү}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Файлды шилтеме менен жөнөтүү}other{# файлды шилтеме менен жөнөтүү}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Сүрөт гана}other{Сүрөттөр гана}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Видео гана}other{Видеолор гана}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Файл гана}other{Файлдар гана}}"</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> diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml index b191eca3..4879cc0e 100644 --- a/java/res/values-lt/strings.xml +++ b/java/res/values-lt/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Bendrinamas vaizdo įrašas su nuoroda}one{Bendrinamas # vaizdo įrašas su nuoroda}few{Bendrinami # vaizdo įrašai su nuoroda}many{Bendrinamas # vaizdo įrašo su nuoroda}other{Bendrinama # vaizdo įrašų su nuoroda}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Bendrinamas failas su tekstu}one{Bendrinamas # failas su tekstu}few{Bendrinami # failai su tekstu}many{Bendrinama # failo su tekstu}other{Bendrinama # failų su tekstu}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Bendrinamas failas su nuoroda}one{Bendrinamas # failas su nuoroda}few{Bendrinami # failai su nuoroda}many{Bendrinama # failo su nuoroda}other{Bendrinama # failų su nuoroda}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Tik vaizdas}one{Tik vaizdai}few{Tik vaizdai}many{Tik vaizdai}other{Tik vaizdai}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Tik vaizdo įrašas}one{Tik vaizdo įrašai}few{Tik vaizdo įrašai}many{Tik vaizdo įrašai}other{Tik vaizdo įrašai}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Tik failas}one{Tik failai}few{Tik failai}many{Tik failai}other{Tik failai}}"</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> diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml index 3f114adb..ec0b3600 100644 --- a/java/res/values-lv/strings.xml +++ b/java/res/values-lv/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Tiek kopīgots videoklips ar saiti}zero{Tiek kopīgoti # videoklipi ar saitēm}one{Tiek kopīgots # videoklips ar saitēm}other{Tiek kopīgoti # videoklipi ar saitēm}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Tiek kopīgots fails ar tekstu}zero{Tiek kopīgoti # faili ar tekstu}one{Tiek kopīgots # fails ar tekstu}other{Tiek kopīgoti # faili ar tekstu}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Tiek kopīgots fails ar saiti}zero{Tiek kopīgoti # faili ar saitēm}one{Tiek kopīgots # fails ar saitēm}other{Tiek kopīgoti # faili ar saitēm}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Tikai attēls}zero{Tikai attēli}one{Tikai attēli}other{Tikai attēli}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Tikai videoklips}zero{Tikai videoklipi}one{Tikai videoklipi}other{Tikai videoklipi}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Tikai fails}zero{Tikai faili}one{Tikai faili}other{Tikai faili}}"</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> diff --git a/java/res/values-mk/strings.xml b/java/res/values-mk/strings.xml index be091d97..d90b165c 100644 --- a/java/res/values-mk/strings.xml +++ b/java/res/values-mk/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Се споделува видео со линк}one{Се споделуваат # видео со линк}other{Се споделуваat # видеa со линк}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Се споделува датотека со SMS}one{Се споделуваат # датотека со SMS}other{Се споделуваат # датотеки со SMS}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Се споделува датотека со линк}one{Се споделуваат # датотека со линк}other{Се споделуваат # датотеки со линк}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Само слика}one{Само слики}other{Само слики}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Само видео}one{Само видеа}other{Само видеа}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Само датотека}one{Само датотеки}other{Само датотеки}}"</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> diff --git a/java/res/values-mn/strings.xml b/java/res/values-mn/strings.xml index 5b7bea06..4b1c89b1 100644 --- a/java/res/values-mn/strings.xml +++ b/java/res/values-mn/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Холбоостой видео хуваалцаж байна}other{Холбоостой # видео хуваалцаж байна}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Тексттэй файл хуваалцаж байна}other{Тексттэй # файл хуваалцаж байна}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Холбоостой файл хуваалцаж байна}other{Холбоостой # файл хуваалцаж байна}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Зөвхөн зураг}other{Зөвхөн зургууд}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Зөвхөн видео}other{Зөвхөн видеонууд}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Зөвхөн файл}other{Зөвхөн файлууд}}"</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> diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml index 74ec2197..8e6ba164 100644 --- a/java/res/values-nb/strings.xml +++ b/java/res/values-nb/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Deler videoen med link}other{Deler # videoer med link}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Deler filen med tekst}other{Deler # filer med tekst}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Deler filen med link}other{Deler # filer med link}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Bare bildet}other{Bare bildene}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Bare videoen}other{Bare videoene}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Bare filen}other{Bare filene}}"</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> diff --git a/java/res/values-ne/strings.xml b/java/res/values-ne/strings.xml index 41482cfa..6d8d15cb 100644 --- a/java/res/values-ne/strings.xml +++ b/java/res/values-ne/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{लिंक भएको भिडियो सेयर गरिँदै छ}other{लिंक भएका # वटा भिडियो सेयर गरिँदै छन्}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{टेक्स्ट भएको फाइल सेयर गरिँदै छ}other{टेक्स्ट भएका # वटा फाइल सेयर गरिँदै छन्}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{लिंक भएको फाइल सेयर गरिँदै छ}other{लिंक भएका # वटा फाइल सेयर गरिँदै छन्}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{फोटो मात्र}other{फोटोहरू मात्र}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{भिडियो मात्र}other{भिडियोहरू मात्र}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{फाइल मात्र}other{फाइलहरू मात्र}}"</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> diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index a5f4e56a..7d210d3b 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Video delen via link}other{# video\'s delen via link}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Bestand delen via tekstbericht}other{# bestanden delen via tekstbericht}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Bestand delen via link}other{# bestanden delen via link}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Alleen afbeelding}other{Alleen afbeeldingen}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Alleen video}other{Alleen video\'s}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Alleen bestand}other{Alleen bestanden}}"</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> diff --git a/java/res/values-or/strings.xml b/java/res/values-or/strings.xml index db910605..85f21d28 100644 --- a/java/res/values-or/strings.xml +++ b/java/res/values-or/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{ଲିଙ୍କ ସହ ଭିଡିଓ ସେୟାର କରାଯାଉଛି}other{ଲିଙ୍କ ସହ #ଟି ଭିଡିଓ ସେୟାର କରାଯାଉଛି}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{ଟେକ୍ସଟ ସହ ଫାଇଲ ସେୟାର କରାଯାଉଛି}other{ଟେକ୍ସଟ ସହ #ଟି ଫାଇଲ ସେୟାର କରାଯାଉଛି}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{ଲିଙ୍କ ସହ ଫାଇଲ ସେୟାର କରାଯାଉଛି}other{ଲିଙ୍କ ସହ #ଟି ଫାଇଲ ସେୟାର କରାଯାଉଛି}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{କେବଳ ଇମେଜ}other{କେବଳ ଇମେଜଗୁଡ଼ିକ}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{କେବଳ ଭିଡିଓ}other{କେବଳ ଭିଡିଓଗୁଡ଼ିକ}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{କେବଳ ଫାଇଲ}other{କେବଳ ଫାଇଲଗୁଡ଼ିକ}}"</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> diff --git a/java/res/values-pa/strings.xml b/java/res/values-pa/strings.xml index 91cf2bf2..d2a7f3ea 100644 --- a/java/res/values-pa/strings.xml +++ b/java/res/values-pa/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{ਲਿੰਕ ਨਾਲ ਵੀਡੀਓ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}one{ਲਿੰਕ ਨਾਲ # ਵੀਡੀਓ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}other{ਲਿੰਕ ਨਾਲ # ਵੀਡੀਓ ਸਾਂਝੇ ਕੀਤੇ ਜਾ ਰਹੇ ਹਨ}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{ਲਿਖਤ ਸੁਨੇਹੇ ਨਾਲ ਫ਼ਾਈਲ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}one{ਲਿਖਤ ਸੁਨੇਹੇ ਨਾਲ # ਫ਼ਾਈਲ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}other{ਲਿਖਤ ਸੁਨੇਹੇ ਨਾਲ # ਫ਼ਾਈਲਾਂ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{ਲਿੰਕ ਨਾਲ ਫ਼ਾਈਲ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}one{ਲਿੰਕ ਨਾਲ # ਫ਼ਾਈਲ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}other{ਲਿੰਕ ਨਾਲ # ਫ਼ਾਈਲਾਂ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{ਸਿਰਫ਼ ਚਿੱਤਰ}one{ਸਿਰਫ਼ ਚਿੱਤਰ}other{ਸਿਰਫ਼ ਚਿੱਤਰ}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{ਸਿਰਫ਼ ਵੀਡੀਓ}one{ਸਿਰਫ਼ ਵੀਡੀਓ}other{ਸਿਰਫ਼ ਵੀਡੀਓ}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{ਸਿਰਫ਼ ਫ਼ਾਈਲ}one{ਸਿਰਫ਼ ਫ਼ਾਈਲ}other{ਸਿਰਫ਼ ਫ਼ਾਈਲਾਂ}}"</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> diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml index 9497bce2..594ab2a4 100644 --- a/java/res/values-pl/strings.xml +++ b/java/res/values-pl/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Udostępnianie filmu przez link}few{Udostępnianie # filmów przez link}many{Udostępnianie # filmów przez link}other{Udostępnianie # filmu przez link}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Udostępnianie pliku przez SMS}few{Udostępnianie # plików przez SMS}many{Udostępnianie # plików przez SMS}other{Udostępnianie # pliku przez SMS}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Udostępnianie pliku przez link}few{Udostępnianie # plików przez link}many{Udostępnianie # plików przez link}other{Udostępnianie # pliku przez link}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Tylko obraz}few{Tylko obrazy}many{Tylko obrazy}other{Tylko obrazy}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Tylko film}few{Tylko filmy}many{Tylko filmy}other{Tylko filmy}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Tylko plik}few{Tylko pliki}many{Tylko pliki}other{Tylko pliki}}"</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> diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml index 925a70a9..df31c09d 100644 --- a/java/res/values-ro/strings.xml +++ b/java/res/values-ro/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Se trimite videoclipul cu linkul}few{Se trimit # videoclipuri cu linkul}other{Se trimit # de videoclipuri cu linkul}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Se trimite fișierul cu text}few{Se trimit # fișiere cu text}other{Se trimit # de fișiere cu text}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Se trimite fișierul cu linkul}few{Se trimit # fișiere cu linkul}other{Se trimit # de fișiere cu linkul}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Numai imaginea}few{Numai imaginile}other{Numai imaginile}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Numai videoclipul}few{Numai videoclipurile}other{Numai videoclipurile}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Numai fișierul}few{Numai fișierele}other{Numai fișierele}}"</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> diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml index f7657c02..21142597 100644 --- a/java/res/values-ru/strings.xml +++ b/java/res/values-ru/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Отправка видео со ссылкой}one{Отправка # видео со ссылкой}few{Отправка # видео со ссылкой}many{Отправка # видео со ссылкой}other{Отправка # видео со ссылкой}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Отправка файла с текстом}one{Отправка # файла с текстом}few{Отправка # файлов с текстом}many{Отправка # файлов с текстом}other{Отправка # файла с текстом}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Отправка файла со ссылкой}one{Отправка # файла со ссылкой}few{Отправка # файлов со ссылкой}many{Отправка # файлов со ссылкой}other{Отправка # файла со ссылкой}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Только изображение}one{Только изображения}few{Только изображения}many{Только изображения}other{Только изображения}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Только видео}one{Только видео}few{Только видео}many{Только видео}other{Только видео}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Только файл}one{Только файлы}few{Только файлы}many{Только файлы}other{Только файлы}}"</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> diff --git a/java/res/values-si/strings.xml b/java/res/values-si/strings.xml index 4ed45567..a1362aad 100644 --- a/java/res/values-si/strings.xml +++ b/java/res/values-si/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{සබැඳිය සමග වීඩියෝව බෙදා ගැනීම}one{සබැඳිය සමග වීඩියෝ #ක් බෙදා ගැනීම}other{සබැඳිය සමග වීඩියෝ #ක් බෙදා ගැනීම}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{පෙළ සමග ගොනුව බෙදා ගැනීම}one{පෙළ සමග ගොනු #ක් බෙදා ගැනීම}other{පෙළ සමග ගොනු #ක් බෙදා ගැනීම}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{සබැඳිය සමග ගොනුව බෙදා ගැනීම}one{සබැඳිය සමග ගොනු #ක් බෙදා ගැනීම}other{සබැඳිය සමග ගොනු #ක් බෙදා ගැනීම}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{රූපය පමණි}one{රූප පමණි}other{රූප පමණි}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{වීඩියෝව පමණි}one{වීඩියෝ පමණි}other{වීඩියෝ පමණි}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{ගොනුව පමණි}one{ගොනු පමණි}other{ගොනු පමණි}}"</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> diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml index 8166e10a..f61d450a 100644 --- a/java/res/values-sk/strings.xml +++ b/java/res/values-sk/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Zdieľa sa video s odkazom}few{Zdieľajú sa # videá s odkazom}many{Sharing # videos with link}other{Zdieľa sa # videí s odkazom}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Zdieľa sa súbor s textom}few{Zdieľajú sa # súbory s textom}many{Sharing # files with text}other{Zdieľa sa # súborov s textom}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Zdieľa sa súbor s odkazom}few{Zdieľajú sa # súbory s odkazom}many{Sharing # files with link}other{Zdieľa sa # súborov s odkazom}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Iba obrázok}few{Iba obrázky}many{Iba obrázky}other{Iba obrázky}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Iba video}few{Iba videá}many{Iba videá}other{Iba videá}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Iba súbor}few{Iba súbory}many{Iba súbory}other{Iba súbory}}"</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> diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml index b24effe6..0d8fc8b9 100644 --- a/java/res/values-sl/strings.xml +++ b/java/res/values-sl/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Deljenje videoposnetka s povezavo}one{Deljenje # videoposnetka s povezavo}two{Deljenje # videoposnetkov s povezavo}few{Deljenje # videoposnetkov s povezavo}other{Deljenje # videoposnetkov s povezavo}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Deljenje datoteke z besedilom}one{Deljenje # datoteke z besedilom}two{Deljenje # datotek z besedilom}few{Deljenje # datotek z besedilom}other{Deljenje # datotek z besedilom}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Deljenje datoteke s povezavo}one{Deljenje # datoteke s povezavo}two{Deljenje # datotek s povezavo}few{Deljenje # datotek s povezavo}other{Deljenje # datotek s povezavo}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Samo slika}one{Samo slike}two{Samo slike}few{Samo slike}other{Samo slike}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Samo videoposnetek}one{Samo videoposnetki}two{Samo videoposnetki}few{Samo videoposnetki}other{Samo videoposnetki}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Samo datoteka}one{Samo datoteke}two{Samo datoteke}few{Samo datoteke}other{Samo datoteke}}"</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> diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml index 95f20c05..feaf9f29 100644 --- a/java/res/values-sr/strings.xml +++ b/java/res/values-sr/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Дели се видео са линком}one{Дели се # видео са линком}few{Деле се # видео снимка са линком}other{Дели се # видео снимака са линком}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Дели се фајл са текстом}one{Дели се # фајл са текстом}few{Деле се # фајла са текстом}other{Дели се # фајлова са текстом}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Дели се фајл са линком}one{Дели се # фајл са линком}few{Деле се # фајла са линком}other{Дели се # фајлова са линком}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Само слика}one{Само слике}few{Само слике}other{Само слике}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Само видео}one{Само видео снимци}few{Само видео снимци}other{Само видео снимци}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Само фајл}one{Само фајлови}few{Само фајлови}other{Само фајлови}}"</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> @@ -85,7 +82,7 @@ <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="7115260573975624516">"Пословне апликације су паузиране"</string> - <string name="resolver_switch_on_work" msgid="8678893259344318807">"Опозови паузу"</string> + <string name="resolver_switch_on_work" msgid="8678893259344318807">"Поново активирај"</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> diff --git a/java/res/values-ta/strings.xml b/java/res/values-ta/strings.xml index 63770bae..5744b508 100644 --- a/java/res/values-ta/strings.xml +++ b/java/res/values-ta/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{இணைப்புடன் வீடியோவைப் பகிர்கிறது}other{இணைப்புடன் # வீடியோக்களைப் பகிர்கிறது}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{வார்த்தைகளைக் கொண்ட ஃபைலைப் பகிர்கிறது}other{வார்த்தைகளைக் கொண்ட # ஃபைல்களைப் பகிர்கிறது}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{இணைப்பைக் கொண்ட ஃபைலைப் பகிர்கிறது}other{இணைப்பைக் கொண்ட # ஃபைல்களைப் பகிர்கிறது}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{படம் மட்டும்}other{படங்கள் மட்டும்}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{வீடியோ மட்டும்}other{வீடியோக்கள் மட்டும்}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{ஃபைல் மட்டும்}other{ஃபைல்கள் மட்டும்}}"</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> diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml index e605487b..723c7cf9 100644 --- a/java/res/values-th/strings.xml +++ b/java/res/values-th/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{กำลังแชร์วิดีโอพร้อมลิงก์}other{กำลังแชร์วิดีโอ # รายการพร้อมลิงก์}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{กำลังแชร์ไฟล์พร้อมข้อความ}other{กำลังแชร์ไฟล์ # รายการพร้อมข้อความ}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{กำลังแชร์ไฟล์พร้อมลิงก์}other{กำลังแชร์ไฟล์ # รายการพร้อมลิงก์}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{รูปภาพเท่านั้น}other{รูปภาพเท่านั้น}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{วิดีโอเท่านั้น}other{วิดีโอเท่านั้น}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{ไฟล์เท่านั้น}other{ไฟล์เท่านั้น}}"</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> diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index d021a86b..e81943f4 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Bağlantı ekli video paylaşılıyor}other{Bağlantı ekli # video paylaşılıyor}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Metin ekli dosya paylaşılıyor}other{Metin ekli # dosya paylaşılıyor}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Bağlantı ekli dosya paylaşılıyor}other{Bağlantı ekli # dosya paylaşılıyor}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Yalnızca resim}other{Yalnızca resimler}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Yalnızca video}other{Yalnızca videolar}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Yalnızca dosya}other{Yalnızca dosyalar}}"</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> diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml index e03764af..344e8064 100644 --- a/java/res/values-uk/strings.xml +++ b/java/res/values-uk/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Надсилання відео з посиланням}one{Надсилання # відео з посиланням}few{Надсилання # відео з посиланням}many{Надсилання # відео з посиланням}other{Надсилання # відео з посиланням}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Надсилання файлу з текстом}one{Надсилання # файлу з текстом}few{Надсилання # файлів із текстом}many{Надсилання # файлів із текстом}other{Надсилання # файлу з текстом}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Надсилання файлу з посиланням}one{Надсилання # файлу з посиланням}few{Надсилання # файлів із посиланням}many{Надсилання # файлів із посиланням}other{Надсилання # файлу з посиланням}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Лише зображення}one{Лише зображення}few{Лише зображення}many{Лише зображення}other{Лише зображення}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Лише відео}one{Лише відео}few{Лише відео}many{Лише відео}other{Лише відео}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Лише файл}one{Лише файли}few{Лише файли}many{Лише файли}other{Лише файли}}"</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> diff --git a/java/res/values-ur/strings.xml b/java/res/values-ur/strings.xml index 5c9b3c04..0079e078 100644 --- a/java/res/values-ur/strings.xml +++ b/java/res/values-ur/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{لنک کے ساتھ ویڈیو کا اشتراک کیا جا رہا ہے}other{لنک کے ساتھ # ویڈیوز کا اشتراک کیا جا رہا ہے}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{ٹیکسٹ کے ساتھ فائل کا اشتراک کیا جا رہا ہے}other{ٹیکسٹ کے ساتھ # فائلز کا اشتراک کیا جا رہا ہے}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{لنک کے ساتھ فائل کا اشتراک کیا جا رہا ہے}other{لنک کے ساتھ # فائلز کا اشتراک کیا جا رہا ہے}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{صرف تصویر}other{صرف تصاویر}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{صرف ویڈیو}other{صرف ویڈیوز}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{صرف فائل}other{صرف فائلز}}"</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> diff --git a/java/res/values-uz/strings.xml b/java/res/values-uz/strings.xml index 1cdecbe3..022f531a 100644 --- a/java/res/values-uz/strings.xml +++ b/java/res/values-uz/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Havolali videoni yuborish}other{# ta havolali videoni yuborish}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Matnli faylni yuborish}other{# ta matnli faylni yuborish}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Havolali faylni yuborish}other{# ta havolali faylni yuborish}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Faqat rasm}other{Faqat rasmlar}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Faqat video}other{Faqat videolar}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Faqat fayl}other{Faqat fayllar}}"</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> diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml index 271f1c7f..e90c7c02 100644 --- a/java/res/values-vi/strings.xml +++ b/java/res/values-vi/strings.xml @@ -66,12 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{Đang chia sẻ video có đường liên kết}other{Đang chia sẻ # video có đường liên kết}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{Đang chia sẻ tệp có văn bản}other{Đang chia sẻ # tệp có văn bản}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{Đang chia sẻ tệp có đường liên kết}other{Đang chia sẻ # tệp có đường liên kết}}"</string> - <!-- no translation found for sharing_images_only (7762589767189955438) --> - <skip /> - <!-- no translation found for sharing_videos_only (5549729252364968606) --> - <skip /> - <!-- no translation found for sharing_files_only (6603666533766964768) --> - <skip /> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{Chỉ chia sẻ hình ảnh}other{Chỉ chia sẻ các hình ảnh}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{Chỉ chia sẻ video}other{Chỉ chia sẻ các video}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{Chỉ chia sẻ tệp}other{Chỉ chia sẻ các tệp}}"</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> diff --git a/java/res/values-zh-rHK/strings.xml b/java/res/values-zh-rHK/strings.xml index 8ee35f1b..3888e582 100644 --- a/java/res/values-zh-rHK/strings.xml +++ b/java/res/values-zh-rHK/strings.xml @@ -66,9 +66,9 @@ <string name="sharing_videos_with_link" msgid="6383290441403042321">"{count,plural, =1{正在分享影片 (含有連結)}other{正在分享 # 部影片 (含有連結)}}"</string> <string name="sharing_files_with_text" msgid="7331187260405018080">"{count,plural, =1{正在分享檔案 (含有文字)}other{正在分享 # 個檔案 (含有文字)}}"</string> <string name="sharing_files_with_link" msgid="6052797122358827239">"{count,plural, =1{正在分享檔案 (含有連結)}other{正在分享 # 個檔案 (含有連結)}}"</string> - <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{只有圖片}other{只有圖片}}"</string> - <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{只有影片}other{只有影片}}"</string> - <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{只有檔案}other{只有檔案}}"</string> + <string name="sharing_images_only" msgid="7762589767189955438">"{count,plural, =1{僅含圖片}other{僅含圖片}}"</string> + <string name="sharing_videos_only" msgid="5549729252364968606">"{count,plural, =1{僅含影片}other{僅含影片}}"</string> + <string name="sharing_files_only" msgid="6603666533766964768">"{count,plural, =1{僅含檔案}other{僅含檔案}}"</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> diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml index 6da0ec1c..46ff75ed 100644 --- a/java/res/values/dimens.xml +++ b/java/res/values/dimens.xml @@ -57,7 +57,7 @@ than 480dp, the values are set in values-h480dp/dimens.xml --> <dimen name="chooser_preview_width">412dp</dimen> <dimen name="chooser_view_spacing">8dp</dimen> - <dimen name="chooser_action_max_width">120dp</dimen> + <dimen name="chooser_action_max_width">140dp</dimen> <dimen name="chooser_preview_image_height_tall">64dp</dimen> <dimen name="grid_padding_top">6dp</dimen> <dimen name="width_text_image_preview_size">46dp</dimen> diff --git a/java/src/com/android/intentresolver/AnnotatedUserHandles.java b/java/src/com/android/intentresolver/AnnotatedUserHandles.java index 769195ed..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,28 +80,74 @@ 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); - } - - // TODO: integrate logic for `ResolverActivity.EXTRA_CALLING_USER`. - userHandleSharesheetLaunchedAs = UserHandle.of(UserHandle.myUserId()); + /** 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. - personalProfileUserHandle = UserHandle.of(ActivityManager.getCurrentUser()); + 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(); + } + + @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; + } + + 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 @@ -124,24 +172,46 @@ public final class AnnotatedUserHandles { .orElse(null); } - /** - * 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; + @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; } - return queryIntentsUser; - } - private Boolean isLaunchedAsCloneProfile() { - return userHandleSharesheetLaunchedAs.equals(cloneProfileUserHandle); + 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/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index 84e14d72..014aa2a2 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -83,10 +83,10 @@ 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.ImageLoader; -import com.android.intentresolver.contentpreview.PreviewDataProvider; +import com.android.intentresolver.contentpreview.PreviewViewModel; import com.android.intentresolver.flags.FeatureFlagRepository; import com.android.intentresolver.flags.FeatureFlagRepositoryFactory; import com.android.intentresolver.grid.ChooserGridAdapter; @@ -272,12 +272,14 @@ public class ChooserActivity extends ResolverActivity implements } }); + BasePreviewViewModel previewViewModel = + new ViewModelProvider(this, createPreviewViewModelFactory()) + .get(BasePreviewViewModel.class); mChooserContentPreviewUi = new ChooserContentPreviewUi( getLifecycle(), - createPreviewDataProvider(), + previewViewModel.createOrReuseProvider(mChooserRequest), mChooserRequest.getTargetIntent(), - this::isImageType, - createPreviewImageLoader(), + previewViewModel.createOrReuseImageLoader(), createChooserActionFactory(), mEnterTransitionAnimationDelegate, new HeadlineGeneratorImpl(this)); @@ -538,14 +540,6 @@ public class ChooserActivity extends ResolverActivity implements mMaxTargetsPerRow); } - private PreviewDataProvider createPreviewDataProvider() { - // TODO: move this into a ViewModel so it could survive orientation change - return new PreviewDataProvider( - mChooserRequest.getTargetIntent(), - getContentResolver(), - this::isImageType); - } - private int findSelectedProfile() { int selectedProfile = getSelectedProfileExtra(); if (selectedProfile == -1) { @@ -722,10 +716,6 @@ public class ChooserActivity extends ResolverActivity implements return resolver.query(uri, null, null, null, null); } - private boolean isImageType(@Nullable String mimeType) { - return mimeType != null && mimeType.startsWith("image/"); - } - private int getNumSheetExpansions() { return getPreferences(Context.MODE_PRIVATE).getInt(PREF_NUM_SHEET_EXPANSIONS, 0); } @@ -1325,14 +1315,8 @@ public class ChooserActivity extends ResolverActivity implements } @VisibleForTesting - protected ImageLoader createPreviewImageLoader() { - final int cacheSize; - float chooserWidth = getResources().getDimension(R.dimen.chooser_width); - // imageWidth = imagePreviewHeight * minAspectRatio (see ScrollableImagePreviewView) - float imageWidth = - getResources().getDimension(R.dimen.chooser_preview_image_height_tall) * 2 / 5; - cacheSize = (int) (Math.ceil(chooserWidth / imageWidth) + 2); - return new ImagePreviewImageLoader(this, getLifecycle(), cacheSize); + protected ViewModelProvider.Factory createPreviewViewModelFactory() { + return PreviewViewModel.Companion.getFactory(); } private ChooserActionFactory createChooserActionFactory() { @@ -1550,6 +1534,10 @@ 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); @@ -1591,7 +1579,10 @@ public class ChooserActivity extends ResolverActivity implements } if (mMultiProfilePagerAdapter.getActiveListAdapter() == adapter) { - Tracer.INSTANCE.endLaunchToShortcutTrace(); + long duration = Tracer.INSTANCE.endLaunchToShortcutTrace(); + if (duration >= 0) { + Log.d(TAG, "stat to first shortcut time: " + duration + " ms"); + } } logDirectShareTargetReceived(userHandle); sendVoiceChoicesIfNeeded(); diff --git a/java/src/com/android/intentresolver/ChooserListAdapter.java b/java/src/com/android/intentresolver/ChooserListAdapter.java index ebbf5515..c20af20c 100644 --- a/java/src/com/android/intentresolver/ChooserListAdapter.java +++ b/java/src/com/android/intentresolver/ChooserListAdapter.java @@ -676,6 +676,7 @@ public class ChooserListAdapter extends ResolverListAdapter { @Override protected Drawable doInBackground(Void... voids) { Drawable drawable; + Trace.beginSection("shortcut-icon"); try { drawable = getChooserTargetIconDrawable( mContext, @@ -688,6 +689,8 @@ public class ChooserListAdapter extends ResolverListAdapter { + mTargetInfo.getChooserTargetComponentName(), e); drawable = loadIconPlaceholder(); + } finally { + Trace.endSection(); } return drawable; } diff --git a/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java index 9c096fd2..da7dc998 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; @@ -130,6 +131,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/ResolverActivity.java b/java/src/com/android/intentresolver/ResolverActivity.java index aea6c2c9..ac3b9a61 100644 --- a/java/src/com/android/intentresolver/ResolverActivity.java +++ b/java/src/com/android/intentresolver/ResolverActivity.java @@ -125,9 +125,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 @@ -228,7 +229,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; }; @@ -1864,8 +1865,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; @@ -1892,23 +1895,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 diff --git a/java/src/com/android/intentresolver/ResolverListAdapter.java b/java/src/com/android/intentresolver/ResolverListAdapter.java index fb7641b3..a5fdd320 100644 --- a/java/src/com/android/intentresolver/ResolverListAdapter.java +++ b/java/src/com/android/intentresolver/ResolverListAdapter.java @@ -1034,12 +1034,15 @@ public class ResolverListAdapter extends BaseAdapter { @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(); } } 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 55131de2..9100b392 100644 --- a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java @@ -88,7 +88,6 @@ public final class ChooserContentPreviewUi { Lifecycle lifecycle, PreviewDataProvider previewData, Intent targetIntent, - MimeTypeClassifier imageClassifier, ImageLoader imageLoader, ActionFactory actionFactory, TransitionElementStatusCallback transitionElementStatusCallback, @@ -97,7 +96,7 @@ public final class ChooserContentPreviewUi { mContentPreviewUi = createContentPreview( previewData, targetIntent, - imageClassifier, + DefaultMimeTypeClassifier.INSTANCE, imageLoader, actionFactory, transitionElementStatusCallback, @@ -119,6 +118,7 @@ public final class ChooserContentPreviewUi { int previewType = previewData.getPreviewType(); if (previewType == CONTENT_PREVIEW_TEXT) { return createTextPreview( + mLifecycle, targetIntent, actionFactory, imageLoader, @@ -141,6 +141,7 @@ public final class ChooserContentPreviewUi { if (!TextUtils.isEmpty(text)) { FilesPlusTextContentPreviewUi previewUi = new FilesPlusTextContentPreviewUi( + mLifecycle, isSingleImageShare, previewData.getUriCount(), targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT), @@ -181,6 +182,7 @@ public final class ChooserContentPreviewUi { } private static TextContentPreviewUi createTextPreview( + Lifecycle lifecycle, Intent targetIntent, ChooserContentPreviewUi.ActionFactory actionFactory, ImageLoader imageLoader, @@ -196,6 +198,7 @@ public final class ChooserContentPreviewUi { } } return new TextContentPreviewUi( + lifecycle, sharingText, previewTitle, previewThumbnail, diff --git a/java/src/com/android/intentresolver/contentpreview/DefaultMimeTypeClassifier.kt b/java/src/com/android/intentresolver/contentpreview/DefaultMimeTypeClassifier.kt new file mode 100644 index 00000000..b9215709 --- /dev/null +++ b/java/src/com/android/intentresolver/contentpreview/DefaultMimeTypeClassifier.kt @@ -0,0 +1,19 @@ +/* + * 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 + +object DefaultMimeTypeClassifier : MimeTypeClassifier diff --git a/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java index 860423c4..e4e33839 100644 --- a/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java @@ -31,6 +31,7 @@ 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; @@ -48,6 +49,7 @@ import java.util.function.Consumer; * file content). */ class FilesPlusTextContentPreviewUi extends ContentPreviewUi { + private final Lifecycle mLifecycle; private final CharSequence mText; private final ChooserContentPreviewUi.ActionFactory mActionFactory; private final ImageLoader mImageLoader; @@ -63,6 +65,7 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi { private boolean mAllVideos; FilesPlusTextContentPreviewUi( + Lifecycle lifecycle, boolean isSingleImage, int fileCount, CharSequence text, @@ -70,6 +73,7 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi { ImageLoader imageLoader, MimeTypeClassifier typeClassifier, HeadlineGenerator headlineGenerator) { + mLifecycle = lifecycle; if (isSingleImage && fileCount != 1) { throw new IllegalArgumentException( "fileCount = " + fileCount + " and isSingleImage = true"); @@ -155,13 +159,16 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi { ImageView imagePreview = mContentPreviewView.requireViewById(R.id.image_view); if (mIsSingleImage && mFirstFilePreviewUri != null) { - mImageLoader.loadImage(mFirstFilePreviewUri, bitmap -> { - if (bitmap == null) { - imagePreview.setVisibility(View.GONE); - } else { - imagePreview.setImageBitmap(bitmap); - } - }); + mImageLoader.loadImage( + mLifecycle, + mFirstFilePreviewUri, + bitmap -> { + if (bitmap == null) { + imagePreview.setVisibility(View.GONE); + } else { + imagePreview.setImageBitmap(bitmap); + } + }); } else { imagePreview.setVisibility(View.GONE); } diff --git a/java/src/com/android/intentresolver/contentpreview/ImageLoader.kt b/java/src/com/android/intentresolver/contentpreview/ImageLoader.kt index 225807ee..8d0fb84b 100644 --- a/java/src/com/android/intentresolver/contentpreview/ImageLoader.kt +++ b/java/src/com/android/intentresolver/contentpreview/ImageLoader.kt @@ -18,32 +18,29 @@ 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. - */ +/** 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. + * failed. */ - fun loadImage(uri: Uri, callback: Consumer<Bitmap?>) + fun loadImage(callerLifecycle: Lifecycle, uri: Uri, callback: Consumer<Bitmap?>) - /** - * Prepopulate the image loader cache. - */ + /** Prepopulate the image loader cache. */ fun prePopulate(uris: List<Uri>) - /** - * Load preview image; caching is allowed. - */ + /** 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. */ diff --git a/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt b/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt index c97efdd1..89b79a0a 100644 --- a/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt +++ b/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.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,9 +14,9 @@ * limitations under the License. */ -package com.android.intentresolver +package com.android.intentresolver.contentpreview -import android.content.Context +import android.content.ContentResolver import android.graphics.Bitmap import android.net.Uri import android.util.Log @@ -26,12 +26,10 @@ import androidx.annotation.VisibleForTesting import androidx.collection.LruCache import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope -import com.android.intentresolver.contentpreview.ImageLoader import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CompletableDeferred -import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import java.util.function.Consumer @@ -42,29 +40,24 @@ private const val TAG = "ImagePreviewImageLoader" * Implements preview image loading for the content preview UI. Provides requests deduplication and * image caching. */ -@VisibleForTesting -class ImagePreviewImageLoader @JvmOverloads constructor( - private val context: Context, - private val lifecycle: Lifecycle, +@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) +class ImagePreviewImageLoader( + private val scope: CoroutineScope, + thumbnailSize: Int, + private val contentResolver: ContentResolver, 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) - } + 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>() + @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(uri: Uri, callback: Consumer<Bitmap?>) { - lifecycle.coroutineScope.launch { + override fun loadImage(callerLifecycle: Lifecycle, uri: Uri, callback: Consumer<Bitmap?>) { + callerLifecycle.coroutineScope.launch { val image = loadImageAsync(uri, caching = true) if (isActive) { callback.accept(image) @@ -74,28 +67,26 @@ class ImagePreviewImageLoader @JvmOverloads constructor( override fun prePopulate(uris: List<Uri>) { uris.asSequence().take(cache.maxSize()).forEach { uri -> - lifecycle.coroutineScope.launch { - loadImageAsync(uri, caching = true) - } + scope.launch { loadImageAsync(uri, caching = true) } } } private suspend fun loadImageAsync(uri: Uri, caching: Boolean): Bitmap? { - return getRequestDeferred(uri, caching) - .await() + 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 - } - } + 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() } @@ -103,22 +94,23 @@ class ImagePreviewImageLoader @JvmOverloads constructor( } private fun RequestRecord.loadBitmapAsync() { - lifecycle.coroutineScope.launch(dispatcher) { - loadBitmap() - }.invokeOnCompletion { cause -> - if (cause is CancellationException) { - cancel() + scope + .launch { loadBitmap() } + .invokeOnCompletion { cause -> + if (cause is CancellationException) { + cancel() + } } - } } private fun RequestRecord.loadBitmap() { - val bitmap = try { - context.contentResolver.loadThumbnail(uri, thumbnailSize, null) - } catch (t: Throwable) { - Log.d(TAG, "failed to load $uri preview", t) - null - } + val bitmap = + try { + contentResolver.loadThumbnail(uri, thumbnailSize, null) + } catch (t: Throwable) { + Log.d(TAG, "failed to load $uri preview", t) + null + } complete(bitmap) } @@ -144,4 +136,4 @@ class ImagePreviewImageLoader @JvmOverloads constructor( val deferred: CompletableDeferred<Bitmap?>, @GuardedBy("lock") var caching: Boolean ) -} +}
\ No newline at end of file diff --git a/java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java b/java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java index 2de60c5b..c86b0fe2 100644 --- a/java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java +++ b/java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java @@ -22,14 +22,12 @@ import androidx.annotation.Nullable; /** * 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 MimeTypeClassifier { /** @return whether the specified {@code mimeType} is classified as an "image" type. */ - boolean isImageType(@Nullable String mimeType); + 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) { diff --git a/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt b/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt index 94db7a63..ae705369 100644 --- a/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt +++ b/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt @@ -78,11 +78,10 @@ constructor( constructor( targetIntent: Intent, contentResolver: ContentInterface, - typeClassifier: MimeTypeClassifier, ) : this( targetIntent, contentResolver, - typeClassifier, + DefaultMimeTypeClassifier, Dispatchers.IO, ) 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 3c8a6e48..19fd3bb4 100644 --- a/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java @@ -28,6 +28,7 @@ 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; @@ -36,6 +37,7 @@ import java.util.ArrayList; import java.util.List; class TextContentPreviewUi extends ContentPreviewUi { + private final Lifecycle mLifecycle; @Nullable private final CharSequence mSharingText; @Nullable @@ -47,12 +49,14 @@ class TextContentPreviewUi extends ContentPreviewUi { private final HeadlineGenerator mHeadlineGenerator; TextContentPreviewUi( + Lifecycle lifecycle, @Nullable CharSequence sharingText, @Nullable CharSequence previewTitle, @Nullable Uri previewThumbnail, ChooserContentPreviewUi.ActionFactory actionFactory, ImageLoader imageLoader, HeadlineGenerator headlineGenerator) { + mLifecycle = lifecycle; mSharingText = sharingText; mPreviewTitle = previewTitle; mPreviewThumbnail = previewThumbnail; @@ -117,6 +121,7 @@ class TextContentPreviewUi extends ContentPreviewUi { previewThumbnailView.setVisibility(View.GONE); } else { mImageLoader.loadImage( + mLifecycle, mPreviewThumbnail, (bitmap) -> updateViewWithImage( contentPreviewLayout.findViewById( diff --git a/java/src/com/android/intentresolver/measurements/Tracer.kt b/java/src/com/android/intentresolver/measurements/Tracer.kt index f7e01879..5f69932a 100644 --- a/java/src/com/android/intentresolver/measurements/Tracer.kt +++ b/java/src/com/android/intentresolver/measurements/Tracer.kt @@ -18,14 +18,20 @@ package com.android.intentresolver.measurements import android.os.SystemClock import android.os.Trace -import android.util.Log +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 TAG = "Tracer" 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())) { @@ -33,18 +39,112 @@ object Tracer { } } - fun endLaunchToShortcutTrace() { + fun endLaunchToShortcutTrace(): Long { val time = elapsedTimeNow() val startTime = launchToFirstShortcut.get() - if (startTime >= 0 && launchToFirstShortcut.compareAndSet(startTime, -1L)) { + return if (startTime >= 0 && launchToFirstShortcut.compareAndSet(startTime, -1L)) { Trace.endAsyncSection(SECTION_LAUNCH_TO_SHORTCUT, 1) - Log.d(TAG, "stat to first shortcut time: ${time - startTime} ms") + 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 { diff --git a/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt b/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt index ee6893d0..3ffbe039 100644 --- a/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt +++ b/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt @@ -38,6 +38,10 @@ import androidx.annotation.WorkerThread import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope import com.android.intentresolver.chooser.DisplayResolveInfo +import com.android.intentresolver.measurements.Tracer +import com.android.intentresolver.measurements.runTracing +import java.util.concurrent.Executor +import java.util.function.Consumer import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asExecutor @@ -47,20 +51,19 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch -import java.util.concurrent.Executor -import java.util.function.Consumer /** * 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 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. + * 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?, @@ -73,13 +76,15 @@ open class ShortcutLoader @VisibleForTesting constructor( private val shortcutToChooserTargetConverter = ShortcutToChooserTargetConverter() private val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager private val appPredictorCallback = AppPredictor.Callback { onAppPredictorCallback(it) } - 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) + 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( @@ -93,7 +98,8 @@ open class ShortcutLoader @VisibleForTesting constructor( context, lifecycle, appPredictor?.let { AppPredictorProxy(it) }, - userHandle, userHandle == UserHandle.of(ActivityManager.getCurrentUser()), + userHandle, + userHandle == UserHandle.of(ActivityManager.getCurrentUser()), targetIntentFilter, Dispatchers.IO, callback @@ -103,43 +109,38 @@ open class ShortcutLoader @VisibleForTesting constructor( appPredictor?.registerPredictionUpdates(dispatcher.asExecutor(), appPredictorCallback) lifecycle.coroutineScope .launch { - appTargetSource.combine(shortcutSource) { appTargets, shortcutData -> - if (appTargets == null || shortcutData == null) { - null - } else { - filterShortcuts( - appTargets, - shortcutData.shortcuts, - shortcutData.isFromAppPredictor, - shortcutData.appPredictorTargets - ) + 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")) - } + .filter { it != null } + .flowOn(dispatcher) + .collect { callback.accept(it ?: error("can not be null")) } } .invokeOnCompletion { - runCatching { - appPredictor?.unregisterPredictionUpdates(appPredictorCallback) - } + runCatching { appPredictor?.unregisterPredictionUpdates(appPredictorCallback) } Log.d(TAG, "destroyed, user: $userHandle") } reset() } - /** - * Clear application targets (see [updateAppTargets] and initiate shrtcuts loading. - */ + /** 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() - } + lifecycle.coroutineScope.launch(dispatcher) { loadShortcuts() } } /** @@ -154,7 +155,10 @@ open class ShortcutLoader @VisibleForTesting constructor( @WorkerThread private fun loadShortcuts() { // no need to query direct share for work profile when its locked or disabled - if (!shouldQueryDirectShareTargets()) return + if (!shouldQueryDirectShareTargets()) { + Log.d(TAG, "skip shortcuts loading for user $userHandle") + return + } Log.d(TAG, "querying direct share targets for user $userHandle") queryDirectShareTargets(false) } @@ -163,33 +167,49 @@ open class ShortcutLoader @VisibleForTesting constructor( private fun queryDirectShareTargets(skipAppPredictionService: Boolean) { if (!skipAppPredictionService && appPredictor != null) { 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 + 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) @@ -202,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 @@ -234,9 +252,11 @@ open class ShortcutLoader @VisibleForTesting constructor( ): 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>() @@ -246,17 +266,17 @@ open class ShortcutLoader @VisibleForTesting constructor( // ShareShortcutInfos directly. 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) } @@ -270,16 +290,17 @@ open class ShortcutLoader @VisibleForTesting constructor( } /** - * 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 ShortcutData( val shortcuts: List<ShareShortcutInfo>, @@ -287,27 +308,21 @@ open class ShortcutLoader @VisibleForTesting constructor( 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.updateAppTargets] 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?> @@ -318,27 +333,20 @@ 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() } @@ -350,12 +358,21 @@ open class ShortcutLoader @VisibleForTesting constructor( 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/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/ChooserWrapperActivity.java b/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java index 82ba8d4d..fa934f87 100644 --- a/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java +++ b/java/tests/src/com/android/intentresolver/ChooserWrapperActivity.java @@ -32,10 +32,11 @@ 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.chooser.DisplayResolveInfo; import com.android.intentresolver.chooser.TargetInfo; -import com.android.intentresolver.contentpreview.ImageLoader; import com.android.intentresolver.flags.FeatureFlagRepository; import com.android.intentresolver.grid.ChooserGridAdapter; import com.android.intentresolver.shortcuts.ShortcutLoader; @@ -194,10 +195,10 @@ public class ChooserWrapperActivity } @Override - protected ImageLoader createPreviewImageLoader() { - return sOverrides.imageLoader == null - ? super.createPreviewImageLoader() - : sOverrides.imageLoader; + protected ViewModelProvider.Factory createPreviewViewModelFactory() { + return TestContentPreviewViewModel.Companion.wrap( + super.createPreviewViewModelFactory(), + sOverrides.imageLoader); } @Override diff --git a/java/tests/src/com/android/intentresolver/ResolverActivityTest.java b/java/tests/src/com/android/intentresolver/ResolverActivityTest.java index 5cece092..31c0a498 100644 --- a/java/tests/src/com/android/intentresolver/ResolverActivityTest.java +++ b/java/tests/src/com/android/intentresolver/ResolverActivityTest.java @@ -34,6 +34,7 @@ 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; @@ -741,7 +742,7 @@ public class ResolverActivityTest { } @Test - public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_autolaunch() { + public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_doesNotAutoLaunch() { markWorkProfileUserAvailable(); int workProfileTargets = 4; List<ResolvedComponentInfo> personalResolvedComponentInfos = @@ -763,7 +764,7 @@ public class ResolverActivityTest { mActivityRule.launchActivity(sendIntent); waitForIdle(); - assertThat(chosen[0], is(personalResolvedComponentInfos.get(1).getResolveInfoAt(0))); + assertNull(chosen[0]); } @Test 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/TestPreviewImageLoader.kt b/java/tests/src/com/android/intentresolver/TestPreviewImageLoader.kt index 74a253b8..bf87ed8a 100644 --- a/java/tests/src/com/android/intentresolver/TestPreviewImageLoader.kt +++ b/java/tests/src/com/android/intentresolver/TestPreviewImageLoader.kt @@ -18,13 +18,12 @@ 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 bitmaps: Map<Uri, Bitmap> -) : ImageLoader { - override fun loadImage(uri: Uri, callback: Consumer<Bitmap?>) { +internal class TestPreviewImageLoader(private val bitmaps: Map<Uri, Bitmap>) : ImageLoader { + override fun loadImage(callerLifecycle: Lifecycle, uri: Uri, callback: Consumer<Bitmap?>) { callback.accept(bitmaps[uri]) } diff --git a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java index 6ba67fa7..c2212bc2 100644 --- a/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java +++ b/java/tests/src/com/android/intentresolver/UnbundledChooserActivityTest.java @@ -2341,7 +2341,7 @@ public class UnbundledChooserActivityTest { } @Test - public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_autolaunch() { + public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_doesNotAutoLaunch() { markWorkProfileUserAvailable(); int workProfileTargets = 4; List<ResolvedComponentInfo> personalResolvedComponentInfos = @@ -2360,7 +2360,7 @@ public class UnbundledChooserActivityTest { mActivityRule.launchActivity(Intent.createChooser(sendIntent, "Test")); waitForIdle(); - assertThat(chosen[0], is(personalResolvedComponentInfos.get(1).getResolveInfoAt(0))); + assertNull(chosen[0]); } @Test diff --git a/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt b/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt index 5a4b6c76..c62f36ce 100644 --- a/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt +++ b/java/tests/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt @@ -16,7 +16,6 @@ package com.android.intentresolver.contentpreview -import android.content.ClipDescription import android.content.Intent import android.graphics.Bitmap import android.net.Uri @@ -37,13 +36,14 @@ import org.mockito.Mockito.verify class ChooserContentPreviewUiTest { private val lifecycle = mock<Lifecycle>() private val previewData = mock<PreviewDataProvider>() - private val imageClassifier = MimeTypeClassifier { mimeType -> - mimeType != null && ClipDescription.compareMimeTypes(mimeType, "image/*") - } private val headlineGenerator = mock<HeadlineGenerator>() private val imageLoader = object : ImageLoader { - override fun loadImage(uri: Uri, callback: Consumer<Bitmap?>) { + override fun loadImage( + callerLifecycle: Lifecycle, + uri: Uri, + callback: Consumer<Bitmap?>, + ) { callback.accept(null) } override fun prePopulate(uris: List<Uri>) = Unit @@ -67,11 +67,10 @@ class ChooserContentPreviewUiTest { lifecycle, previewData, Intent(Intent.ACTION_VIEW), - imageClassifier, imageLoader, actionFactory, transitionCallback, - headlineGenerator + headlineGenerator, ) assertThat(testSubject.preferredContentPreview) .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_TEXT) @@ -87,11 +86,10 @@ class ChooserContentPreviewUiTest { lifecycle, previewData, Intent(Intent.ACTION_SEND), - imageClassifier, imageLoader, actionFactory, transitionCallback, - headlineGenerator + headlineGenerator, ) assertThat(testSubject.preferredContentPreview) .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE) @@ -116,11 +114,10 @@ class ChooserContentPreviewUiTest { lifecycle, previewData, Intent(Intent.ACTION_SEND).apply { putExtra(Intent.EXTRA_TEXT, "Shared text") }, - imageClassifier, imageLoader, actionFactory, transitionCallback, - headlineGenerator + headlineGenerator, ) assertThat(testSubject.mContentPreviewUi) .isInstanceOf(FilesPlusTextContentPreviewUi::class.java) @@ -145,11 +142,10 @@ class ChooserContentPreviewUiTest { lifecycle, previewData, Intent(Intent.ACTION_SEND), - imageClassifier, imageLoader, actionFactory, transitionCallback, - headlineGenerator + headlineGenerator, ) assertThat(testSubject.preferredContentPreview) .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE) diff --git a/java/tests/src/com/android/intentresolver/ImagePreviewImageLoaderTest.kt b/java/tests/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoaderTest.kt index 3c399cc4..184401a0 100644 --- a/java/tests/src/com/android/intentresolver/ImagePreviewImageLoaderTest.kt +++ b/java/tests/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoaderTest.kt @@ -14,15 +14,19 @@ * limitations under the License. */ -package com.android.intentresolver +package com.android.intentresolver.contentpreview import android.content.ContentResolver -import android.content.Context -import android.content.res.Resources 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 kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineStart.UNDISPATCHED import kotlinx.coroutines.Dispatchers @@ -30,6 +34,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch +import kotlinx.coroutines.plus import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestCoroutineScheduler import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -49,28 +54,26 @@ class ImagePreviewImageLoaderTest { 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 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 contentResolver = + mock<ContentResolver> { + whenever(loadThumbnail(any(), any(), anyOrNull())).thenReturn(bitmap) + } private val lifecycleOwner = TestLifecycleOwner() - private val dispatcher = UnconfinedTestDispatcher(scheduler) - private val testSubject = ImagePreviewImageLoader( - context, lifecycleOwner.lifecycle, 1, dispatcher - ) + 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, + 1, + ) } @After @@ -110,14 +113,16 @@ class ImagePreviewImageLoaderTest { fun invoke_overlappedRequests_Deduplicate() = runTest { val scheduler = TestCoroutineScheduler() val dispatcher = StandardTestDispatcher(scheduler) - val testSubject = ImagePreviewImageLoader(context, lifecycleOwner.lifecycle, 1, dispatcher) + val testSubject = + ImagePreviewImageLoader( + lifecycleOwner.lifecycle.coroutineScope + dispatcher, + imageSize.width, + contentResolver, + 1, + ) coroutineScope { - launch(start = UNDISPATCHED) { - testSubject(uriOne, false) - } - launch(start = UNDISPATCHED) { - testSubject(uriOne, false) - } + launch(start = UNDISPATCHED) { testSubject(uriOne, false) } + launch(start = UNDISPATCHED) { testSubject(uriOne, false) } scheduler.advanceUntilIdle() } @@ -154,11 +159,15 @@ class ImagePreviewImageLoaderTest { fun invoke_imageLoaderScopeClosedMidflight_throwsCancellationException() = runTest { val scheduler = TestCoroutineScheduler() val dispatcher = StandardTestDispatcher(scheduler) - val testSubject = ImagePreviewImageLoader(context, lifecycleOwner.lifecycle, 1, dispatcher) + val testSubject = + ImagePreviewImageLoader( + lifecycleOwner.lifecycle.coroutineScope + dispatcher, + imageSize.width, + contentResolver, + 1 + ) coroutineScope { - val deferred = async(start = UNDISPATCHED) { - testSubject(uriOne, false) - } + val deferred = async(start = UNDISPATCHED) { testSubject(uriOne, false) } lifecycleOwner.state = Lifecycle.State.DESTROYED scheduler.advanceUntilIdle() deferred.await() @@ -169,14 +178,16 @@ class ImagePreviewImageLoaderTest { fun invoke_multipleCallsWithDifferentCacheInstructions_cachingPrevails() = runTest { val scheduler = TestCoroutineScheduler() val dispatcher = StandardTestDispatcher(scheduler) - val testSubject = ImagePreviewImageLoader(context, lifecycleOwner.lifecycle, 1, dispatcher) + val testSubject = + ImagePreviewImageLoader( + lifecycleOwner.lifecycle.coroutineScope + dispatcher, + imageSize.width, + contentResolver, + 1 + ) coroutineScope { - launch(start = UNDISPATCHED) { - testSubject(uriOne, false) - } - launch(start = UNDISPATCHED) { - testSubject(uriOne, true) - } + launch(start = UNDISPATCHED) { testSubject(uriOne, false) } + launch(start = UNDISPATCHED) { testSubject(uriOne, true) } scheduler.advanceUntilIdle() } testSubject(uriOne, true) diff --git a/java/tests/src/com/android/intentresolver/contentpreview/PreviewDataProviderTest.kt b/java/tests/src/com/android/intentresolver/contentpreview/PreviewDataProviderTest.kt index 5be373b3..2c47efa5 100644 --- a/java/tests/src/com/android/intentresolver/contentpreview/PreviewDataProviderTest.kt +++ b/java/tests/src/com/android/intentresolver/contentpreview/PreviewDataProviderTest.kt @@ -16,7 +16,6 @@ package com.android.intentresolver.contentpreview -import android.content.ClipDescription import android.content.ContentInterface import android.content.Intent import android.database.MatrixCursor @@ -44,9 +43,7 @@ import org.mockito.Mockito.verify @OptIn(ExperimentalCoroutinesApi::class) class PreviewDataProviderTest { private val contentResolver = mock<ContentInterface>() - private val mimeTypeClassifier = MimeTypeClassifier { mimeType -> - mimeType != null && ClipDescription.compareMimeTypes(mimeType, "image/*") - } + private val mimeTypeClassifier = DefaultMimeTypeClassifier private val lifecycleOwner = TestLifecycleOwner() private val dispatcher = UnconfinedTestDispatcher() |