Merge Android 12L

Bug: 222710654
Merged-In: Idc284bc85f8f701a75e4dea96ff7fbe049734f9e
Change-Id: I6787c5a6bbf222c671235ee727c846f2a491e351
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 8b37a56..55fe2da 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -28,8 +28,8 @@
     <string name="permdesc_downloadCacheNonPurgeable" msgid="3071381088686444674">"এপটোক ডাউনল’ড কেশ্বত ফাইল ডাউনল’ড কৰিবলৈ অনুমতি দিয়ে, যাক ডাউনল’ড মেনেজাৰক অধিক খালী ঠাই প্ৰয়োজন হ\'লে স্বয়ংক্ৰিয়ভাৱে মচি পেলাব নোৱাৰি।"</string>
     <string name="permlab_downloadWithoutNotification" msgid="4877101864770265405">"জাননী নিদিয়াকৈ ফাইল ডাউনল’ড কৰিব পাৰে"</string>
     <string name="permdesc_downloadWithoutNotification" msgid="7699189763226483523">"এপটোক ব্যৱহাৰকাৰীক কোনো জাননী নিদিয়াকৈ ডাউনল’ড মেনেজাৰ ব্যৱহাৰ কৰি ফাইল ডাউনল’ড কৰিবলৈ অনুমতি দিয়ে।"</string>
-    <string name="permlab_accessAllDownloads" msgid="8227356876527248611">"আটাইবোৰ ছিষ্টেম ডাউনল\'ড এক্সেছ কৰিব পাৰে"</string>
-    <string name="permdesc_accessAllDownloads" msgid="7541731738152145079">"ছিষ্টেমত থকা যিকোনো এপে সূচনা কৰা আটাইবোৰ ডাউনল’ড চাবলৈ আৰু সংশোধন কৰিবলৈ এপ্‌টোক অনুমতি দিয়ে।"</string>
+    <string name="permlab_accessAllDownloads" msgid="8227356876527248611">"সকলো ছিষ্টেম ডাউনল\'ডত প্ৰৱেশ কৰিব পাৰে"</string>
+    <string name="permdesc_accessAllDownloads" msgid="7541731738152145079">"ছিষ্টেমত থকা যিকোনো এপে সূচনা কৰা সকলো ডাউনল’ড চাবলৈ আৰু সংশোধন কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
     <string name="download_unknown_title" msgid="1017800350818840396">"&lt;শিৰোনামবিহীন&gt;"</string>
     <string name="notification_download_complete" msgid="466652037490092787">"ডাউনল’ড সম্পূৰ্ণ হ’ল।"</string>
     <string name="notification_download_failed" msgid="3932167763860605874">"ডাউনল’ড কৰিবপৰা নগ\'ল।"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 75a81bf..af2995e 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -41,7 +41,7 @@
     <string name="wifi_recommended_body" msgid="8710820743211704403">"Ovim preuzimanjem od <xliff:g id="SIZE">%1$s </xliff:g> možete da skratite vek trajanja baterije i/ili preterano koristite mobilnu vezu za prenos podataka, što može da dovede do troškova kod mobilnog operatera shodno tarifnom paketu.\n\n Dodirnite <xliff:g id="QUEUE_TEXT">%2$s</xliff:g> da biste započeli ovo preuzimanje kada se ponovo povežete sa WiFi mrežom."</string>
     <string name="button_queue_for_wifi" msgid="6650185573566994738">"Red"</string>
     <string name="button_cancel_download" msgid="4135046775536601831">"Otkaži"</string>
-    <string name="button_start_now" msgid="3817100969365441730">"Započni"</string>
+    <string name="button_start_now" msgid="3817100969365441730">"Započni odmah"</string>
     <plurals name="notif_summary_active" formatted="false" msgid="8652501374845637331">
       <item quantity="one">Preuzima se <xliff:g id="NUMBER">%d</xliff:g> datoteka</item>
       <item quantity="few">Preuzimaju se <xliff:g id="NUMBER">%d</xliff:g> datoteke</item>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 7d5647e..1e2a420 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -36,9 +36,9 @@
     <string name="notification_need_wifi_for_size" msgid="4743443900432303646">"Ukuran download memerlukan Wi-Fi."</string>
     <string name="notification_paused_in_background" msgid="6393408819031041778">"Dijeda di latar belakang."</string>
     <string name="wifi_required_title" msgid="7266700488421122218">"Download terlalu besar untuk jaringan operator"</string>
-    <string name="wifi_required_body" msgid="4005023496578941958">"Anda harus menggunakan Wi-Fi untuk menyelesaikan download <xliff:g id="SIZE">%1$s </xliff:g> ini. \n\nSentuh <xliff:g id="QUEUE_TEXT">%2$s </xliff:g> untuk memulai download ini saat Anda terhubung lagi ke jaringan Wi-Fi."</string>
+    <string name="wifi_required_body" msgid="4005023496578941958">"Anda harus menggunakan Wi-Fi untuk menyelesaikan download <xliff:g id="SIZE">%1$s </xliff:g> ini. \n\nSentuh <xliff:g id="QUEUE_TEXT">%2$s </xliff:g> untuk memulai download ini saat Anda tersambung lagi ke jaringan Wi-Fi."</string>
     <string name="wifi_recommended_title" msgid="6488158053932133804">"Antrekan untuk didownload nanti?"</string>
-    <string name="wifi_recommended_body" msgid="8710820743211704403">"Memulai download <xliff:g id="SIZE">%1$s </xliff:g> ini sekarang dapat mempersingkat masa pakai baterai Anda dan/atau menyebabkan penggunaan berlebih dari sambungan data seluler, yang dapat berakibat dikenai tagihan oleh operator ponsel, tergantung paket data Anda.\n\n Sentuh <xliff:g id="QUEUE_TEXT">%2$s</xliff:g> untuk memulai download ini saat Anda terhubung lagi ke jaringan Wi-Fi."</string>
+    <string name="wifi_recommended_body" msgid="8710820743211704403">"Memulai download <xliff:g id="SIZE">%1$s </xliff:g> ini sekarang dapat mempersingkat masa pakai baterai Anda dan/atau menyebabkan penggunaan berlebih dari sambungan data seluler, yang dapat berakibat dikenai tagihan oleh operator ponsel, tergantung paket data Anda.\n\n Sentuh <xliff:g id="QUEUE_TEXT">%2$s</xliff:g> untuk memulai download ini saat Anda tersambung lagi ke jaringan Wi-Fi."</string>
     <string name="button_queue_for_wifi" msgid="6650185573566994738">"Antrean"</string>
     <string name="button_cancel_download" msgid="4135046775536601831">"Batal"</string>
     <string name="button_start_now" msgid="3817100969365441730">"Mulai sekarang"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 730cc91..772ac26 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -43,12 +43,12 @@
     <string name="button_cancel_download" msgid="4135046775536601831">"Annulla"</string>
     <string name="button_start_now" msgid="3817100969365441730">"Avvia adesso"</string>
     <plurals name="notif_summary_active" formatted="false" msgid="8652501374845637331">
-      <item quantity="one"><xliff:g id="NUMBER">%d</xliff:g> files downloading</item>
       <item quantity="other">Download di <xliff:g id="NUMBER">%d</xliff:g> file in corso</item>
+      <item quantity="one">Download di 1 file in corso</item>
     </plurals>
     <plurals name="notif_summary_waiting" formatted="false" msgid="1782251721955177526">
-      <item quantity="one"><xliff:g id="NUMBER">%d</xliff:g> files waiting</item>
       <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> file in attesa</item>
+      <item quantity="one">1 file in attesa</item>
     </plurals>
     <string name="download_remaining" msgid="2313089371178695625">"<xliff:g id="DURATION">%s</xliff:g> rimanenti"</string>
     <string name="download_no_application_title" msgid="5780812573953335721">"Impossibile aprire il file"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index d6907f7..4cf0e88 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -41,7 +41,7 @@
     <string name="wifi_recommended_body" msgid="8710820743211704403">"यस <xliff:g id="SIZE">%1$s </xliff:g> डाउनलोडलाई सुरु गर्दा तपाईंको ब्याट्रिको काल छोट्टिन सक्छ र/वा तपाईंको मोबाइल डेटा जडानको अधिकतम प्रयोग भई तपाईंको डेटा योजना अनुसार मोबाइल अपरेटरले थप शुल्क लिन सक्छ। \n\n छुनुहोस् <xliff:g id="QUEUE_TEXT">%2$s</xliff:g>तल यस डाउनलोडलाई सुरु गर्न अर्को पटक तपाईं Wi-Fi सन्जालमा जडित हुने बेला।"</string>
     <string name="button_queue_for_wifi" msgid="6650185573566994738">"लाम"</string>
     <string name="button_cancel_download" msgid="4135046775536601831">"रद्द गर्नुहोस्"</string>
-    <string name="button_start_now" msgid="3817100969365441730">"अहिले न"</string>
+    <string name="button_start_now" msgid="3817100969365441730">"अहिले सुरु गर्नुहोस्"</string>
     <plurals name="notif_summary_active" formatted="false" msgid="8652501374845637331">
       <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> फाइलहरू डाउनलोड हुँदैछन्</item>
       <item quantity="one">१ फाइल डाउनलोड हुँदैछ</item>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 952c4e4..19a87b8 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -18,7 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="5264040740662487684">"Downloadbeheer"</string>
     <string name="storage_description" msgid="169690279447532621">"Downloads"</string>
-    <string name="permlab_downloadManager" msgid="4241473724446132797">"Downloadbeheer bekijken."</string>
+    <string name="permlab_downloadManager" msgid="4241473724446132797">"Downloadbeheer weergeven."</string>
     <string name="permdesc_downloadManager" msgid="5562734314998369030">"Hiermee heeft de app toegang tot downloadbeheer en kan de app via downloadbeheer bestanden downloaden. Schadelijke apps kunnen dit gebruiken om downloads te verstoren en toegang te krijgen tot persoonlijke informatie."</string>
     <string name="permlab_downloadManagerAdvanced" msgid="2225663947531460795">"Geavanceerde functies van de downloadbeheerder."</string>
     <string name="permdesc_downloadManagerAdvanced" msgid="3902478062563030716">"Hiermee heeft de app toegang tot de geavanceerde functies van downloadbeheer. Schadelijke apps kunnen dit gebruiken om downloads te verstoren en toegang te krijgen tot persoonlijke informatie."</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 4470f93..3121473 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -40,7 +40,7 @@
     <string name="wifi_recommended_title" msgid="6488158053932133804">"ପରେ ଡାଉନଲୋଡ୍‌ କରିବା ପାଇଁ ଧାଡ଼ିରେ ରଖିବେ?"</string>
     <string name="wifi_recommended_body" msgid="8710820743211704403">"ଏହି <xliff:g id="SIZE">%1$s </xliff:g>ର ଡାଉନଲୋଡ୍‌ ଆରମ୍ଭ କଲେ ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ଶୀଘ୍ର ସରିଯାଇପାରେ ଏବଂ/କିମ୍ୱା ମୋବାଇଲ୍‌ର ଅନେକ ଡାଟା ଖର୍ଚ୍ଚ ହୋଇପାରେ, ଯାହା ପାଇଁ ମୋବାଇଲ୍‌ ଅପରେଟର୍‌, ଆପଣଙ୍କ ଡାଟା ପ୍ଲାନ୍‌ ହିସାବରେ ଆପଣଙ୍କଠାରୁ ପଇସା ନେଇପାରେ|\n\n ଆଗାମୀ ଥର ଯେତେବେଳେ ଆପଣ ୱାଇ-ଫାଇ ନେଟୱର୍କ ସହିତ ଯୋଡ଼ିହେବେ, ଏହି ଡାଉନଲୋଡ୍‌ ଆରମ୍ଭ କରିବା ପାଇଁ <xliff:g id="QUEUE_TEXT">%2$s</xliff:g>କୁ ସ୍ପର୍ଶ କରନ୍ତୁ|"</string>
     <string name="button_queue_for_wifi" msgid="6650185573566994738">"ଧାଡ଼ିରେ ରଖନ୍ତୁ"</string>
-    <string name="button_cancel_download" msgid="4135046775536601831">"ବାତିଲ୍ କରନ୍ତୁ"</string>
+    <string name="button_cancel_download" msgid="4135046775536601831">"ବାତିଲ୍‍"</string>
     <string name="button_start_now" msgid="3817100969365441730">"ବର୍ତ୍ତମାନ ଆରମ୍ଭ କରନ୍ତୁ"</string>
     <plurals name="notif_summary_active" formatted="false" msgid="8652501374845637331">
       <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g>ଟି ଫାଇଲ୍‌ ଡାଉନଲୋଡ୍‌ ହେଉଛି</item>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index da877cf..0d58a8f 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -23,7 +23,7 @@
     <string name="permlab_downloadManagerAdvanced" msgid="2225663947531460795">"ਐਡਵਾਂਸਡ ਡਾਊਨਲੋਡ ਪ੍ਰਬੰਧਕ ਫੰਕਸ਼ਨ।"</string>
     <string name="permdesc_downloadManagerAdvanced" msgid="3902478062563030716">"ਐਪ ਨੂੰ ਡਾਊਨਲੋਡ ਪ੍ਰਬੰਧਕ ਦੇ ਐਡਵਾਂਸਡ ਫੰਕਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਖਰਾਬ ਐਪਾਂ ਇਸਦੀ ਵਰਤੋਂ ਡਾਊਨਲੋਡ ਵਿੱਚ ਵਿਘਨ ਪਾਉਣ ਅਤੇ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਲਈ ਕਰ ਸਕਦੀਆਂ ਹਨ।"</string>
     <string name="permlab_downloadCompletedIntent" msgid="2674407390116052956">"ਡਾਊਨਲੋਡ ਸੂਚਨਾਵਾਂ ਭੇਜੋ।"</string>
-    <string name="permdesc_downloadCompletedIntent" msgid="3384693829639860032">"ਐਪ ਨੂੰ ਪੂਰੇ ਹੋਏ ਡਾਊਨਲੋਡ ਬਾਰੇ ਸੂਚਨਾਵਾਂ ਭੇਜਣ ਦਿਓ। ਨੁਕਸਾਨਦੇਹ ਐਪਾਂ ਇਸਦੀ ਵਰਤੋਂ ਫ਼ਾਈਲਾਂ ਡਾਊਨਲੋਡ ਕਰਨ ਵਾਲੀਆਂ ਹੋਰ ਐਪਾਂ ਨੂੰ ਉਲਝਣ ਵਿੱਚ ਪਾਉਣ ਲਈ ਕਰ ਸਕਦੀਆਂ ਹਨ।"</string>
+    <string name="permdesc_downloadCompletedIntent" msgid="3384693829639860032">"ਐਪ ਨੂੰ ਡਾਊਨਲੋਡਸ ਪੂਰਾ ਕੀਤੇ ਬਿਨਾਂ ਸੂਚਨਾਵਾਂ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਖ਼ਰਾਬ ਐਪਸ ਇਸਦੀ ਵਰਤੋਂ ਹੋਰਾਂ ਐਪਸ ਨੂੰ ਉਲਝਣ ਵਿੱਚ ਪਾਉਣ ਲਈ ਕਰ ਸਕਦੇ ਹਨ ਜੋ ਫਾਈਲਾਂ ਡਾਊਨਲੋਡ ਕਰਦੇ ਹਨ।"</string>
     <string name="permlab_downloadCacheNonPurgeable" msgid="4538031250425141333">"ਡਾਊਨਲੋਡ ਕੈਸ਼ੇ ਵਿੱਚ ਜਗ੍ਹਾ ਰੱਖਿਅਤ ਕਰੋ"</string>
     <string name="permdesc_downloadCacheNonPurgeable" msgid="3071381088686444674">"ਐਪ ਨੂੰ ਡਾਊਨਲੋਡ ਕੈਸ਼ੇ ਵਿੱਚ ਉਹ ਫਾਈਲਾਂ ਡਾਊਨਲੋਡ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਜੋ ਆਪਣੇ ਆਪ ਨਹੀਂ ਮਿਟਾਈਆਂ ਜਾ ਸਕਦੀਆਂ ਜਦੋਂ ਡਾਊਨਲੋਡ ਪ੍ਰਬੰਧਕ ਨੂੰ ਵੱਧ ਜਗ੍ਹਾ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।"</string>
     <string name="permlab_downloadWithoutNotification" msgid="4877101864770265405">"ਸੂਚਨਾ ਤੋਂ ਬਿਨਾਂ ਫ਼ਾਈਲਾਂ ਡਾਊਨਲੋਡ ਕਰੋ"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index e64fadf..e8b3e02 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -43,12 +43,12 @@
     <string name="button_cancel_download" msgid="4135046775536601831">"Cancelar"</string>
     <string name="button_start_now" msgid="3817100969365441730">"Começar agora"</string>
     <plurals name="notif_summary_active" formatted="false" msgid="8652501374845637331">
-      <item quantity="one">1 ficheiro a ser transferido</item>
       <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> ficheiros a serem transferidos</item>
+      <item quantity="one">1 ficheiro a ser transferido</item>
     </plurals>
     <plurals name="notif_summary_waiting" formatted="false" msgid="1782251721955177526">
-      <item quantity="one">1 ficheiro em espera</item>
       <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> ficheiros em espera</item>
+      <item quantity="one">1 ficheiro em espera</item>
     </plurals>
     <string name="download_remaining" msgid="2313089371178695625">"Faltam <xliff:g id="DURATION">%s</xliff:g>"</string>
     <string name="download_no_application_title" msgid="5780812573953335721">"Não é possível abrir o ficheiro"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 2355624..bd9021e 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="5264040740662487684">"Менеджер скачивания"</string>
+    <string name="app_label" msgid="5264040740662487684">"Диспетчер загрузки"</string>
     <string name="storage_description" msgid="169690279447532621">"Скачанные"</string>
     <string name="permlab_downloadManager" msgid="4241473724446132797">"Доступ к менеджеру загрузки."</string>
     <string name="permdesc_downloadManager" msgid="5562734314998369030">"Приложение получит доступ к диспетчеру загрузок и сможет загружать файлы через него. Вредоносные программы смогут таким образом прерывать загрузки и просматривать личную информацию."</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 6a259cb..38e41b3 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -41,7 +41,7 @@
     <string name="wifi_recommended_body" msgid="8710820743211704403">"Овим преузимањем од <xliff:g id="SIZE">%1$s </xliff:g> можете да скратите век трајања батерије и/или претерано користите мобилну везу за пренос података, што може да доведе до трошкова код мобилног оператера сходно тарифном пакету.\n\n Додирните <xliff:g id="QUEUE_TEXT">%2$s</xliff:g> да бисте започели ово преузимање када се поново повежете са WiFi мрежом."</string>
     <string name="button_queue_for_wifi" msgid="6650185573566994738">"Ред"</string>
     <string name="button_cancel_download" msgid="4135046775536601831">"Откажи"</string>
-    <string name="button_start_now" msgid="3817100969365441730">"Започни"</string>
+    <string name="button_start_now" msgid="3817100969365441730">"Започни одмах"</string>
     <plurals name="notif_summary_active" formatted="false" msgid="8652501374845637331">
       <item quantity="one">Преузима се <xliff:g id="NUMBER">%d</xliff:g> датотека</item>
       <item quantity="few">Преузимају се <xliff:g id="NUMBER">%d</xliff:g> датотеке</item>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index e8fc369..1aa5f1c 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -33,12 +33,12 @@
     <string name="download_unknown_title" msgid="1017800350818840396">"&lt;Okänd&gt;"</string>
     <string name="notification_download_complete" msgid="466652037490092787">"Nedladdningen har slutförts."</string>
     <string name="notification_download_failed" msgid="3932167763860605874">"Det gick inte att ladda ned."</string>
-    <string name="notification_need_wifi_for_size" msgid="4743443900432303646">"Nedladdningen kräver wifi."</string>
+    <string name="notification_need_wifi_for_size" msgid="4743443900432303646">"Nedladdningen kräver Wi-Fi."</string>
     <string name="notification_paused_in_background" msgid="6393408819031041778">"Pausad i bakgrunden."</string>
     <string name="wifi_required_title" msgid="7266700488421122218">"Nedladdningen är för stor för operatörsnätverket"</string>
-    <string name="wifi_required_body" msgid="4005023496578941958">"Du måste använda wifi om du vill slutföra nedladdningen på <xliff:g id="SIZE">%1$s </xliff:g>. \n \n Tryck på <xliff:g id="QUEUE_TEXT">%2$s </xliff:g> om du vill påbörja nedladdningen nästa gång du är ansluten till ett wifi-nätverk."</string>
+    <string name="wifi_required_body" msgid="4005023496578941958">"Du måste använda Wi-Fi om du vill slutföra nedladdningen på <xliff:g id="SIZE">%1$s </xliff:g>. \n \n Tryck på <xliff:g id="QUEUE_TEXT">%2$s </xliff:g> om du vill påbörja nedladdningen nästa gång du är ansluten till ett Wi-Fi-nätverk."</string>
     <string name="wifi_recommended_title" msgid="6488158053932133804">"Vill du ställa den i kö för nedladdning senare?"</string>
-    <string name="wifi_recommended_body" msgid="8710820743211704403">"Om du laddar ned <xliff:g id="SIZE">%1$s </xliff:g> kan det leda till att batteritiden minskar eller att dataanslutningen överbelastas. Det kan i sin tur innebära att operatören tar ut högre avgifter, beroende på abonnemang.\n\n Tryck på <xliff:g id="QUEUE_TEXT">%2$s</xliff:g> om du vill starta nedladdningen nästa gång mobilen är ansluten till ett wifi-nätverk."</string>
+    <string name="wifi_recommended_body" msgid="8710820743211704403">"Om du laddar ned <xliff:g id="SIZE">%1$s </xliff:g> kan det leda till att batteritiden minskar eller att dataanslutningen överbelastas. Det kan i sin tur innebära att operatören tar ut högre avgifter, beroende på abonnemang.\n\n Tryck på <xliff:g id="QUEUE_TEXT">%2$s</xliff:g> om du vill starta nedladdningen nästa gång mobilen är ansluten till ett Wi-Fi-nätverk."</string>
     <string name="button_queue_for_wifi" msgid="6650185573566994738">"Kö"</string>
     <string name="button_cancel_download" msgid="4135046775536601831">"Avbryt"</string>
     <string name="button_start_now" msgid="3817100969365441730">"Starta nu"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 08d400c..96eac7c 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -19,15 +19,15 @@
     <string name="app_label" msgid="5264040740662487684">"பதிவிறக்க நிர்வாகி"</string>
     <string name="storage_description" msgid="169690279447532621">"பதிவிறக்கங்கள்"</string>
     <string name="permlab_downloadManager" msgid="4241473724446132797">"பதிவிறக்க நிர்வாகியை அணுகவும்."</string>
-    <string name="permdesc_downloadManager" msgid="5562734314998369030">"பதிவிறக்க நிர்வாகியை அணுகவும், ஃபைல்களைப் பதிவிறக்குவதற்காக அதைப் பயன்படுத்தவும் ஆப்ஸை அனுமதிக்கிறது. பதிவிறக்கங்களைத் தடைசெய்யவும், தனிப்பட்டத் தகவலை அணுகவும் தீங்கிழைக்கும் ஆப்ஸ் இதைப் பயன்படுத்தலாம்."</string>
+    <string name="permdesc_downloadManager" msgid="5562734314998369030">"பதிவிறக்க நிர்வாகியை அணுகவும், கோப்புகளைப் பதிவிறக்குவதற்காக அதைப் பயன்படுத்தவும் ஆப்ஸை அனுமதிக்கிறது. பதிவிறக்கங்களைத் தடைசெய்யவும், தனிப்பட்டத் தகவலை அணுகவும் தீங்கிழைக்கும் ஆப்ஸ் இதைப் பயன்படுத்தலாம்."</string>
     <string name="permlab_downloadManagerAdvanced" msgid="2225663947531460795">"மேம்பட்ட பதிவிறக்க நிர்வாகி செயல்பாடுகள்."</string>
     <string name="permdesc_downloadManagerAdvanced" msgid="3902478062563030716">"பதிவிறக்க நிர்வாகியின் மேம்பட்ட செயல்பாடுகளை அணுகுவதற்குப் ஆப்ஸை அனுமதிக்கிறது. பதிவிறக்கங்களைத் தடைசெய்யவும், தனிப்பட்டத் தகவலை அணுகவும் தீங்கிழைக்கும் ஆப்ஸ் இதைப் பயன்படுத்தலாம்."</string>
     <string name="permlab_downloadCompletedIntent" msgid="2674407390116052956">"பதிவிறக்க அறிவிப்புகளை அனுப்பவும்."</string>
-    <string name="permdesc_downloadCompletedIntent" msgid="3384693829639860032">"முடிந்த பதிவிறக்கங்கள் குறித்த அறிவிப்புகளை அனுப்புவதற்குப் ஆப்ஸை அனுமதிக்கிறது. ஃபைல்களைப் பதிவிறக்கும் பிற பயன்பாடுகளைக் குழப்புவதற்கு தீங்கிழைக்கும் ஆப்ஸ் இதைப் பயன்படுத்தலாம்."</string>
+    <string name="permdesc_downloadCompletedIntent" msgid="3384693829639860032">"முடிந்த பதிவிறக்கங்கள் குறித்த அறிவிப்புகளை அனுப்புவதற்குப் ஆப்ஸை அனுமதிக்கிறது. கோப்புகளைப் பதிவிறக்கும் பிற பயன்பாடுகளைக் குழப்புவதற்கு தீங்கிழைக்கும் ஆப்ஸ் இதைப் பயன்படுத்தலாம்."</string>
     <string name="permlab_downloadCacheNonPurgeable" msgid="4538031250425141333">"தற்காலிகச் சேமிப்பில் இடத்தை முன்பதிவு செய்தல்"</string>
-    <string name="permdesc_downloadCacheNonPurgeable" msgid="3071381088686444674">"பதிவிறக்க நிர்வாகிக்கு அதிகப்படியான இடம் தேவைப்படும்போது தானாகவே நீக்கப்படாத, தற்காலிகச் சேமிப்பில் ஃபைல்களைப் பதிவிறக்க ஆப்ஸை அனுமதிக்கிறது."</string>
-    <string name="permlab_downloadWithoutNotification" msgid="4877101864770265405">"அறிவிப்பு இல்லாமல் ஃபைல்களைப் பதிவிறக்குதல்"</string>
-    <string name="permdesc_downloadWithoutNotification" msgid="7699189763226483523">"எந்த அறிவிப்பையும் பயனருக்குக் காட்டாமல் பதிவிறக்க நிர்வாகியின் மூலம் ஃபைல்களைப் பதிவிறக்கப் ஆப்ஸை அனுமதிக்கிறது."</string>
+    <string name="permdesc_downloadCacheNonPurgeable" msgid="3071381088686444674">"பதிவிறக்க நிர்வாகிக்கு அதிகப்படியான இடம் தேவைப்படும்போது தானாகவே நீக்கப்படாத, தற்காலிகச் சேமிப்பில் கோப்புகளைப் பதிவிறக்க ஆப்ஸை அனுமதிக்கிறது."</string>
+    <string name="permlab_downloadWithoutNotification" msgid="4877101864770265405">"அறிவிப்பு இல்லாமல் கோப்புகளைப் பதிவிறக்குதல்"</string>
+    <string name="permdesc_downloadWithoutNotification" msgid="7699189763226483523">"எந்த அறிவிப்பையும் பயனருக்குக் காட்டாமல் பதிவிறக்க நிர்வாகியின் மூலம் கோப்புகளைப் பதிவிறக்கப் ஆப்ஸை அனுமதிக்கிறது."</string>
     <string name="permlab_accessAllDownloads" msgid="8227356876527248611">"அமைப்பின் எல்லா பதிவிறக்கங்களையும் அணுகுதல்"</string>
     <string name="permdesc_accessAllDownloads" msgid="7541731738152145079">"அமைப்பில் உள்ள எந்தப் பயன்பாட்டினாலும் தொடங்கப்படும் எல்லா பதிவிறக்கங்களையும் கண்டு மாற்றுவதற்குப் ஆப்ஸை அனுமதிக்கிறது."</string>
     <string name="download_unknown_title" msgid="1017800350818840396">"&lt;பெயரிடப்படாதது&gt;"</string>
@@ -43,15 +43,15 @@
     <string name="button_cancel_download" msgid="4135046775536601831">"ரத்துசெய்"</string>
     <string name="button_start_now" msgid="3817100969365441730">"இப்போது தொடங்கு"</string>
     <plurals name="notif_summary_active" formatted="false" msgid="8652501374845637331">
-      <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> ஃபைல்களை இறக்குகிறது</item>
-      <item quantity="one">1 ஃபைலை இறக்குகிறது</item>
+      <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> கோப்புகளை இறக்குகிறது</item>
+      <item quantity="one">1 கோப்பை இறக்குகிறது</item>
     </plurals>
     <plurals name="notif_summary_waiting" formatted="false" msgid="1782251721955177526">
-      <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> ஃபைல்கள்  காத்திருக்கின்றன</item>
-      <item quantity="one">1 ஃபைல் காத்திருக்கிறது</item>
+      <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> கோப்புகள் காத்திருக்கின்றன</item>
+      <item quantity="one">1 கோப்பு காத்திருக்கிறது</item>
     </plurals>
     <string name="download_remaining" msgid="2313089371178695625">"<xliff:g id="DURATION">%s</xliff:g> மீதமுள்ளது"</string>
-    <string name="download_no_application_title" msgid="5780812573953335721">"ஃபைலைத் திறக்க முடியவில்லை"</string>
+    <string name="download_no_application_title" msgid="5780812573953335721">"கோப்பைத் திறக்க முடியவில்லை"</string>
     <string name="root_downloads" msgid="8380500940211778491">"பதிவிறக்கங்கள்"</string>
     <string name="download_queued" msgid="3383844741769045371">"வரிசைப்படுத்தப்பட்டது"</string>
     <string name="download_running" msgid="774654178925442490">"செயலிலுள்ளது"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 3ed7cc0..b13fce7 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -19,15 +19,15 @@
     <string name="app_label" msgid="5264040740662487684">"డౌన్‌లోడ్ మేనేజ‌ర్‌"</string>
     <string name="storage_description" msgid="169690279447532621">"డౌన్‌లోడ్‌లు"</string>
     <string name="permlab_downloadManager" msgid="4241473724446132797">"డౌన్‌లోడ్ మేనేజర్‌ను యాక్సెస్ చేయి."</string>
-    <string name="permdesc_downloadManager" msgid="5562734314998369030">"డౌన్‌లోడ్ మేనేజర్‌ను యాక్సెస్ చేయడానికి మరియు దీన్ని ఉపయోగించి ఫైళ్లను డౌన్‌లోడ్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు డౌన్‌లోడ్‌లకు అంతరాయం కలిగించడానికి మరియు ప్రైవేట్ సమాచారాన్ని యాక్సెస్ చేయడానికి దీన్ని ఉపయోగించవచ్చు."</string>
+    <string name="permdesc_downloadManager" msgid="5562734314998369030">"డౌన్‌లోడ్ మేనేజర్‌ను యాక్సెస్ చేయడానికి మరియు దీన్ని ఉపయోగించి ఫైల్‌లను డౌన్‌లోడ్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు డౌన్‌లోడ్‌లకు అంతరాయం కలిగించడానికి మరియు ప్రైవేట్ సమాచారాన్ని యాక్సెస్ చేయడానికి దీన్ని ఉపయోగించవచ్చు."</string>
     <string name="permlab_downloadManagerAdvanced" msgid="2225663947531460795">"అధునాతన డౌన్‌లోడ్ నిర్వాహికి ఫంక్షన్‌లు."</string>
     <string name="permdesc_downloadManagerAdvanced" msgid="3902478062563030716">"డౌన్‌లోడ్ మేనేజర్ యొక్క అధునాతన ఫంక్షన్‌లను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు డౌన్‌లోడ్‌లకు అంతరాయం కలిగించడానికి మరియు ప్రైవేట్ సమాచారాన్ని యాక్సెస్ చేయడానికి దీన్ని ఉపయోగించవచ్చు."</string>
     <string name="permlab_downloadCompletedIntent" msgid="2674407390116052956">"డౌన్‌లోడ్ నోటిఫికేషన్‌లను పంపండి."</string>
-    <string name="permdesc_downloadCompletedIntent" msgid="3384693829639860032">"పూర్తయిన డౌన్‌లోడ్‌ల గురించి నోటిఫికేషన్‌లను పంపడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు ఫైళ్లను డౌన్‌లోడ్ చేసే ఇతర యాప్‌లను తప్పుదారి పట్టించేందుకు దీన్ని ఉపయోగించవచ్చు."</string>
+    <string name="permdesc_downloadCompletedIntent" msgid="3384693829639860032">"పూర్తయిన డౌన్‌లోడ్‌ల గురించి నోటిఫికేషన్‌లను పంపడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు ఫైల్‌లను డౌన్‌లోడ్ చేసే ఇతర అనువర్తనాలను తప్పుదారి పట్టించేందుకు దీన్ని ఉపయోగించవచ్చు."</string>
     <string name="permlab_downloadCacheNonPurgeable" msgid="4538031250425141333">"డౌన్‌లోడ్ కాష్‌లో స్థలాన్ని నిల్వ చేయడం"</string>
-    <string name="permdesc_downloadCacheNonPurgeable" msgid="3071381088686444674">"డౌన్‌లోడ్ కాష్‌కు ఫైళ్లను డౌన్‌లోడ్ చేయడానికి యాప్‌ను అనుమతిస్తుంది, డౌన్‌లోడ్ నిర్వాహికికి మరింత స్థలం అవసరమైనప్పుడు అవి ఆటోమేటిక్‌గా తొలగించబడవు."</string>
-    <string name="permlab_downloadWithoutNotification" msgid="4877101864770265405">"నోటిఫికేషన్ లేకుండానే ఫైళ్లను డౌన్‌లోడ్ చేయడం"</string>
-    <string name="permdesc_downloadWithoutNotification" msgid="7699189763226483523">"వినియోగదారుకి ఎటువంటి నోటిఫికేషన్‌ను చూపకుండానే డౌన్‌లోడ్ నిర్వాహికి ద్వారా ఫైళ్లను డౌన్‌లోడ్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permdesc_downloadCacheNonPurgeable" msgid="3071381088686444674">"డౌన్‌లోడ్ కాష్‌కు ఫైల్‌లను డౌన్‌లోడ్ చేయడానికి యాప్‌ను అనుమతిస్తుంది, డౌన్‌లోడ్ నిర్వాహికికి మరింత స్థలం అవసరమైనప్పుడు అవి స్వయంచాలకంగా తొలగించబడవు."</string>
+    <string name="permlab_downloadWithoutNotification" msgid="4877101864770265405">"నోటిఫికేషన్ లేకుండానే ఫైల్‌లను డౌన్‌లోడ్ చేయడం"</string>
+    <string name="permdesc_downloadWithoutNotification" msgid="7699189763226483523">"వినియోగదారుకి ఎటువంటి నోటిఫికేషన్‌ను చూపకుండానే డౌన్‌లోడ్ నిర్వాహికి ద్వారా ఫైల్‌లను డౌన్‌లోడ్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_accessAllDownloads" msgid="8227356876527248611">"అన్ని సిస్టమ్ డౌన్‌లోడ్‌లను యాక్సెస్ చేయి"</string>
     <string name="permdesc_accessAllDownloads" msgid="7541731738152145079">"సిస్టమ్‌లో ఏదైనా యాప్ ద్వారా ప్రారంభించబడిన అన్ని డౌన్‌లోడ్‌లను వీక్షించడానికి మరియు సవరించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="download_unknown_title" msgid="1017800350818840396">"&lt;శీర్షిక లేనిది&gt;"</string>
@@ -43,11 +43,11 @@
     <string name="button_cancel_download" msgid="4135046775536601831">"రద్దు చేయి"</string>
     <string name="button_start_now" msgid="3817100969365441730">"ఇప్పుడే ప్రారంభించు"</string>
     <plurals name="notif_summary_active" formatted="false" msgid="8652501374845637331">
-      <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> ఫైళ్లు డౌన్‌లోడ్ అవుతున్నాయి</item>
+      <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> ఫైల్‌లు డౌన్‌లోడ్ అవుతున్నాయి</item>
       <item quantity="one">1 ఫైల్ డౌన్‌లోడ్ అవుతోంది</item>
     </plurals>
     <plurals name="notif_summary_waiting" formatted="false" msgid="1782251721955177526">
-      <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> ఫైళ్లు వేచి ఉన్నాయి</item>
+      <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> ఫైల్‌లు వేచి ఉన్నాయి</item>
       <item quantity="one">1 ఫైల్ వేచి ఉంది</item>
     </plurals>
     <string name="download_remaining" msgid="2313089371178695625">"<xliff:g id="DURATION">%s</xliff:g> మిగిలి ఉంది"</string>
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
index a9e0237..1afa090 100644
--- a/src/com/android/providers/downloads/DownloadProvider.java
+++ b/src/com/android/providers/downloads/DownloadProvider.java
@@ -257,6 +257,7 @@
     private int mSystemUid = -1;
 
     private StorageManager mStorageManager;
+    private AppOpsManager mAppOpsManager;
 
     /**
      * Creates and updated database on demand when opening it.
@@ -587,6 +588,7 @@
         mSystemUid = Process.SYSTEM_UID;
 
         mStorageManager = getContext().getSystemService(StorageManager.class);
+        mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
 
         // Grant access permissions for all known downloads to the owning apps.
         final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
@@ -735,10 +737,9 @@
                         android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                         "No permission to write");
 
-                final AppOpsManager appOps = getContext().getSystemService(AppOpsManager.class);
-                if (appOps.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, getCallingPackage(),
-                        Binder.getCallingUid(), getCallingAttributionTag(), null)
-                        != AppOpsManager.MODE_ALLOWED) {
+                if (mAppOpsManager.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE,
+                        getCallingPackage(), Binder.getCallingUid(), getCallingAttributionTag(),
+                        null) != AppOpsManager.MODE_ALLOWED) {
                     throw new SecurityException("No permission to write");
                 }
             }
@@ -1067,41 +1068,11 @@
             throw new SecurityException(e);
         }
 
-        final int targetSdkVersion = getCallingPackageTargetSdkVersion();
-        final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
-        final boolean runningLegacyMode = appOpsManager.checkOp(AppOpsManager.OP_LEGACY_STORAGE,
+        final boolean isLegacyMode = mAppOpsManager.checkOp(AppOpsManager.OP_LEGACY_STORAGE,
                 Binder.getCallingUid(), getCallingPackage()) == AppOpsManager.MODE_ALLOWED;
-
-        if (Helpers.isFilenameValidInExternalPackage(getContext(), file, getCallingPackage())
-                || Helpers.isFilenameValidInKnownPublicDir(file.getAbsolutePath())) {
-            // No permissions required for paths belonging to calling package or
-            // public downloads dir.
-            return;
-        } else if (runningLegacyMode && Helpers.isFilenameValidInExternal(getContext(), file)) {
-            // Otherwise we require write permission
-            getContext().enforceCallingOrSelfPermission(
-                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
-                    "No permission to write to " + file);
-
-            final AppOpsManager appOps = getContext().getSystemService(AppOpsManager.class);
-            if (appOps.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, getCallingPackage(),
-                    Binder.getCallingUid(), getCallingAttributionTag(), null)
-                    != AppOpsManager.MODE_ALLOWED) {
-                throw new SecurityException("No permission to write to " + file);
-            }
-        } else if (Helpers.isFilenameValidInExternalObbDir(file) &&
-                ((appOpsManager.noteOp(
-                    AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
-                    Binder.getCallingUid(), getCallingPackage(), null, "obb_download")
-                        == AppOpsManager.MODE_ALLOWED)
-                || (getContext().checkCallingOrSelfPermission(
-                    android.Manifest.permission.REQUEST_INSTALL_PACKAGES)
-                    == PackageManager.PERMISSION_GRANTED))) {
-            // Installers are allowed to download in OBB dirs, even outside their own package
-            return;
-        } else {
-            throw new SecurityException("Unsupported path " + file);
-        }
+        Helpers.checkDestinationFilePathRestrictions(file, getCallingPackage(), getContext(),
+                mAppOpsManager, getCallingAttributionTag(), isLegacyMode,
+                /* allowDownloadsDirOnly */ false);
     }
 
     private void checkDownloadedFilePath(ContentValues values) {
@@ -1123,49 +1094,15 @@
             throw new IllegalArgumentException("File doesn't exist: " + file);
         }
 
-        final int targetSdkVersion = getCallingPackageTargetSdkVersion();
-        final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
-        final boolean runningLegacyMode = appOpsManager.checkOp(AppOpsManager.OP_LEGACY_STORAGE,
-                Binder.getCallingUid(), getCallingPackage()) == AppOpsManager.MODE_ALLOWED;
-
         if (Binder.getCallingPid() == Process.myPid()) {
             return;
-        } else if (Helpers.isFilenameValidInExternalPackage(getContext(), file, getCallingPackage())
-                || Helpers.isFilenameValidInPublicDownloadsDir(file)) {
-            // No permissions required for paths belonging to calling package or
-            // public downloads dir.
-            return;
-        } else if (runningLegacyMode && Helpers.isFilenameValidInExternal(getContext(), file)) {
-            // Otherwise we require write permission
-            getContext().enforceCallingOrSelfPermission(
-                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
-                    "No permission to write to " + file);
-
-            final AppOpsManager appOps = getContext().getSystemService(AppOpsManager.class);
-            if (appOps.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, getCallingPackage(),
-                    Binder.getCallingUid(), getCallingAttributionTag(), null)
-                    != AppOpsManager.MODE_ALLOWED) {
-                throw new SecurityException("No permission to write to " + file);
-            }
-        } else {
-            throw new SecurityException("Unsupported path " + file);
         }
-    }
 
-    private int getCallingPackageTargetSdkVersion() {
-        final String callingPackage = getCallingPackage();
-        if (callingPackage != null) {
-            ApplicationInfo ai = null;
-            try {
-                ai = getContext().getPackageManager()
-                        .getApplicationInfo(callingPackage, 0);
-            } catch (PackageManager.NameNotFoundException ignored) {
-            }
-            if (ai != null) {
-                return ai.targetSdkVersion;
-            }
-        }
-        return Build.VERSION_CODES.CUR_DEVELOPMENT;
+        final boolean isLegacyMode = mAppOpsManager.checkOp(AppOpsManager.OP_LEGACY_STORAGE,
+                Binder.getCallingUid(), getCallingPackage()) == AppOpsManager.MODE_ALLOWED;
+        Helpers.checkDestinationFilePathRestrictions(file, getCallingPackage(), getContext(),
+                mAppOpsManager, getCallingAttributionTag(), isLegacyMode,
+                /* allowDownloadsDirOnly */ true);
     }
 
     /**
diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java
index 772c0b9..574b222 100644
--- a/src/com/android/providers/downloads/Helpers.java
+++ b/src/com/android/providers/downloads/Helpers.java
@@ -34,6 +34,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.AppOpsManager;
 import android.app.job.JobInfo;
 import android.app.job.JobScheduler;
 import android.content.ComponentName;
@@ -41,8 +42,10 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -84,6 +87,9 @@
     private static final Pattern PATTERN_ANDROID_DIRS =
             Pattern.compile("(?i)^/storage/[^/]+(?:/[0-9]+)?/Android/(?:data|obb|media)/.+");
 
+    private static final Pattern PATTERN_ANDROID_PRIVATE_DIRS =
+            Pattern.compile("(?i)^/storage/[^/]+(?:/[0-9]+)?/Android/(data|obb)/.+");
+
     private static final Pattern PATTERN_PUBLIC_DIRS =
             Pattern.compile("(?i)^/storage/[^/]+(?:/[0-9]+)?/([^/]+)/.+");
 
@@ -530,8 +536,7 @@
      * directories that are always writable to apps, regardless of storage
      * permission.
      */
-    static boolean isFilenameValidInExternalPackage(Context context, File file,
-            String packageName) {
+    static boolean isFilenameValidInExternalPackage(File file, String packageName) {
         try {
             if (containsCanonical(buildExternalStorageAppDataDirs(packageName), file) ||
                     containsCanonical(buildExternalStorageAppObbDirs(packageName), file) ||
@@ -539,7 +544,7 @@
                 return true;
             }
         } catch (IOException e) {
-            Log.w(TAG, "Failed to resolve canonical path: " + e);
+            Log.w(TAG, "Failed to resolve canonical path: " + file.getAbsolutePath(), e);
             return false;
         }
 
@@ -552,13 +557,77 @@
                 return true;
             }
         } catch (IOException e) {
-            Log.w(TAG, "Failed to resolve canonical path: " + e);
+            Log.w(TAG, "Failed to resolve canonical path: " + file.getAbsolutePath(), e);
             return false;
         }
 
         return false;
     }
 
+    /**
+     * Check if given file exists in one of the private package-specific external storage
+     * directories.
+     */
+    static boolean isFileInPrivateExternalAndroidDirs(File file) {
+        try {
+            return PATTERN_ANDROID_PRIVATE_DIRS.matcher(file.getCanonicalPath()).matches();
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to resolve canonical path: " + file.getAbsolutePath(), e);
+        }
+
+        return false;
+    }
+
+    /**
+     * Checks destination file path restrictions adhering to App privacy restrictions
+     *
+     * Note: This method is extracted to a static method for better test coverage.
+     */
+    @VisibleForTesting
+    static void checkDestinationFilePathRestrictions(File file, String callingPackage,
+            Context context, AppOpsManager appOpsManager, String callingAttributionTag,
+            boolean isLegacyMode, boolean allowDownloadsDirOnly) {
+        boolean isFileNameValid = allowDownloadsDirOnly ? isFilenameValidInPublicDownloadsDir(file)
+                : isFilenameValidInKnownPublicDir(file.getAbsolutePath());
+        if (isFilenameValidInExternalPackage(file, callingPackage) || isFileNameValid) {
+            // No permissions required for paths belonging to calling package or
+            // public downloads dir.
+            return;
+        } else if (isFilenameValidInExternalObbDir(file) &&
+                isCallingAppInstaller(context, appOpsManager, callingPackage)) {
+            // Installers are allowed to download in OBB dirs, even outside their own package
+            return;
+        } else if (isFileInPrivateExternalAndroidDirs(file)) {
+            // Positive cases of writing to external Android dirs is covered in the if blocks above.
+            // If the caller made it this far, then it cannot write to this path as it is restricted
+            // from writing to other app's external Android dirs.
+            throw new SecurityException("Unsupported path " + file);
+        } else if (isLegacyMode && isFilenameValidInExternal(context, file)) {
+            // Otherwise we require write permission
+            context.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
+                    "No permission to write to " + file);
+
+            if (appOpsManager.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE,
+                    callingPackage, Binder.getCallingUid(), callingAttributionTag, null)
+                    != AppOpsManager.MODE_ALLOWED) {
+                throw new SecurityException("No permission to write to " + file);
+            }
+        } else {
+            throw new SecurityException("Unsupported path " + file);
+        }
+    }
+
+    private static boolean isCallingAppInstaller(Context context, AppOpsManager appOpsManager,
+            String callingPackage) {
+        return (appOpsManager.noteOp(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
+                Binder.getCallingUid(), callingPackage, null, "obb_download")
+                == AppOpsManager.MODE_ALLOWED)
+                || (context.checkCallingOrSelfPermission(
+                android.Manifest.permission.REQUEST_INSTALL_PACKAGES)
+                == PackageManager.PERMISSION_GRANTED);
+    }
+
     static boolean isFilenameValidInPublicDownloadsDir(File file) {
         try {
             if (containsCanonical(buildExternalStoragePublicDirs(
@@ -566,7 +635,7 @@
                 return true;
             }
         } catch (IOException e) {
-            Log.w(TAG, "Failed to resolve canonical path: " + e);
+            Log.w(TAG, "Failed to resolve canonical path: " + file.getAbsolutePath(), e);
             return false;
         }
 
@@ -608,7 +677,7 @@
                 }
             }
         } catch (IOException e) {
-            Log.w(TAG, "Failed to resolve canonical path: " + e);
+            Log.w(TAG, "Failed to resolve canonical path: " + file.getAbsolutePath(), e);
             return false;
         }
 
@@ -786,13 +855,13 @@
             final ContentValues values = new ContentValues();
             values.putNull(Constants.UID);
             downloadProvider.update(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, values,
-                    Helpers.buildQueryWithIds(idsToOrphan), null);
+                    buildQueryWithIds(idsToOrphan), null);
         }
         if (idsToDelete.size() > 0) {
             Log.i(Constants.TAG, "Deleting downloads with ids "
                     + Arrays.toString(idsToDelete.toArray()) + " as owner package is removed");
             downloadProvider.delete(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
-                    Helpers.buildQueryWithIds(idsToDelete), null);
+                    buildQueryWithIds(idsToDelete), null);
         }
     }
 
diff --git a/tests/src/com/android/providers/downloads/HelpersTest.java b/tests/src/com/android/providers/downloads/HelpersTest.java
index 08c0b13..eb742d6 100644
--- a/tests/src/com/android/providers/downloads/HelpersTest.java
+++ b/tests/src/com/android/providers/downloads/HelpersTest.java
@@ -35,11 +35,13 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.AppOpsManager;
 import android.content.ContentProvider;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.database.MatrixCursor;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Environment;
 import android.os.Process;
 import android.provider.Downloads;
@@ -49,11 +51,8 @@
 import android.util.LongArray;
 import android.util.LongSparseArray;
 
-import libcore.io.IoUtils;
-
 import java.io.File;
 import java.util.Arrays;
-import java.util.function.BiConsumer;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -62,6 +61,7 @@
  */
 @SmallTest
 public class HelpersTest extends AndroidTestCase {
+    private static final String TAG = "DownloadManagerHelpersTest";
 
     private final static int TEST_UID1 = 11111;
     private final static int TEST_UID2 = 11112;
@@ -72,7 +72,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-
+        // This is necessary for mockito to work
+        System.setProperty("dexmaker.dexcache", mContext.getCacheDir().toString());
         mMockitoHelper.setUp(getClass());
     }
 
@@ -149,6 +150,363 @@
                 "/storage/AAAA-FFFF/Download/dir/bar.html"));
     }
 
+    public void testCheckDestinationFilePathRestrictions_noPermission() throws Exception {
+        // Downloading to our own private app directory should always be allowed, even for
+        // permission-less app
+        checkDestinationFilePathRestrictions_noPermission(
+                "/storage/emulated/0/Android/data/DownloadManagerHelpersTest/test",
+                /* isLegacyMode */ false);
+        checkDestinationFilePathRestrictions_noPermission(
+                "/storage/emulated/0/Android/data/DownloadManagerHelpersTest/test",
+                /* isLegacyMode */ true);
+        checkDestinationFilePathRestrictions_noPermission(
+                "/storage/emulated/0/Android/obb/DownloadManagerHelpersTest/test",
+                /* isLegacyMode */ false);
+        checkDestinationFilePathRestrictions_noPermission(
+                "/storage/emulated/0/Android/obb/DownloadManagerHelpersTest/test",
+                /* isLegacyMode */ true);
+        checkDestinationFilePathRestrictions_noPermission(
+                "/storage/emulated/0/Android/media/DownloadManagerHelpersTest/test",
+                /* isLegacyMode */ false);
+        checkDestinationFilePathRestrictions_noPermission(
+                "/storage/emulated/0/Android/media/DownloadManagerHelpersTest/test",
+                /* isLegacyMode */ true);
+
+        // All apps can write to Environment.STANDARD_DIRECTORIES
+        checkDestinationFilePathRestrictions_noPermission("/storage/emulated/0/Pictures/test",
+                /* isLegacyMode */ false);
+        checkDestinationFilePathRestrictions_noPermission("/storage/emulated/0/Download/test",
+                /* isLegacyMode */ false);
+        checkDestinationFilePathRestrictions_noPermission("/storage/emulated/0/Pictures/test",
+                /* isLegacyMode */ true);
+        checkDestinationFilePathRestrictions_noPermission("/storage/emulated/0/Download/test",
+                /* isLegacyMode */ true);
+
+        // Apps can never access other app's private directories (Android/data, Android/obb) paths
+        // (unless they are installers in which case they can access Android/obb paths)
+        try {
+            checkDestinationFilePathRestrictions_noPermission(
+                    "/storage/emulated/0/Android/data/foo/test", /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot access other app's private packages");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_noPermission(
+                    "/storage/emulated/0/Android/data/foo/test", /* isLegacyMode */ true);
+            fail("Expected SecurityException as caller cannot access other app's private packages"
+                    + " even in legacy mode");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_noPermission(
+                    "/storage/emulated/0/Android/obb/foo/test", /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot access other app's private packages");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_noPermission(
+                    "/storage/emulated/0/Android/obb/foo/test", /* isLegacyMode */ true);
+            fail("Expected SecurityException as caller cannot access other app's private packages"
+                    + " even in legacy mode");
+        } catch (SecurityException expected) {
+        }
+
+        // Non-legacy apps can never access Android/ or Android/media dirs for other packages.
+        try {
+            checkDestinationFilePathRestrictions_noPermission("/storage/emulated/0/Android/",
+                    /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot write to Android dir");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_noPermission(
+                    "/storage/emulated/0/Android/media/", /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot write to Android dir");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_noPermission(
+                    "/storage/emulated/0/Android/media/foo", /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot write to Android dir");
+        } catch (SecurityException expected) {
+        }
+
+        // Legacy apps require WRITE_EXTERNAL_STORAGE permission to access Android/ or Android/media
+        // dirs.
+        try {
+            checkDestinationFilePathRestrictions_noPermission("/storage/emulated/0/Android/",
+                    /* isLegacyMode */ true);
+            fail("Expected SecurityException as caller cannot write to Android/ as it does not"
+                    + " have WRITE_EXTERNAL_STORAGE permission");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_noPermission(
+                    "/storage/emulated/0/Android/media/", /* isLegacyMode */ true);
+            fail("Expected SecurityException as caller cannot write to Android/ as it does not"
+                    + " have WRITE_EXTERNAL_STORAGE permission");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_noPermission(
+                    "/storage/emulated/0/Android/media/foo", /* isLegacyMode */ true);
+            fail("Expected SecurityException as caller cannot write to Android/media as it does not"
+                    + " have WRITE_EXTERNAL_STORAGE permission");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testCheckDestinationFilePathRestrictions_installer() throws Exception {
+        // Downloading to other obb dirs should be allowed as installer
+        checkDestinationFilePathRestrictions_installer("/storage/emulated/0/Android/obb/foo/test",
+                /* isLegacyMode */ false);
+        checkDestinationFilePathRestrictions_installer("/storage/emulated/0/Android/obb/foo/test",
+                /* isLegacyMode */ true);
+
+        // Installer apps can not access other app's Android/data private dirs
+        try {
+            checkDestinationFilePathRestrictions_installer(
+                    "/storage/emulated/0/Android/data/foo/test", /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot access other app's private packages");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_installer(
+                    "/storage/emulated/0/Android/data/foo/test", /* isLegacyMode */ true);
+            fail("Expected SecurityException as caller cannot access other app's private packages"
+                    + " even in legacy mode");
+        } catch (SecurityException expected) {
+        }
+
+        // Non-legacy apps can never access Android/ or Android/media dirs for other packages.
+        try {
+            checkDestinationFilePathRestrictions_installer("/storage/emulated/0/Android/",
+                    /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot write to Android dir");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_installer("/storage/emulated/0/Android/media/",
+                    /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot write to Android dir");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_installer("/storage/emulated/0/Android/media/foo",
+                    /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot write to Android dir");
+        } catch (SecurityException expected) {
+        }
+
+        // Legacy apps require WRITE_EXTERNAL_STORAGE permission to access Android/ or Android/media
+        // dirs.
+        try {
+            checkDestinationFilePathRestrictions_installer("/storage/emulated/0/Android/",
+                    /* isLegacyMode */ true);
+            fail("Expected SecurityException as caller cannot write to Android/ as it does not"
+                    + " have WRITE_EXTERNAL_STORAGE permission");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_installer("/storage/emulated/0/Android/media/",
+                    /* isLegacyMode */ true);
+            fail("Expected SecurityException as caller cannot write to Android/ as it does not"
+                    + " have WRITE_EXTERNAL_STORAGE permission");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_installer("/storage/emulated/0/Android/media/foo",
+                    /* isLegacyMode */ true);
+            fail("Expected SecurityException as caller cannot write to Android/media as it does not"
+                    + " have WRITE_EXTERNAL_STORAGE permission");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testCheckDestinationFilePathRestrictions_WES() throws Exception {
+        // Apps with WRITE_EXTERNAL_STORAGE can not access other app's private dirs
+        // (Android/data and Android/obb paths)
+        try {
+            checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Android/data/foo/test",
+                    /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot access other app's private packages");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Android/data/foo/test",
+                    /* isLegacyMode */ true);
+            fail("Expected SecurityException as caller cannot access other app's private packages"
+                    + " even in legacy mode");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Android/obb/foo/test",
+                    /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot access other app's private packages");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Android/obb/foo/test",
+                    /* isLegacyMode */ true);
+            fail("Expected SecurityException as caller cannot access other app's private packages"
+                    + " even in legacy mode");
+        } catch (SecurityException expected) {
+        }
+
+        // Non-legacy apps can never access Android/ or Android/media dirs for other packages.
+        try {
+            checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Android/",
+                    /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot write to Android dir");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Android/media/",
+                    /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot write to Android dir");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Android/media/foo",
+                    /* isLegacyMode */ false);
+            fail("Expected SecurityException as caller cannot write to Android dir");
+        } catch (SecurityException expected) {
+        }
+
+        // Legacy apps with WRITE_EXTERNAL_STORAGE can access shared storage file path including
+        // Android/ and Android/media dirs
+        checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Pictures/test",
+                /* isLegacyMode */ true);
+        checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Download/test",
+                /* isLegacyMode */ true);
+        checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Android/",
+                /* isLegacyMode */ true);
+        checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Android/media/",
+                /* isLegacyMode */ true);
+        checkDestinationFilePathRestrictions_WES("/storage/emulated/0/Android/media/foo",
+                /* isLegacyMode */ true);
+    }
+
+    private void checkDestinationFilePathRestrictions_noPermission(String filePath,
+            boolean isLegacyMode) {
+        final Context mockContext = mock(Context.class);
+        when(mockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.REQUEST_INSTALL_PACKAGES))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+        when(mockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_EXTERNAL_STORAGE))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+        final String callingAttributionTag = "test";
+        final AppOpsManager mockAppOpsManager = mock(AppOpsManager.class);
+        final String callingPackage = TAG;
+        when(mockAppOpsManager.noteOp(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
+                Binder.getCallingUid(), callingPackage, null, "obb_download"))
+                .thenReturn(AppOpsManager.MODE_ERRORED);
+        when(mockAppOpsManager.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE,
+                callingPackage, Binder.getCallingUid(), callingAttributionTag, null))
+                .thenReturn(AppOpsManager.MODE_ERRORED);
+        File file = new File(filePath);
+
+        Helpers.checkDestinationFilePathRestrictions(file, callingPackage, mockContext,
+                mockAppOpsManager, callingAttributionTag, isLegacyMode,
+                /* allowDownloadsDirOnly */ false);
+    }
+
+    private void checkDestinationFilePathRestrictions_installer(String filePath,
+            boolean isLegacyMode) throws Exception {
+        final Context mockContext = mock(Context.class);
+        when(mockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.REQUEST_INSTALL_PACKAGES))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        when(mockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_EXTERNAL_STORAGE))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+
+        final String callingAttributionTag = "test";
+        final AppOpsManager mockAppOpsManager = mock(AppOpsManager.class);
+        final String callingPackage = TAG;
+        when(mockAppOpsManager.noteOp(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
+                Binder.getCallingUid(), callingPackage, null, "obb_download"))
+                .thenReturn(AppOpsManager.MODE_ALLOWED);
+        when(mockAppOpsManager.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE,
+                callingPackage, Binder.getCallingUid(), callingAttributionTag, null))
+                .thenReturn(AppOpsManager.MODE_ERRORED);
+        File file = new File(filePath);
+
+        Helpers.checkDestinationFilePathRestrictions(file, callingPackage, mockContext,
+                mockAppOpsManager, callingAttributionTag, isLegacyMode,
+                /* allowDownloadsDirOnly */ false);
+    }
+
+    private void checkDestinationFilePathRestrictions_WES(String filePath, boolean isLegacyMode)
+            throws Exception {
+        final Context mockContext = mock(Context.class);
+        when(mockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_EXTERNAL_STORAGE))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        when(mockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.REQUEST_INSTALL_PACKAGES))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+
+        final AppOpsManager mockAppOpsManager = mock(AppOpsManager.class);
+        final String callingAttributionTag = "test";
+        final String callingPackage = TAG;
+        when(mockAppOpsManager.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE,
+                callingPackage, Binder.getCallingUid(), callingAttributionTag, null))
+                .thenReturn(AppOpsManager.MODE_ALLOWED);
+        when(mockAppOpsManager.noteOp(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
+                Binder.getCallingUid(), callingPackage, null, "obb_download"))
+                .thenReturn(AppOpsManager.MODE_ERRORED);
+        File file = new File(filePath);
+
+        Helpers.checkDestinationFilePathRestrictions(file, callingPackage, mockContext,
+                mockAppOpsManager, callingAttributionTag, isLegacyMode,
+                /* allowDownloadsDirOnly */ false);
+    }
+
+    public void testIsFileInPrivateExternalAndroidDirs() throws Exception {
+        assertTrue(isFileInPrivateExternalAndroidDirs(
+                "/storage/emulated/0/Android/data/com.example"));
+        assertTrue(isFileInPrivateExternalAndroidDirs(
+                "/storage/emulated/0/Android/data/com.example/colors.txt"));
+        assertTrue(isFileInPrivateExternalAndroidDirs(
+                "/storage/emulated/0/Android/obb/com.example/file.mp4"));
+        assertTrue(isFileInPrivateExternalAndroidDirs(
+                "/storage/AAAA-FFFF/Android/obb/com.example/file.mp4"));
+
+        assertFalse(isFileInPrivateExternalAndroidDirs("/storage/emulated/0/Android/"));
+        assertFalse(isFileInPrivateExternalAndroidDirs("/storage/AAAA-FFFF/Android/"));
+        assertFalse(isFileInPrivateExternalAndroidDirs(
+                "/storage/emulated/0/Android/media/com.example/file.mp4"));
+        assertFalse(isFileInPrivateExternalAndroidDirs(
+                "/storage/AAAA-FFFF/Android/media/com.example/file.mp4"));
+        assertFalse(isFileInPrivateExternalAndroidDirs("/storage/emulated/0/Download/foo.pdf"));
+        assertFalse(isFileInPrivateExternalAndroidDirs(
+                "/storage/emulated/0/Download/dir/bar.html"));
+        assertFalse(isFileInPrivateExternalAndroidDirs("/storage/AAAA-FFFF/Download/dir/bar.html"));
+    }
+
+    private static boolean isFileInPrivateExternalAndroidDirs(String filePath) {
+        return Helpers.isFileInPrivateExternalAndroidDirs(new File(filePath));
+    }
+
     public void testIsFilenameValidinKnownPublicDir() throws Exception {
         assertTrue(Helpers.isFilenameValidInKnownPublicDir(
                 "/storage/emulated/0/Download/dir/file.txt"));
diff --git a/ui/res/values-as/strings.xml b/ui/res/values-as/strings.xml
index 5cfcb62..9784662 100644
--- a/ui/res/values-as/strings.xml
+++ b/ui/res/values-as/strings.xml
@@ -32,8 +32,8 @@
     <string name="dialog_title_queued_body" msgid="7481231558376227012">"ফাইল লানি পাতি থোৱা হৈছে"</string>
     <string name="dialog_queued_body" msgid="2374398802707010234">"এই ফাইলটো ভৱিষ্যতে ডাউনল’ড কৰিবলৈ লানি পাতি থোৱা হৈছে, গতিকে সদ্যহতে উপলব্ধ নহয়।"</string>
     <string name="dialog_file_missing_body" msgid="7896653198405160564">"ডাউনল’ড কৰা ফাইলটো বিচাৰি পোৱা নাই।"</string>
-    <string name="dialog_insufficient_space_on_external" msgid="1847671628253287114">"ডাউনল’ড সম্পূৰ্ণ কৰিব নোৱাৰি। বাহ্যিক ষ্ট’ৰেজত পৰ্যাপ্ত খালী ঠাই নাই।"</string>
-    <string name="dialog_insufficient_space_on_cache" msgid="703074452633529558">"ডাউনল’ড সম্পূৰ্ণ কৰিব নোৱাৰি। আভ্যন্তৰীণ ডাউনল’ড ষ্ট’ৰেজত পৰ্যাপ্ত খালী ঠাই নাই।"</string>
+    <string name="dialog_insufficient_space_on_external" msgid="1847671628253287114">"ডাউনল’ড সম্পূৰ্ণ কৰিবপৰা নোৱাৰি। বাহ্যিক সঞ্চয়াগাৰত পৰ্যাপ্ত খালী ঠাই নাই।"</string>
+    <string name="dialog_insufficient_space_on_cache" msgid="703074452633529558">"ডাউনল’ড সম্পূৰ্ণ কৰিব নোৱাৰি। আভ্যন্তৰীণ ডাউনল’ড সঞ্চয়াগাৰত পৰ্যাপ্ত খালী ঠাই নাই।"</string>
     <string name="dialog_cannot_resume" msgid="3101433441301206866">"ডাউনল\'ডত বিঘিনি জন্মোৱা হৈছিল আৰু ইয়াক পুনৰায় আৰম্ভ কৰিবপৰা নাযাব।"</string>
     <string name="dialog_file_already_exists" msgid="6849168874901909994">"ডাউনল’ড কৰিব নোৱাৰি। লক্ষ্যস্থানত ফাইলটো ইতিমধ্যে আছে।"</string>
     <string name="dialog_media_not_found" msgid="7376030905821161865">"ডাউনল’ড কৰিব নোৱাৰি। বাহ্যিক মিডিয়া উপলব্ধ নহয়।"</string>
@@ -44,8 +44,8 @@
     <string name="cancel_running_download" msgid="8586888328847044473">"বাতিল কৰক"</string>
     <string name="retry_download" msgid="6957856437473044831">"পুনৰ চেষ্টা কৰক"</string>
     <string name="start_now_download" msgid="1518778561803897734">"এতিয়া আৰম্ভ কৰক"</string>
-    <string name="deselect_all" msgid="4673983454506880405">"আটাইবোৰ বাছনি নোহোৱা কৰক"</string>
-    <string name="select_all" msgid="7469093306474000460">"আটাইবোৰ বাছনি কৰক"</string>
+    <string name="deselect_all" msgid="4673983454506880405">"সকলো বাছনি নোহোৱা কৰক"</string>
+    <string name="select_all" msgid="7469093306474000460">"সকলো বাছনি কৰক"</string>
     <string name="selected_count" msgid="5876842902167894010">"<xliff:g id="TOTAL">%2$d</xliff:g>ৰ ভিতৰত <xliff:g id="NUMBER">%1$d</xliff:g>টা বাছনি কৰা হ’ল"</string>
     <string name="download_share_dialog" msgid="5212760257251501969">"ইয়াৰ জৰিয়তে শ্বেয়াৰ কৰক"</string>
 </resources>
diff --git a/ui/res/values-b+sr+Latn/strings.xml b/ui/res/values-b+sr+Latn/strings.xml
index 2f83c97..7722211 100644
--- a/ui/res/values-b+sr+Latn/strings.xml
+++ b/ui/res/values-b+sr+Latn/strings.xml
@@ -43,7 +43,7 @@
     <string name="keep_queued_download" msgid="6905870466259272973">"Zadrži"</string>
     <string name="cancel_running_download" msgid="8586888328847044473">"Otkaži"</string>
     <string name="retry_download" msgid="6957856437473044831">"Probaj ponovo"</string>
-    <string name="start_now_download" msgid="1518778561803897734">"Započni"</string>
+    <string name="start_now_download" msgid="1518778561803897734">"Započni odmah"</string>
     <string name="deselect_all" msgid="4673983454506880405">"Opozovi sve izbore"</string>
     <string name="select_all" msgid="7469093306474000460">"Izaberi sve"</string>
     <string name="selected_count" msgid="5876842902167894010">"Izabrano je <xliff:g id="NUMBER">%1$d</xliff:g> od <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
diff --git a/ui/res/values-gu/strings.xml b/ui/res/values-gu/strings.xml
index 47391c1..1c1bcaf 100644
--- a/ui/res/values-gu/strings.xml
+++ b/ui/res/values-gu/strings.xml
@@ -38,9 +38,9 @@
     <string name="dialog_file_already_exists" msgid="6849168874901909994">"ડાઉનલોડ કરી શકાતું નથી. ગંતવ્ય ફાઇલ પહેલાંથી જ અસ્તિત્વમાં છે."</string>
     <string name="dialog_media_not_found" msgid="7376030905821161865">"ડાઉનલોડ કરી શકાતું નથી. બાહ્ય મીડિયા ઉપલબ્ધ નથી."</string>
     <string name="download_no_application_title" msgid="1209223807604231431">"ફાઇલ ખોલી શકાતી નથી"</string>
-    <string name="remove_download" msgid="244394809285977300">"કાઢી નાખો"</string>
+    <string name="remove_download" msgid="244394809285977300">"દૂર કરો"</string>
     <string name="delete_download" msgid="1861638125603383676">"કાઢી નાખો"</string>
-    <string name="keep_queued_download" msgid="6905870466259272973">"રાખો"</string>
+    <string name="keep_queued_download" msgid="6905870466259272973">"Keep"</string>
     <string name="cancel_running_download" msgid="8586888328847044473">"રદ કરો"</string>
     <string name="retry_download" msgid="6957856437473044831">"ફરી પ્રયાસ કરો"</string>
     <string name="start_now_download" msgid="1518778561803897734">"હવે શરૂ કરો"</string>
diff --git a/ui/res/values-ne/strings.xml b/ui/res/values-ne/strings.xml
index 21c01cd..0df4d5a 100644
--- a/ui/res/values-ne/strings.xml
+++ b/ui/res/values-ne/strings.xml
@@ -43,7 +43,7 @@
     <string name="keep_queued_download" msgid="6905870466259272973">"राख्नुहोस्"</string>
     <string name="cancel_running_download" msgid="8586888328847044473">"रद्द गर्नुहोस्"</string>
     <string name="retry_download" msgid="6957856437473044831">"पुनःप्रयास गर्नुहोस्"</string>
-    <string name="start_now_download" msgid="1518778561803897734">"अहिले न"</string>
+    <string name="start_now_download" msgid="1518778561803897734">"अहिले सुरु गर्नुहोस्"</string>
     <string name="deselect_all" msgid="4673983454506880405">"सबै अचयन गर्नुहोस्"</string>
     <string name="select_all" msgid="7469093306474000460">"सबै चयन गर्नुहोस्"</string>
     <string name="selected_count" msgid="5876842902167894010">"छानिएको <xliff:g id="TOTAL">%2$d</xliff:g> को <xliff:g id="NUMBER">%1$d</xliff:g> बाट"</string>
diff --git a/ui/res/values-or/strings.xml b/ui/res/values-or/strings.xml
index fc75304..62079ee 100644
--- a/ui/res/values-or/strings.xml
+++ b/ui/res/values-or/strings.xml
@@ -41,7 +41,7 @@
     <string name="remove_download" msgid="244394809285977300">"କାଢ଼ିଦିଅନ୍ତୁ"</string>
     <string name="delete_download" msgid="1861638125603383676">"ଡିଲିଟ୍‌ କରନ୍ତୁ"</string>
     <string name="keep_queued_download" msgid="6905870466259272973">"Keep"</string>
-    <string name="cancel_running_download" msgid="8586888328847044473">"ବାତିଲ୍ କରନ୍ତୁ"</string>
+    <string name="cancel_running_download" msgid="8586888328847044473">"ବାତିଲ୍‍"</string>
     <string name="retry_download" msgid="6957856437473044831">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
     <string name="start_now_download" msgid="1518778561803897734">"ବର୍ତ୍ତମାନ ଆରମ୍ଭ କରନ୍ତୁ"</string>
     <string name="deselect_all" msgid="4673983454506880405">"କିଛି ବି ଚୟନ କରନ୍ତୁ ନାହିଁ"</string>
diff --git a/ui/res/values-sq/strings.xml b/ui/res/values-sq/strings.xml
index ae07522..ea880b6 100644
--- a/ui/res/values-sq/strings.xml
+++ b/ui/res/values-sq/strings.xml
@@ -47,5 +47,5 @@
     <string name="deselect_all" msgid="4673983454506880405">"Hiq përzgjedhjen nga të gjitha"</string>
     <string name="select_all" msgid="7469093306474000460">"Përzgjidhi të gjitha"</string>
     <string name="selected_count" msgid="5876842902167894010">"U zgjodhën <xliff:g id="NUMBER">%1$d</xliff:g> nga gjithsej <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <string name="download_share_dialog" msgid="5212760257251501969">"Shpërndaj nëpërmjet"</string>
+    <string name="download_share_dialog" msgid="5212760257251501969">"Shpërnda nëpërmjet"</string>
 </resources>
diff --git a/ui/res/values-sr/strings.xml b/ui/res/values-sr/strings.xml
index 2892c79..801ebd2 100644
--- a/ui/res/values-sr/strings.xml
+++ b/ui/res/values-sr/strings.xml
@@ -43,7 +43,7 @@
     <string name="keep_queued_download" msgid="6905870466259272973">"Задржи"</string>
     <string name="cancel_running_download" msgid="8586888328847044473">"Откажи"</string>
     <string name="retry_download" msgid="6957856437473044831">"Пробај поново"</string>
-    <string name="start_now_download" msgid="1518778561803897734">"Започни"</string>
+    <string name="start_now_download" msgid="1518778561803897734">"Започни одмах"</string>
     <string name="deselect_all" msgid="4673983454506880405">"Опозови све изборе"</string>
     <string name="select_all" msgid="7469093306474000460">"Изабери све"</string>
     <string name="selected_count" msgid="5876842902167894010">"Изабрано је <xliff:g id="NUMBER">%1$d</xliff:g> од <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
diff --git a/ui/res/values-ta/strings.xml b/ui/res/values-ta/strings.xml
index 4e76714..b134fdf 100644
--- a/ui/res/values-ta/strings.xml
+++ b/ui/res/values-ta/strings.xml
@@ -28,16 +28,16 @@
     <string name="download_success" msgid="3895973294927323747">"முடிந்தது"</string>
     <string name="download_error" msgid="6652902885480887230">"தோல்வி"</string>
     <string name="dialog_title_not_available" msgid="7793272183758002416">"பதிவிறக்க முடியவில்லை"</string>
-    <string name="dialog_failed_body" msgid="4538779125597383173">"ஃபைலைப் பின்னர் பதிவிறக்க முயற்சிக்கவா அல்லது வரிசையிலிருந்து நீக்க விரும்புகிறீர்களா?"</string>
-    <string name="dialog_title_queued_body" msgid="7481231558376227012">"வரிசையில் உள்ள ஃபைல்"</string>
-    <string name="dialog_queued_body" msgid="2374398802707010234">"இந்த ஃபைல் எதிர்கால பதிவிறக்கத்திற்கு வரிசைப்படுத்தப்பட்டது, அதனால், இதுவரை இது கிடைக்கவில்லை."</string>
-    <string name="dialog_file_missing_body" msgid="7896653198405160564">"பதிவிறக்கிய ஃபைலைக் கண்டறிய முடியவில்லை."</string>
+    <string name="dialog_failed_body" msgid="4538779125597383173">"கோப்பைப் பின்னர் பதிவிறக்க முயற்சிக்கவா அல்லது வரிசையிலிருந்து நீக்க விரும்புகிறீர்களா?"</string>
+    <string name="dialog_title_queued_body" msgid="7481231558376227012">"வரிசையில் உள்ள கோப்பு"</string>
+    <string name="dialog_queued_body" msgid="2374398802707010234">"இந்தக் கோப்பு எதிர்கால பதிவிறக்கத்திற்கு வரிசைப்படுத்தப்பட்டது, அதனால், இதுவரை இது கிடைக்கவில்லை."</string>
+    <string name="dialog_file_missing_body" msgid="7896653198405160564">"பதிவிறக்கிய கோப்பைக் கண்டறிய முடியவில்லை."</string>
     <string name="dialog_insufficient_space_on_external" msgid="1847671628253287114">"பதிவிறக்கத்தை முடிக்க முடியவில்லை. வெளிப்புறச் சேமிப்பிடத்தில் போதுமான இடம் இல்லை."</string>
     <string name="dialog_insufficient_space_on_cache" msgid="703074452633529558">"பதிவிறக்கத்தை முடிக்க முடியவில்லை. அகப் பதிவிறக்க சேமிப்பிடத்தில் போதுமான இடம் இல்லை."</string>
     <string name="dialog_cannot_resume" msgid="3101433441301206866">"பதிவிறக்கம் குறுக்கிடப்பட்டது, மேலும் மீண்டும் தொடங்க முடியாது."</string>
-    <string name="dialog_file_already_exists" msgid="6849168874901909994">"பதிவிறக்க முடியவில்லை. இலக்கு ஃபைல் ஏற்கெனவே உள்ளது."</string>
+    <string name="dialog_file_already_exists" msgid="6849168874901909994">"பதிவிறக்க முடியவில்லை. இலக்குக் கோப்பு ஏற்கனவே உள்ளது."</string>
     <string name="dialog_media_not_found" msgid="7376030905821161865">"பதிவிறக்க முடியவில்லை. வெளிப்புற மீடியா கிடைக்கவில்லை."</string>
-    <string name="download_no_application_title" msgid="1209223807604231431">"ஃபைலைத் திறக்க முடியவில்லை"</string>
+    <string name="download_no_application_title" msgid="1209223807604231431">"கோப்பைத் திறக்க முடியவில்லை"</string>
     <string name="remove_download" msgid="244394809285977300">"அகற்று"</string>
     <string name="delete_download" msgid="1861638125603383676">"நீக்கு"</string>
     <string name="keep_queued_download" msgid="6905870466259272973">"வைத்திரு"</string>
diff --git a/ui/res/values-te/strings.xml b/ui/res/values-te/strings.xml
index 8fb2c86..b6afeb1 100644
--- a/ui/res/values-te/strings.xml
+++ b/ui/res/values-te/strings.xml
@@ -47,5 +47,5 @@
     <string name="deselect_all" msgid="4673983454506880405">"అన్నింటి ఎంపికను తీసివేయి"</string>
     <string name="select_all" msgid="7469093306474000460">"అన్నీ ఎంచుకోండి"</string>
     <string name="selected_count" msgid="5876842902167894010">"<xliff:g id="TOTAL">%2$d</xliff:g>లో <xliff:g id="NUMBER">%1$d</xliff:g> ఎంచుకోబడ్డాయి"</string>
-    <string name="download_share_dialog" msgid="5212760257251501969">"వీటి ద్వారా షేర్ చేయండి"</string>
+    <string name="download_share_dialog" msgid="5212760257251501969">"వీటి ద్వారా భాగస్వామ్యం చేయండి"</string>
 </resources>