summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml14
-rw-r--r--res/mipmap-hdpi/ic_launcher_download.pngbin9282 -> 4473 bytes
-rw-r--r--res/mipmap-mdpi/ic_launcher_download.pngbin5420 -> 2818 bytes
-rw-r--r--res/mipmap-xhdpi/ic_launcher_download.pngbin13962 -> 6351 bytes
-rw-r--r--res/mipmap-xxhdpi/ic_launcher_download.pngbin40279 -> 10361 bytes
-rw-r--r--res/mipmap-xxxhdpi/ic_launcher_download.pngbin35468 -> 14962 bytes
-rw-r--r--res/values-az-rAZ/strings.xml63
-rw-r--r--res/values-be/strings.xml58
-rw-r--r--res/values-bn-rBD/strings.xml63
-rw-r--r--res/values-cs/strings.xml2
-rw-r--r--res/values-et/strings.xml58
-rw-r--r--res/values-eu-rES/strings.xml63
-rw-r--r--res/values-gl-rES/strings.xml63
-rw-r--r--res/values-hi/strings.xml12
-rw-r--r--res/values-is-rIS/strings.xml63
-rw-r--r--res/values-kk-rKZ/strings.xml63
-rw-r--r--res/values-km-rKH/strings.xml2
-rw-r--r--res/values-kn-rIN/strings.xml63
-rw-r--r--res/values-ky-rKG/strings.xml63
-rw-r--r--res/values-mk-rMK/strings.xml63
-rw-r--r--res/values-ml-rIN/strings.xml63
-rw-r--r--res/values-mr-rIN/strings.xml63
-rw-r--r--res/values-ms/strings.xml58
-rw-r--r--res/values-my-rMM/strings.xml63
-rw-r--r--res/values-ne-rNP/strings.xml63
-rw-r--r--res/values-pt/strings.xml12
-rw-r--r--res/values-ru/strings.xml4
-rw-r--r--res/values-si-rLK/strings.xml63
-rw-r--r--res/values-sl/strings.xml14
-rw-r--r--res/values-sw/strings.xml2
-rw-r--r--res/values-ta-rIN/strings.xml63
-rw-r--r--res/values-te-rIN/strings.xml63
-rw-r--r--res/values-ur-rPK/strings.xml63
-rw-r--r--res/values-uz-rUZ/strings.xml63
-rw-r--r--res/values-zh-rHK/strings.xml2
-rw-r--r--src/com/android/providers/downloads/Constants.java20
-rw-r--r--src/com/android/providers/downloads/DownloadIdleService.java185
-rw-r--r--src/com/android/providers/downloads/DownloadInfo.java84
-rw-r--r--src/com/android/providers/downloads/DownloadNotifier.java2
-rw-r--r--src/com/android/providers/downloads/DownloadProvider.java152
-rw-r--r--src/com/android/providers/downloads/DownloadReceiver.java57
-rw-r--r--src/com/android/providers/downloads/DownloadService.java73
-rw-r--r--src/com/android/providers/downloads/DownloadStorageProvider.java2
-rw-r--r--src/com/android/providers/downloads/DownloadThread.java886
-rw-r--r--src/com/android/providers/downloads/Helpers.java218
-rw-r--r--src/com/android/providers/downloads/StopRequestException.java8
-rw-r--r--src/com/android/providers/downloads/StorageManager.java472
-rw-r--r--src/com/android/providers/downloads/StorageUtils.java271
-rw-r--r--tests/AndroidManifest.xml2
-rw-r--r--tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java36
-rw-r--r--tests/src/com/android/providers/downloads/AbstractPublicApiTest.java15
-rw-r--r--tests/src/com/android/providers/downloads/FakeSystemFacade.java4
-rw-r--r--tests/src/com/android/providers/downloads/HelpersTest.java68
-rw-r--r--tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java14
-rw-r--r--tests/src/com/android/providers/downloads/StorageTest.java247
-rw-r--r--tests/src/com/android/providers/downloads/ThreadingTest.java11
-rw-r--r--ui/res/anim/footer_appear.xml25
-rw-r--r--ui/res/anim/footer_disappear.xml25
-rw-r--r--ui/res/drawable-hdpi/ic_download_misc_file_type.pngbin2405 -> 0 bytes
-rw-r--r--ui/res/drawable-hdpi/ic_launcher_drm_file.pngbin4501 -> 0 bytes
-rw-r--r--ui/res/drawable-hdpi/ic_menu_desk_clock.pngbin2171 -> 0 bytes
-rw-r--r--ui/res/drawable-mdpi/ic_download_misc_file_type.pngbin1624 -> 0 bytes
-rw-r--r--ui/res/drawable-mdpi/ic_launcher_drm_file.pngbin2738 -> 0 bytes
-rw-r--r--ui/res/layout/download_list.xml71
-rw-r--r--ui/res/layout/download_list_item.xml85
-rw-r--r--ui/res/layout/list_group_header.xml23
-rw-r--r--ui/res/menu/download_menu.xml27
-rw-r--r--ui/res/mipmap-hdpi/ic_launcher_download.pngbin9282 -> 4473 bytes
-rw-r--r--ui/res/mipmap-mdpi/ic_launcher_download.pngbin5420 -> 2818 bytes
-rw-r--r--ui/res/mipmap-xhdpi/ic_launcher_download.pngbin13962 -> 6351 bytes
-rw-r--r--ui/res/mipmap-xxhdpi/ic_launcher_download.pngbin40279 -> 10361 bytes
-rw-r--r--ui/res/mipmap-xxxhdpi/ic_launcher_download.pngbin35468 -> 14962 bytes
-rw-r--r--ui/res/values-az-rAZ/strings.xml (renamed from ui/res/values-ms/strings.xml)62
-rw-r--r--ui/res/values-be/strings.xml50
-rw-r--r--ui/res/values-bn-rBD/strings.xml50
-rw-r--r--ui/res/values-eu-rES/strings.xml (renamed from ui/res/values-et/strings.xml)62
-rw-r--r--ui/res/values-gl-rES/strings.xml50
-rw-r--r--ui/res/values-hi/strings.xml10
-rw-r--r--ui/res/values-is-rIS/strings.xml50
-rw-r--r--ui/res/values-kk-rKZ/strings.xml50
-rw-r--r--ui/res/values-km-rKH/strings.xml2
-rw-r--r--ui/res/values-kn-rIN/strings.xml50
-rw-r--r--ui/res/values-ky-rKG/strings.xml50
-rw-r--r--ui/res/values-mk-rMK/strings.xml50
-rw-r--r--ui/res/values-ml-rIN/strings.xml50
-rw-r--r--ui/res/values-mr-rIN/strings.xml50
-rw-r--r--ui/res/values-my-rMM/strings.xml50
-rw-r--r--ui/res/values-ne-rNP/strings.xml50
-rw-r--r--ui/res/values-si-rLK/strings.xml50
-rw-r--r--ui/res/values-ta-rIN/strings.xml50
-rw-r--r--ui/res/values-te-rIN/strings.xml50
-rw-r--r--ui/res/values-ur-rPK/strings.xml50
-rw-r--r--ui/res/values-uz-rUZ/strings.xml50
-rw-r--r--ui/res/values/dimen.xml19
-rw-r--r--ui/src/com/android/providers/downloads/ui/DateSortedDownloadAdapter.java60
-rw-r--r--ui/src/com/android/providers/downloads/ui/DateSortedExpandableListAdapter.java354
-rw-r--r--ui/src/com/android/providers/downloads/ui/DownloadAdapter.java215
-rw-r--r--ui/src/com/android/providers/downloads/ui/DownloadItem.java156
-rw-r--r--ui/src/com/android/providers/downloads/ui/DownloadList.java765
99 files changed, 3642 insertions, 3368 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index cee7cbc9..579f8dde 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -54,6 +54,7 @@
<!-- TODO: replace with READ_NETWORK_POLICY permission when it exists -->
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING" />
+ <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application android:process="android.process.media"
@@ -92,12 +93,21 @@
</intent-filter>
</provider>
- <service android:name=".DownloadService"
- android:permission="android.permission.ACCESS_DOWNLOAD_MANAGER" />
+ <service
+ android:name=".DownloadService"
+ android:permission="android.permission.ACCESS_DOWNLOAD_MANAGER" />
+
+ <service
+ android:name="com.android.providers.downloads.DownloadIdleService"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE">
+ </service>
+
<receiver android:name=".DownloadReceiver" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
+ <action android:name="android.intent.action.UID_REMOVED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
diff --git a/res/mipmap-hdpi/ic_launcher_download.png b/res/mipmap-hdpi/ic_launcher_download.png
index 2450cfbb..f958bbd3 100644
--- a/res/mipmap-hdpi/ic_launcher_download.png
+++ b/res/mipmap-hdpi/ic_launcher_download.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher_download.png b/res/mipmap-mdpi/ic_launcher_download.png
index 7b56ada3..f2e93766 100644
--- a/res/mipmap-mdpi/ic_launcher_download.png
+++ b/res/mipmap-mdpi/ic_launcher_download.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher_download.png b/res/mipmap-xhdpi/ic_launcher_download.png
index 775004f2..4dc53363 100644
--- a/res/mipmap-xhdpi/ic_launcher_download.png
+++ b/res/mipmap-xhdpi/ic_launcher_download.png
Binary files differ
diff --git a/res/mipmap-xxhdpi/ic_launcher_download.png b/res/mipmap-xxhdpi/ic_launcher_download.png
index ed8c7827..87162909 100644
--- a/res/mipmap-xxhdpi/ic_launcher_download.png
+++ b/res/mipmap-xxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/res/mipmap-xxxhdpi/ic_launcher_download.png b/res/mipmap-xxxhdpi/ic_launcher_download.png
index 2dbe0f2d..f5be2199 100644
--- a/res/mipmap-xxxhdpi/ic_launcher_download.png
+++ b/res/mipmap-xxxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
new file mode 100644
index 00000000..28af64d4
--- /dev/null
+++ b/res/values-az-rAZ/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"Endirmə İdarəçisi"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"Endirmə idarəçisinə daxil ol."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"Tətbiqə faylları endirmək üçün endirmə idarçisinə daxil olmağa imkan verir. Zərərli tətbiqlər bundan endirmələri pozmaq və özəl məlumatlara daxil olmaq üçün istifadə edə bilər."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Ətraflı endirmə idarəçisi funksiyaları."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Tətbiqə endirmə idarəçisinin inkişaf etmiş funksiyalarına daxil olmaq üçün imkan verir. Zərərli tətbiqlər bunu endirmələri pozmaq və özəl məlumatlara daxil olmaq üçün istifadə edə bilər."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Endirmə məlumatı göndər."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Tətbiqə tamamlanmış endirmələr haqqında məlumat göndərməyə imkan verir. Zərərli tətbiqlər bunu faylları endirən tətbiqləri çaşdırmaq üçün istifadə edə bilər."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB yaddaşına bütün endirmələrə baxın"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD karta endirmələrə baxın"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Tətbiqə hansı tətbiqin endirdiyindən asılı olmayaraq yaddaş kartındakı endirilən faylları görmə imkanı verir."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Endirmə keşində ehtiyat yer mühafizə et"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Tətbiqə endirmə idarəçisinə daha çox yer lazım olanda başqa faylları endirmə vasitəsi ilə avtomatik olarak silinməyən keşlər endirməsinə imkan verir."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"xəbərdarlıq etmədən faylları endir"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Bu tətbiq istifadəçiyə hər hansı bir məlumat göstərmədən faylları endirmə idarəçisi vasitəsi ilə endirmək imkanı verir."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Sistemdəki bütün endirilənlərə gir"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Tətbiqə başqa bir tətbiq vasitəsi ilə başladılan endirmələri göstərmək və dəyişdirmək imkanı verir."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;Başlıqsız&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"Endirmə tamamlandı."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"Endirmə uğursuz oldu."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"Endirmə həcmi Wi-Fi tələb edir."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"Arxa fonda dayandırıldı."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"Endirmə operator şəbəkə üçün çox böyükdür"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"Bu <xliff:g id="SIZE">%s </xliff:g> endirməni başa çatdırmaq üçün Wi-Fi istifadə etməlisiniz. \n \n Növbəti dəfə WiFi şəbəkəsinə qoşulanda bu endirməni başlatmaq üçün <xliff:g id="QUEUE_TEXT">%s </xliff:g> toxunun."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"Daha sonra endirmək üçün növbəyə salmaq istəyirsiniz?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"Bu <xliff:g id="SIZE">%s </xliff:g> böyüklükdəki faylı endirməyə başlamaq batareyanızı azalda bilər/və ya mobil data əlaqənizin böyük bir hissəsinin işlədilməsinə gətirib çixara bilər, bu da sizin data planınınızdan asılı olaraq mobil operatorunuz tərəfindən xərcə səbəb ola bilər. \n \n Növbəti dəfə WiFi şəbəkəsinə qoşulanda bu endirməyə başlamaq üçün <xliff:g id="QUEUE_TEXT">%s</xliff:g> toxunun."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"Növbəyə sal"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"Ləğv et"</string>
+ <string name="button_start_now" msgid="792123674007840864">"İndi başlat"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"1 fayl endirilir"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> fayl endirilir"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 fayl gözləyir"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> fayl gözləyir"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> qalır"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"Fayl açılmır"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"Endirmələr"</string>
+ <string name="download_queued" msgid="3302638231377947451">"Növbəyə salınıb"</string>
+ <string name="download_running" msgid="3925050393361158266">"Davam edir"</string>
+ <string name="download_error" msgid="5144180777324573236">"Uğursuz"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"İrəliləyir, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
deleted file mode 100644
index f4b59a86..00000000
--- a/res/values-be/strings.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="3658948994665187911">"Менеджэр спампоўвання"</string>
- <string name="permlab_downloadManager" msgid="7779544811202855500">"Доступ да менеджэра спампоўванняў."</string>
- <string name="permdesc_downloadManager" msgid="4237406545998908947">"Дазваляе прыкладанню атрымлiваць доступ да менеджэра спампавання i выкарыстоўваць яго для спампавання файлаў. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта, каб сарваць загрузку і закрыць доступ да прыватнай інфармацыі."</string>
- <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Пашыраныя функцыі менеджэра спампоўванняў."</string>
- <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Дазваляе прыкладанню атрымлiваць доступ да пашыраных функцый менеджэра спампавання. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта, каб сарваць загрузку і закрыць доступ да прыватнай інфармацыі."</string>
- <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Адпраўляць апавяшчэнні аб спампоўцы."</string>
- <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Дазваляе прыкладанню адпраўляць апавяшчэннi аб завершаных спампаваннях. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта, каб негатыўна паўсплываць на іншыя прыкладаннi для спампавання файлаў."</string>
- <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"Прагледзець усе спампоўкі на USB-назапашвальнiк"</string>
- <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"Прагледзець усе спампоўкі на SD-карце"</string>
- <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Дазваляе прыкладанюе бачыць усе спампоўкі на SD-карце, незалежна ад таго, праз якое прыкладанне яны былi спампаваны."</string>
- <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Зарэзерваваць месца ў кэшы спампоўкі"</string>
- <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Дазваляе прыкладанню спампоўваць файлы ў кэш-памяць, якую нельга ачысцiць аўтаматычна, калі менеджэру спампавання спатрэбіцца больш месца на дыске."</string>
- <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"спампоўваць файлы без апавяшчэння"</string>
- <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Дазваляе прыкладанню спампоўваць файлы праз менеджэр спампавання, не кажучы пра гэта карыстальнiку."</string>
- <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Доступ да ўсіх сістэмных спамповак"</string>
- <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Дазваляе прыкладанню праглядаць і змяняць усе спампоўкi, пачатыя любым сiстэмным прыкладаннем."</string>
- <string name="download_unknown_title" msgid="7015124071247271585">"&lt;Без назвы&gt;"</string>
- <string name="notification_download_complete" msgid="5443563299253103667">"Спампаванне завершана"</string>
- <string name="notification_download_failed" msgid="8612136111952014978">"Не атрымалася спампаваць."</string>
- <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"Для спампавання патрабуецца сетка Wi-Fi"</string>
- <string name="notification_paused_in_background" msgid="4328508073283591772">"Прыпынена ў фон. рэжыме"</string>
- <string name="wifi_required_title" msgid="1995971416871498179">"Спампоўка занадта вялікая для сеткі аператара"</string>
- <string name="wifi_required_body" msgid="3067694630143784449">"Каб завяршыць спампаванне файла памерам <xliff:g id="SIZE">%s </xliff:g>, патрабуецца падлучэнне да сеткi Wi-Fi. \n\nДакранiцеся да надпiсу <xliff:g id="QUEUE_TEXT">%s </xliff:g>, каб пачаць спампаванне, калi будзе даступна сетка Wi-Fi."</string>
- <string name="wifi_recommended_title" msgid="7441589306734687400">"Стаць у чаргу, каб спампаваць пазней?"</string>
- <string name="wifi_recommended_body" msgid="1314735166699936073">"Спампаванне файла памерам <xliff:g id="SIZE">%s </xliff:g> можа скараціць тэрмін службы акумулятара або прывесці да празмернага выкарыстання мабільнага падлучэння дадзеных, за што вашым мабiльным аператарам можа спаганяцца дадатковая плата.\n\nДакранiцеся да надпiсу <xliff:g id="QUEUE_TEXT">%s</xliff:g>, каб пачаць спампаванне, калi з\'явiцца падлучэнне да сеткi Wi-Fi."</string>
- <string name="button_queue_for_wifi" msgid="422576726189179221">"Чарга"</string>
- <string name="button_cancel_download" msgid="2430166148737975604">"Адмена"</string>
- <string name="button_start_now" msgid="792123674007840864">"Пачаць прама цяпер"</string>
- <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <plurals name="notif_summary_active">
- <item quantity="one" msgid="8475775855911967027">"Спампоўваецца 1 файл"</item>
- <item quantity="other" msgid="9087228371320573153">"Спампоўваюцца файлы: <xliff:g id="NUMBER">%d</xliff:g>"</item>
- </plurals>
- <plurals name="notif_summary_waiting">
- <item quantity="one" msgid="5537481763963544278">"1 файл чакае"</item>
- <item quantity="other" msgid="549229034166062887">"Файлы чакаюць: <xliff:g id="NUMBER">%d</xliff:g>"</item>
- </plurals>
- <string name="download_remaining" msgid="3139295890887972718">"Засталося <xliff:g id="DURATION">%s</xliff:g>"</string>
- <string name="download_no_application_title" msgid="7935659741162801699">"Не атрымлiваецца адкрыць файл"</string>
-</resources>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
new file mode 100644
index 00000000..93ba42ed
--- /dev/null
+++ b/res/values-bn-rBD/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"ডাউনলোড ম্যানেজার"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"ডাউনলোড ম্যানেজার অ্যাক্সেস করুন।"</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"অ্যাপ্লিকেশানটিকে ডাউনলোড ম্যানেজার অ্যাক্সেস করার এবং এটি ব্যবহার করে ফাইল ডাউনলোড করার অনুমতি দেয়। ক্ষতিকারক অ্যাপ্লিকেশানগুলি ডাউনলোড ব্যাহত এবং ব্যক্তিগত তথ্য অ্যাক্সেস করার জন্য এটি ব্যবহার করতে পারে।"</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"উন্নত ডাউনলোড ম্যানেজার কার্যকারিতা।"</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"অ্যাপ্লিকেশানটিকে ডাউনলোড ম্যানেজারের উন্নত কার্যকারিতাগুলি অ্যাক্সেস করার অনুমতি দেয়। ক্ষতিকারক অ্যাপ্লিকেশানগুলি ডাউনলোড ব্যাহত এবং ব্যক্তিগত তথ্য অ্যাক্সেস করার জন্য এটি ব্যবহার করতে পারে।"</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"ডাউনলোডের বিজ্ঞপ্তিগুলি পাঠান।"</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"অ্যাপ্লিকেশানটিকে সম্পূর্ণ হওয়া ডাউনলোডগুলির জন্য বিজ্ঞপ্তি পাঠানোর অনুমতি দেয়। অন্য যে অ্যাপ্লিকেশানগুলি ফাইল ডাউনলোড করে সেগুলিকে বিভ্রান্ত করতে ক্ষতিকারক অ্যাপ্লিকেশানগুলি এটি ব্যবহার করতে পারে।"</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB সঞ্চয়স্থানের সব ডাউনলোড দেখুন"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD কার্ডের সব ডাউনলোড দেখুন"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"অ্যাপ্লিকেশানটিকে কোন অ্যাপ্লিকেশন কি ডাউনলোড করেছে তা নির্বেশেষে SD কার্ডে সমস্ত ডাউনলোড দেখতে অনুমতি দেয়।"</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"ডাউনলোড ক্যাশেতে জায়গা সংরক্ষিত রাখুন"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"অ্যাপ্লিকেশানটিকে ডাউনলোড ক্যাশে থেকে ফাইলগুলি ডাউনলোড করার অনুমতি দেয়, যখন ডাউনলোড ম্যানেজার আরো বেশি জায়গা চাইবে তখন ডাউনলোড ক্যাশে স্বয়ংক্রিয়ভাবে মোছা যাবে না।"</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"বিজ্ঞপ্তি ছাড়াই ফাইল ডাউনলোড করুন"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"ব্যবহারকারীকে কোনো বিজ্ঞপ্তি না প্রদর্শন করা ছাড়াই অ্যাপ্লিকেশানটিকে ডাউনলোড ম্যানেজারের মাধ্যমে ফাইল ডাউনলোড করার অনুমতি দেয়।"</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"সব সিস্টেম ডাউনলোড অ্যাক্সেস করুন"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"সিস্টেমে যে কোনো অ্যাপ্লিকেশান দ্বারা সূচিত সকল ডাউনলোড প্রদর্শন ও পরিবর্তনের জন্য অ্যাপ্লিকেশানটিকে অনুমতি দেয়।"</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;শিরোনামহীন&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"ডাউনলোড সম্পূর্ণ হয়েছে।"</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"ডাউনলোড অসফল।"</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"ডাউনলোড বড় হওয়ায় Wi-Fi লাগবে।"</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"পশ্চাদপটে বিরাম দেওয়া আছে।"</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"অপারেটর নেটওয়ার্কের জন্য ডাউনলোড অত্যন্ত বড়"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"এই <xliff:g id="SIZE">%s </xliff:g> ডাউনলোড সম্পূর্ণ করতে আপনাকে অবশ্যই Wi-Fi ব্যবহার করতে হবে।\n\nআপনি পরবর্তীতে যখন Wi-Fi নেটওয়ার্কে সংযুক্ত হবেন তখন এই ডাউনলোড শুরু করতে <xliff:g id="QUEUE_TEXT">%s </xliff:g> স্পর্শ করুন।"</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"পরে ডাউনলোডের জন্য সারিবদ্ধ করবেন?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"এই <xliff:g id="SIZE">%s </xliff:g> ডাউনলোড শুরু করলে তা আপনার ব্যাটারি জীবন এবং/অথবা ফলস্বরুপ মাত্রাতিরিক্ত আপনার মোবাইল ডেটা সংযোগ ব্যবহার হতে পারে, যার ফলে আপনার মোবাইল অপারেটর আপনার ডেটা প্ল্যানের উপর নির্ভর করে চার্জ করতে পারে।\n\n আপনার পরবর্তীতে যখন Wi-Fi নেটওয়ার্কে সংযুক্ত হবেন তখন এই ডাউনলোড শুরু করতে <xliff:g id="QUEUE_TEXT">%s</xliff:g> স্পর্শ করুন।"</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"সারি"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"বাতিল করুন"</string>
+ <string name="button_start_now" msgid="792123674007840864">"এখন শুরু করুন"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"১টি ফাইল ডাউনলোড হচ্ছে"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g>টি ফাইল ডাউনলোড হচ্ছে"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"১টি ফাইল অপেক্ষারত"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g>টি ফাইল অপেক্ষারত"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> বাকি"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"ফাইল খোলা যাবে না"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"ডাউনলোডগুলি"</string>
+ <string name="download_queued" msgid="3302638231377947451">"সারিবদ্ধ"</string>
+ <string name="download_running" msgid="3925050393361158266">"প্রগতিতে রয়েছে"</string>
+ <string name="download_error" msgid="5144180777324573236">"অসফল"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g> প্রগতিতে রয়েছে"</string>
+</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index b8c37574..4d358ce0 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -55,7 +55,7 @@
</plurals>
<string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> do stažení"</string>
<string name="download_no_application_title" msgid="7935659741162801699">"Soubor nelze otevřít"</string>
- <string name="root_downloads" msgid="4098414876292351487">"Ke stažení"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"Stahování"</string>
<string name="download_queued" msgid="3302638231377947451">"Ve frontě"</string>
<string name="download_running" msgid="3925050393361158266">"Probíhá"</string>
<string name="download_error" msgid="5144180777324573236">"Neúspěšné"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
deleted file mode 100644
index a3503c2f..00000000
--- a/res/values-et/strings.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="3658948994665187911">"Allalaadimishaldur"</string>
- <string name="permlab_downloadManager" msgid="7779544811202855500">"Juurdepääs allalaadimishaldurile."</string>
- <string name="permdesc_downloadManager" msgid="4237406545998908947">"Võimaldab rakendusel pääseda allalaadimishalduri juurde ja selle abil faile alla laadida. Pahatahtlikud rakendused saavad selle abil allalaadimisi takistada ja privaatsete andmete juurde pääseda."</string>
- <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Allalaadimishalduri täpsemad funktsioonid."</string>
- <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Võimaldab rakendusel pääseda allalaadimishalduri täpsemate funktsioonide juurde. Pahatahtlikud rakendused võivad selle abil allalaadimisi takistada ja privaatsete andmete juurde pääseda."</string>
- <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Allalaadimisteatiste saatmine."</string>
- <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Võimaldab rakendusel saata märguandeid lõpulejõudnud allalaadimiste kohta. Pahatahtlikud rakendused võivad selle abil häirida teisi rakendusi, mis faile alla laadivad."</string>
- <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB allalaadimiste vaat."</string>
- <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"Vaadake kõiki allalaadimisi SD-kaardile"</string>
- <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Võimaldab rakendusel näha kõiki SD-kaardile salvestatud allalaadimisi sõltumata rakendusest, mis need alla laadis."</string>
- <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Reserveeri allalaadimiste vahemälus ruumi"</string>
- <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Võimaldab rakendusel laadida faile allalaadimise vahemällu, mida allalaadimishaldur ei saa ruumi vabastamiseks automaatselt kustutada."</string>
- <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"failide teatamata allalaadimine"</string>
- <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Võimaldab rakendusel allalaadimishalduri kaudu faile alla laadida kasutajale märguannet kuvamata."</string>
- <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Juurdepääs kõigile süsteemi allalaadimistele"</string>
- <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Võimaldab rakendusel vaadata ja muuta kõiki allalaadimisi, mille algatas süsteemis olev mis tahes rakendus."</string>
- <string name="download_unknown_title" msgid="7015124071247271585">"&lt;Pealkirjata&gt;"</string>
- <string name="notification_download_complete" msgid="5443563299253103667">"Allalaadimine on lõpetatud."</string>
- <string name="notification_download_failed" msgid="8612136111952014978">"Allalaadimine ebaõnnestus."</string>
- <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"Allalaad. on vaja WiFit."</string>
- <string name="notification_paused_in_background" msgid="4328508073283591772">"Peatatud taustal."</string>
- <string name="wifi_required_title" msgid="1995971416871498179">"Allalaadimine operaatori võrgu jaoks on liiga suur"</string>
- <string name="wifi_required_body" msgid="3067694630143784449">"<xliff:g id="SIZE">%s </xliff:g> suuruse allalaadimise jaoks tuleb kasutada WiFi-võrku.\n\nPuudutage valikut <xliff:g id="QUEUE_TEXT">%s </xliff:g>, et alustada allalaadimisega järgmine kord, kui olete WiFi-võrguga ühenduses."</string>
- <string name="wifi_recommended_title" msgid="7441589306734687400">"Kas lisada järjekorda hilisemaks allalaadimiseks?"</string>
- <string name="wifi_recommended_body" msgid="1314735166699936073">"<xliff:g id="SIZE">%s </xliff:g> allalaad. võib aku tööiga lüh. ja/või mob. andmemahtu koormata, mistõttu võib mob.operaator teilt sõltuvalt andmeplaanist tasu võtta.\n\n Puud. valikut <xliff:g id="QUEUE_TEXT">%s</xliff:g>, et laadida see alla siis, kui olete WiFi-võrgus."</string>
- <string name="button_queue_for_wifi" msgid="422576726189179221">"Järjekord"</string>
- <string name="button_cancel_download" msgid="2430166148737975604">"Tühista"</string>
- <string name="button_start_now" msgid="792123674007840864">"Alusta nüüd"</string>
- <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
- <plurals name="notif_summary_active">
- <item quantity="one" msgid="8475775855911967027">"1 faili allalaadimine"</item>
- <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> faili allalaadimine"</item>
- </plurals>
- <plurals name="notif_summary_waiting">
- <item quantity="one" msgid="5537481763963544278">"1 fail on ootel"</item>
- <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> faili on ootel"</item>
- </plurals>
- <string name="download_remaining" msgid="3139295890887972718">"Jäänud: <xliff:g id="DURATION">%s</xliff:g>"</string>
- <string name="download_no_application_title" msgid="7935659741162801699">"Faili ei saa avada"</string>
-</resources>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
new file mode 100644
index 00000000..c1f92ec9
--- /dev/null
+++ b/res/values-eu-rES/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"Deskargen kudeatzailea"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"Atzitu deskargen kudeatzailea."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"Deskargen kudeatzailea atzitzea eta fitxategiak deskargatzeko hori erabiltzea baimentzen die aplikazioei. Aplikazio maltzurrek deskargak eteteko eta informazio pribatua atzitzeko erabil dezakete hori."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Deskargen kudeatzailearen eginbide aurreratuak."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Deskargen kudeatzailearen eginbide aurreratuak atzitzea baimentzen die aplikazioei. Aplikazio maltzurrek deskargak eteteko eta informazio pribatua atzitzeko erabil dezakete hori."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Bidali deskargen jakinarazpenak."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Osatutako deskargei buruzko jakinarazpenak bidaltzea baimentzen die aplikazioei. Aplikazio maltzurrek fitxategiak deskargatzen dituzten beste aplikazioak nahasteko erabil dezakete hori."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"Ikusi USB memoriako deskargak"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"Ikusi SD txartelera egin diren deskarga guztiak"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"SD txartelera egin diren deskarga guztiak ikustea baimentzen die aplikazioei, zein aplikaziok deskargatu zituen kontuan hartu gabe."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Erreserbatu memoria deskarga-cachean"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Fitxategiak deskarga-cachera deskargatzea baimentzen die aplikazioei (ezin izango dira automatikoki ezabatu deskargen kudeatzaileak tokia behar duenean)."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"Deskargatu fitxategiak jakinarazi gabe"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Fitxategiak deskargen kudeatzailearen bidez baina erabiltzaileari jakinarazi gabe deskargatzea baimentzen die aplikazioei."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Atzitu sistemaren deskarga guztiak"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Aplikazioek sisteman hasitako deskarga guztiak ikustea eta aldatzea baimentzen die aplikazioei."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;Izengabea&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"Deskarga osatu da."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"Ezin izan da deskargatu."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"Wi-Fi konexioa behar da."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"Atzeko planoan pausatuta"</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"Deskarga handiegia da operadorearen sarerako"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"Wi-Fi konexioa erabili behar duzu <xliff:g id="SIZE">%s </xliff:g>-ko deskarga hau osatzeko. \n\nWi-Fi sare batera konektatzen zaren hurrengo aldian deskargari berrekiteko, ukitu <xliff:g id="QUEUE_TEXT">%s </xliff:g>."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"Ilaran ezarri geroago deskargatzeko?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"<xliff:g id="SIZE">%s </xliff:g>-ko deskarga hau hasten baduzu, baliteke bateriak gutxiago irautea edota datu-konexioa gehiegi erabiltzea eta, horren ondorioz, operadoreak gastu gehigarriak kobratzea, darabilzun datu-planaren arabera.\n\n Wi-Fi sare batera konektatzen zaren hurrengo aldian deskargari berrekiteko, ukitu <xliff:g id="QUEUE_TEXT">%s</xliff:g>."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"Ezarri ilaran"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"Utzi"</string>
+ <string name="button_start_now" msgid="792123674007840864">"Hasi"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="PERCENT">%%</xliff:g> <xliff:g id="NUMBER">%d</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"1 fitxategi deskargatzen"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> fitxategi deskargatzen"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 fitxategi zain"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> fitxategi zain"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"Falta den denbora: <xliff:g id="DURATION">%s</xliff:g>"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"Ezin da fitxategia ireki"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"Deskargak"</string>
+ <string name="download_queued" msgid="3302638231377947451">"Ilaran ezarri da"</string>
+ <string name="download_running" msgid="3925050393361158266">"Abian"</string>
+ <string name="download_error" msgid="5144180777324573236">"Ezin izan da deskargatu"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"Abian, <xliff:g id="PERCENT">%%</xliff:g> <xliff:g id="NUMBER">%d</xliff:g>"</string>
+</resources>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
new file mode 100644
index 00000000..d44fadb4
--- /dev/null
+++ b/res/values-gl-rES/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"Administrador de descargas"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"Acceso ao administrador de descargas"</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"Permite á aplicación acceder ao administrador de descargas e utilizalo para descargar ficheiros. As aplicacións maliciosas poden usar esta opción para interromper as descargas e acceder a información privada."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Funcións avanzadas do administrador de descargas"</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Permite á aplicación acceder ás funcións avanzadas do administrador de descargas. As aplicacións maliciosas poden usar esta opción para interromper as descargas e acceder a información privada."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Enviar notificacións de descarga."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Permite á aplicación enviar notificacións de descargas completadas. É posible que aplicacións maliciosas utilicen esta opción para confundir outras aplicacións que descargan ficheiros."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"Ver descargas a USB"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"Ver todas as descargas na tarxeta SD"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Permite á aplicación ver todas as descargas que se fixeron na tarxeta SD, independentemente da aplicación utilizada para descargalas."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Reservar espazo na caché de descargas"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Permite á aplicación descargar ficheiros na caché de descargas, que non se pode eliminar automaticamente cando o administrador de descargas precisa máis espazo."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"descargar ficheiros sen notificación"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Permite á aplicación descargar ficheiros a través do administrador de descargas sen que se mostre ningunha notificación ao usuario."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Acceso a todas as descargas do sistema"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Permite á aplicación ver e modificar todas as descargas iniciadas por calquera aplicación do sistema."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;Sen título&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"Descarga completa"</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"Descarga incorrecta"</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"A descarga precisa wifi."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"Pausada en segundo plano"</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"Descarga demasiado grande para a rede do operador"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"Debes utilizar a wifi para completar esta descarga de <xliff:g id="SIZE">%s </xliff:g>. \n\nToca <xliff:g id="QUEUE_TEXT">%s </xliff:g> para iniciar esta descarga a próxima vez que te conectes a unha rede wifi"</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"Colocar na cola para descargar máis tarde?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"Se descargas <xliff:g id="SIZE">%s </xliff:g>, podes quedar sen batería e o teu operador pódeche cobrar por un uso excesivo de datos.\n\n Toca <xliff:g id="QUEUE_TEXT">%s</xliff:g> para iniciar esta descarga a próxima vez que te conectes a unha rede wifi."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"Cola"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"Cancelar"</string>
+ <string name="button_start_now" msgid="792123674007840864">"Iniciar agora"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"Descargando 1 ficheiro"</item>
+ <item quantity="other" msgid="9087228371320573153">"Descargando <xliff:g id="NUMBER">%d</xliff:g> ficheiros"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 ficheiro en espera"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> ficheiros en espera"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"Tempo restante: <xliff:g id="DURATION">%s</xliff:g>"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"Non se pode abrir o ficheiro"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"Descargas"</string>
+ <string name="download_queued" msgid="3302638231377947451">"Na cola"</string>
+ <string name="download_running" msgid="3925050393361158266">"En curso"</string>
+ <string name="download_error" msgid="5144180777324573236">"Incorrecta"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"En curso, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 0a931553..11a3a8f6 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -22,27 +22,27 @@
<string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"उन्‍नत डाउनलोड प्रबंधक प्रकार्य."</string>
<string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"ऐप्स को डाउनलोड प्रबंधक के उन्नत फ़ंक्शन तक पहुंचने देता है. दुर्भावनापूर्ण ऐप्स इसका उपयोग डाउनलोड को बाधित करने और निजी जानकारी तक पहुंचने के लिए कर सकते हैं."</string>
<string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"डाउनलोड सूचनाएं भेजें."</string>
- <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"पूर्ण किए गए डाउनलोड के बारे में ऐप्स को सूचना भेजने देता है. दुर्भावनापूर्ण ऐप्स इसका उपयोग फ़ाइलों को डाउनलोड करने वाले अन्य ऐप्स को भ्रमित करने के लिए कर सकते हैं."</string>
- <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB संग्रहण के सभी डाउनलोड देखें"</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"पूर्ण किए गए डाउनलोड के बारे में ऐप्स को नोटिफिकेशन भेजने देता है. दुर्भावनापूर्ण ऐप्स इसका उपयोग फ़ाइलों को डाउनलोड करने वाले अन्य ऐप्स को भ्रमित करने के लिए कर सकते हैं."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB मेमोरी के सभी डाउनलोड देखें"</string>
<string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD कार्ड के लिए सभी डाउनलोड देखें"</string>
<string name="permdesc_seeAllExternal" msgid="1672759909065511233">"इस बात पर ध्यान दिए बिना कि किस ऐप्स ने उन्हें डाउनलोड किया है, ऐप्स को SD कार्ड पर किए गए सभी डाउनलोड देखने देता है."</string>
<string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"डाउनलोड कैश में स्थान सुरक्षित रखें"</string>
<string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"ऐप्स को डाउनलोड संचय पर फ़ाइलें डाउनलोड करने देता है, जिन्हें अपने आप तब हटाया नहीं जा सकता, जब डाउनलोड प्रबंधक को अधिक स्थान की आवश्‍यकता होती है."</string>
- <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"बिना सूचना के फ़ाइलें डाउनलोड करें"</string>
- <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"उपयोगकर्ता को कोई भी सूचना दिखाए बिना ऐप्स को डाउनलोड प्रबंधक द्वारा फ़ाइलें डाउनलोड करने देता है."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"बिना नोटिफिकेशन के फ़ाइलें डाउनलोड करें"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"उपयोगकर्ता को कोई भी नोटिफिकेशन दिखाए बिना ऐप्स को डाउनलोड प्रबंधक द्वारा फ़ाइलें डाउनलोड करने देता है."</string>
<string name="permlab_accessAllDownloads" msgid="2436240495424393717">"सभी सिस्‍टम डाउनलोड में पहुंच प्राप्त करें"</string>
<string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"ऐप्स को सिस्टम पर किसी भी ऐप्स द्वारा शुरू किए गए सभी डाउनलोड देखने और संशोधित करने देता है."</string>
<string name="download_unknown_title" msgid="7015124071247271585">"&lt;शीर्षक-रहित&gt;"</string>
<string name="notification_download_complete" msgid="5443563299253103667">"डाउनलोड पूर्ण."</string>
<string name="notification_download_failed" msgid="8612136111952014978">"डाउनलोड विफल."</string>
- <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"डाउनलोड आकार हेतु वाई-फ़ाई आवश्‍यक."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"डाउनलोड आकार के लिए वाई-फ़ाई आवश्‍यक."</string>
<string name="notification_paused_in_background" msgid="4328508073283591772">"पृष्ठभूमि में रोका गया."</string>
<string name="wifi_required_title" msgid="1995971416871498179">"ऑपरेटर नेटवर्क के लिए डाउनलोड बहुत बड़ा है"</string>
<string name="wifi_required_body" msgid="3067694630143784449">"इस <xliff:g id="SIZE">%s </xliff:g> डाउनलोड को पूर्ण करने के लिए आपको वाई-फ़ाई का उपयोग करना चाहिए.\n\nअगली बार जब आप वाई-फ़ाई नेटवर्क से कनेक्ट हों, तो इस डाउनलोड को शुरू करने के लिए <xliff:g id="QUEUE_TEXT">%s </xliff:g> को स्पर्श करें."</string>
<string name="wifi_recommended_title" msgid="7441589306734687400">"बाद में डाउनलोड करने के लिए कतार में रखें?"</string>
<string name="wifi_recommended_body" msgid="1314735166699936073">"इस <xliff:g id="SIZE">%s </xliff:g> के डाउनलोड को शुरू करना बैटरी का जीवनकाल कम कर सकता है और/या मोबाइल डेटा कनेक्शन का अधिक उपयोग हो सकता है, जिससे आपका मोबाइल डेटा ऑपरेटर आपसे आपकी डेटा योजना के आधार पर शुल्क ले सकता है.\n\n अगली बार जब आप वाई-फ़ाई नेटवर्क से कनेक्ट हों, तो यह डाउनलोड शुरू करने के लिए <xliff:g id="QUEUE_TEXT">%s</xliff:g> को स्पर्श करें."</string>
<string name="button_queue_for_wifi" msgid="422576726189179221">"कतार"</string>
- <string name="button_cancel_download" msgid="2430166148737975604">"रद्द करें"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"रहने दें"</string>
<string name="button_start_now" msgid="792123674007840864">"अब प्रारंभ करें"</string>
<string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<plurals name="notif_summary_active">
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
new file mode 100644
index 00000000..229d5bd4
--- /dev/null
+++ b/res/values-is-rIS/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"Niðurhalsstjórnun"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"Aðgangur að niðurhalsstjórnun."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"Leyfir forriti að fá aðgang að niðurhalsstjórnun og nota hana til að sækja skrár. Spilliforrit geta notað þetta til að trufla niðurhal og fá aðgang að einkaupplýsingum."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Ítarlegir eiginleikar niðurhalsstjórnunar."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Leyfir forritum að fá aðgang að ítarlegum eiginleikum niðurhalsstjórnunar. Spilliforrit geta notað þetta til að trufla niðurhal og fá aðgang að einkaupplýsingum."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Senda tilkynningar um niðurhal."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Leyfir forriti að senda tilkynningar um niðurhal sem er lokið. Spilliforrit geta notað þetta til að skapa rugling hjá öðrum forritum sem sækja skrár."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"Sjá allt niðurhal í USB-geymslu"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"Sjá allt niðurhal á SD-korti"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Leyfir forriti að sjá allt niðurhal á SD-korti, án tillits til þess hvaða forrit sótti skrárnar."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Taka frá pláss í skyndiminni niðurhals"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Leyfir forriti að sækja skrár í skyndiminni niðurhals sem ekki er hægt að hreinsa sjálfkrafa þegar niðurhalsstjórnun þarf meira pláss."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"sækja skrár án tilkynningar"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Leyfir forriti að sækja skrár í gegnum niðurhalsstjórnun án þess að birta notandanum tilkynningu."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Aðgangur að öllu niðurhali kerfis"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Leyfir forriti að skoða og breyta öllu niðurhali sem hvaða forrit kerfisins sem er hóf."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;Ónefnt&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"Niðurhali lokið."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"Niðurhal mistókst."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"Stærðin krefst Wi-Fi."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"Í bið í bakgrunni."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"Of stórt niðurhal fyrir kerfi símafyrirtækis"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"Þú verður að nota Wi-Fi til að ljúka þessu <xliff:g id="SIZE">%s </xliff:g> niðurhali. \n\nÝttu á <xliff:g id="QUEUE_TEXT">%s </xliff:g> til að hefja þetta niðurhal næst þegar þú tengist Wi-Fi neti."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"Setja í biðröð til að sækja síðar?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"Ef þetta <xliff:g id="SIZE">%s </xliff:g> niðurhal er hafið kann rafhlaðan að tæmast hraðar og/eða notkun farsímagagnatengingar að verða mjög mikil, sem kann að hafa í för með sér að símafyrirtækið þitt rukki þig aukalega, allt eftir áskrift.\n\n Ýttu á <xliff:g id="QUEUE_TEXT">%s</xliff:g> til að hefja þetta niðurhal næst þegar þú tengist Wi-Fi neti."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"Setja í biðröð"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"Hætta við"</string>
+ <string name="button_start_now" msgid="792123674007840864">"Hefja núna"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"Verið að sækja 1 skrá"</item>
+ <item quantity="other" msgid="9087228371320573153">"Verið að sækja <xliff:g id="NUMBER">%d</xliff:g> skrár"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 skrá í bið"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> skrár í bið"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> eftir"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"Ekki er hægt að opna skrána"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"Niðurhal"</string>
+ <string name="download_queued" msgid="3302638231377947451">"Í biðröð"</string>
+ <string name="download_running" msgid="3925050393361158266">"Í gangi"</string>
+ <string name="download_error" msgid="5144180777324573236">"Mistókst"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"Í gangi, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
new file mode 100644
index 00000000..8952466e
--- /dev/null
+++ b/res/values-kk-rKZ/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"Жүктеу менеджері"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"Жүктеу менеджеріне кіру."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"Қолданбаға жүктеу менеджеріне кіріп, оны файлдарды жүктеу үшін қолдану мүмкіндігін береді. Залалды қолданбалар бұны жүктеулерге кедергі жасау үшін және жеке ақпаратқа кіру үшін қолдануы мүмкін."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Жүктеу менеджерінің қосымша функциялары."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Қолданбаға жүктеу менеджерінің қосымша функцияларына кіру мүмкіндігін береді. Залалды қолданбалар бұны жүктеулерге кедергі жасау үшін және жеке ақпаратқа кіру үшін қолдануы мүмкін."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Жүктеу хабарларын жіберу."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Қолданбаға аяқталған жүктеулер туралы хабар жіберу мүмкіндігін береді. Залалды қолданбалар бұны файл жүктейтін басқа қолданбаларды шатастыру үшін қолдану мүмкін."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB жадындағы барлық жүктеулерді көру"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD картадағы барлық жүктеулерді көру"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Қолданбаға қандай қолданба жүктелгеніне қарамастан SD картадағы барлық жүктеулерді көру мүмкіндігін береді."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Жүктеу кэшінде орын сақтау"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Қолданбаға файлдарды жүктеу кэшіне жүктеу мүмкіндігін береді, ол жүктеу менеджеріне көбірек орын қажет болғанда автоматты түрде жойылмайды."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"файлдарды ескертусіз жүктеу"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Қолданбаға файлдарды пайдаланушыға ешқандай хабарларды көрсетпей, жүктеу менеджері арқылы жүктеу мүмкіндігін береді"</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Жүйе жүктеулерінің барлығына кіру мүмкіндігі"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Қолданбаға жүйедегі кез келген қолданба бастаған жүктеулерді көру және өзгерту мүмкіндігін береді."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;Атаусыз&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"Жүктеу аяқталды."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"Жүктеу орындалмады."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"Жүктеу өлшемі Wi-Fi байланысын қажет етеді."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"Артқы шепте тоқтатылған."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"Амалдық желі үшін жүктеу тым үлкен"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"<xliff:g id="SIZE">%s </xliff:g> өлшемді жүктеуді аяқтау үшін сізге Wi-Fi қажет. Келесі жолы Wi-Fi желісіне қосылғанда осы жүктеуді бастау үшін \n\nТүртіңіз <xliff:g id="QUEUE_TEXT">%s </xliff:g>."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"Кейінірек жүктеу үшін кезекке қойылсын ба?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"<xliff:g id="SIZE">%s </xliff:g> қазір жүктей бастау батарея ұзақтығын азайтуы және/немесе ұялы дерек байланысын тым көп қолдануға соқтыруы мүмкін, нәтижесінде дерекқор жоспарыңызға қарай ұялы операторыңыз қосымша төлем талап ету мүмкін.\nКелесі жолы Wi-Fi желісіне қосылғанда осы жүктеуді бастау үшін \n Түртіңіз <xliff:g id="QUEUE_TEXT">%s</xliff:g>."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"Кезек"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"Бас тарту"</string>
+ <string name="button_start_now" msgid="792123674007840864">"Қазір бастау"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"1 файл жүктелуде"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> файл жүктелуде"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 файл күтуде"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> файл күтуде"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> қалды"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"Файлды аша алмады"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"Жүктеулер"</string>
+ <string name="download_queued" msgid="3302638231377947451">"Кезекте"</string>
+ <string name="download_running" msgid="3925050393361158266">"Жүктелуде"</string>
+ <string name="download_error" msgid="5144180777324573236">"Сәтсіз"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"Жүктелуде, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
index 2dc768cf..bdb2b789 100644
--- a/res/values-km-rKH/strings.xml
+++ b/res/values-km-rKH/strings.xml
@@ -42,7 +42,7 @@
<string name="wifi_recommended_title" msgid="7441589306734687400">"ដាក់​ជា​ជួរ​ដើម្បី​ទាញ​យក​បន្ទាប់?"</string>
<string name="wifi_recommended_body" msgid="1314735166699936073">"ចាប់ផ្ដើម​ការ​ទាញ​យក <xliff:g id="SIZE">%s </xliff:g> ឥឡូវ​អាច​បណ្ដាលឲ្យ​ថ្ម​របស់​អ្នក​មាន​អាយុ​ខ្លី និង/ឬ​បង្ហាញ​ថា​លើស​ការ​ប្រើ​នៃ​តំណ​ភ្ជាប់​ទិន្នន័យ​ទូរស័ព្ទ​របស់​អ្នក ដែល​អាច​គិត​ប្រាក់​ដោយ​ប្រតិបត្តិករ​ទូរស័ព្ទ​អាស្រ័យ​តាម​គម្រោង​ទិន្នន័យ​របស់​អ្នក។\n\n ប៉ះ <xliff:g id="QUEUE_TEXT">%s</xliff:g> ខាងក្រោម​ដើម្បី​ចាប់ផ្ដើម​ការ​ទាញ​យក​នេះ​នៅ​ពេល​អ្នក​បាន​តភ្ជាប់​បណ្ដាញ​វ៉ាយហ្វាយ។"</string>
<string name="button_queue_for_wifi" msgid="422576726189179221">"ជួរ"</string>
- <string name="button_cancel_download" msgid="2430166148737975604">"បោះ​បង់"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"បោះ​បង់​"</string>
<string name="button_start_now" msgid="792123674007840864">"ចាប់ផ្ដើម​ឥឡូវ"</string>
<string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<plurals name="notif_summary_active">
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
new file mode 100644
index 00000000..62d033b7
--- /dev/null
+++ b/res/values-kn-rIN/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"ಡೌನ್‌ಲೊಡ್‌ ನಿರ್ವಾಹಕ"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"ಡೌನ್‌ಲೋಡ್‌ ನಿರ್ವಾಹಕವನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"ಡೌನ್‌ಲೋಡ್‌ ನಿರ್ವಾಹಕವನ್ನು ಪ್ರವೇಶಿಸಲು ಮತ್ತು ಡೌನ್‌ಲೋಡ್‌ ಫೈಲ್‌ಗಳನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್‌ ಅನುಮತಿ ನೀಡುತ್ತದೆ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಡೌನ್‌ಲೋಡ್‌ಗಳನ್ನು ಭಗ್ನಗೊಳಿಸಲು ಹಾಗೂ ಖಾಸಗಿ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು ಇದನ್ನು ಬಳಸಿಕೊಳ್ಳಬಹುದು."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"ಸುಧಾರಿತ ಡೌನ್‌ಲೋಡ್‌ ನಿರ್ವಾಹಕ ಕಾರ್ಯಚಟುವಟಿಕೆಗಳು."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"ಡೌನ್‌ಲೋಡ್‌ ನಿರ್ವಾಹಕದ ಸುಧಾರಿತ ಕಾರ್ಯಚಟುವಟಿಕೆಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಡೌನ್‌ಲೋಡ್‌ಗಳನ್ನು ಭಗ್ನಗೊಳಿಸಲು ಹಾಗೂ ಖಾಸಗಿ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು ಇದನ್ನು ಬಳಸಿಕೊಳ್ಳಬಹುದು."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"ಡೌನ್‌ಲೋಡ್‌ ಅಧಿಸೂಚನೆಗಳನ್ನು ಕಳುಹಿಸು."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"ಪೂರ್ಣಗೊಂಡಿರುವ ಡೌನ್‌ಲೋಡ್‌ಗಳ ಕುರಿತು ಅಧಿಸೂಚನೆಗಳನ್ನು ಕಳುಹಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಡೌನ್‌ಲೋಡ್ ಮಾಡುವ ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಲ್ಲಿ ಗೊಂದಲವುಂಟು ಮಾಡಲೋಸುಗ ಇದನ್ನು ಬಳಸಿಕೊಳ್ಳಬಹುದು."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB ಸಂಗ್ರಹಣೆಯಲ್ಲಿನ ಎಲ್ಲ ಡೌನ್‌ಲೋಡ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD ಕಾರ್ಡ್‌ನಲ್ಲಾದ ಎಲ್ಲ ಡೌನ್‌ಲೋಡ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"ಯಾವ ಅಪ್ಲಿಕೇಶನ್‌ ಆದರೂ ಡೌನ್‌ಲೋಡ್‌ ಮಾಡಿರಲಿ, SD ಕಾರ್ಡ್‌ನಲ್ಲಾದ ಆ ಎಲ್ಲಾ ಡೌನ್‌ಲೋಡ್‌‌ಗಳನ್ನ ವೀಕ್ಷಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"ಡೌನ್‌ಲೋಡ್‌ ಕ್ಯಾಷ್‌ನಲ್ಲಿ ಸ್ಥಳವನ್ನು ಮೀಸಲಿರಿಸಿ"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"ಡೌನ್‌ಲೊಡ್‌ ನಿರ್ವಾಹಕಕ್ಕೆ ಹೆಚ್ಚಿನ ಸ್ಥಳಾವಕಾಶದ ಅಗತ್ಯವಿರುವ ಸಂದರ್ಭದಲ್ಲಿ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಅಳಿಸಲಾಗದಿರುವ ಫೈಲ್‌ಗಳನ್ನು ಡೌನ್‌ಲೋಡ್‌ ಕ್ಯಾಷ್‌ಗೆ ಡೌನ್‌ಲೋಡ್ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿ ನೀಡಲಾಗುತ್ತದೆ."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"ಅಧಿಸೂಚನೆ ಇಲ್ಲದೆಯೇ ಫೈಲ್‌ಗಳನ್ನು ಡೌನ್‌ಲೋಡ್‌‌ ಮಾಡಿ"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"ಯಾವುದೇ ಅಧಿಸೂಚನೆಯನ್ನು ಬಳಕೆದಾರರಿಗೆ ತೋರಿಸದೇ ಡೌನ್‌ಲೋಡ್‌ ನಿರ್ವಾಹಕದ ಮೂಲಕ ಫೈಲ್‌ಗಳನ್ನು ಡೌನ್‌ಲೋಡ್‌ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"ಎಲ್ಲ ಸಿಸ್ಟಂನ ಡೌನ್‌ಲೋಡ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"ಸಿಸ್ಟಂನಲ್ಲಿ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ ಮೂಲಕ ಆರಂಭಿಸಲಾದ ಎಲ್ಲ ಡೌನ್‌ಲೋಡ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಮತ್ತು ಮಾರ್ಪಡಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿ ನೀಡಲಾಗುತ್ತದೆ."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;ಶೀರ್ಷಿಕೆ ರಹಿತ&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"ಡೌನ್‌ಲೋಡ್‌‌ ಪೂರ್ಣಗೊಂಡಿದೆ."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"ಡೌನ್‌ಲೋಡ್‌ ವಿಫಲಗೊಂಡಿದೆ."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"ಡೌನ್‌ಲೋಡ್‌ ಗಾತ್ರಕ್ಕೆ Wi-Fi ಅಗತ್ಯವಿದೆ."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"ಆಪರೇಟರ್‌ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಡೌನ್‌ಲೋಡ್ ತುಂಬಾ ದೊಡ್ಡದಾಗಿದೆ"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"ನೀವು ಈ <xliff:g id="SIZE">%s </xliff:g> ಡೌನ್‌ಲೋಡ್‌ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಲು ನೀವು Wi-Fi ಅನ್ನು ಬಳಸಬೇಕು. \n\nನೀವು ಸಂಪರ್ಕಿಸಿದ Wi-Fi ನೆಟ್‌ವರ್ಕ್‌ನಿಂದ ಮುಂದಿನ ಬಾರಿ ಈ ಡೌನ್‌ಲೋಡ್‌ ಅನ್ನು ಪ್ರಾರಂಭಿಸಲು <xliff:g id="QUEUE_TEXT">%s </xliff:g> ಸ್ಪರ್ಶಿಸಿ."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"ನಂತರದಲ್ಲಿ ಡೌನ್‌ಲೋಡ್‌ ಮಾಡಲು ಸರದಿಯಲ್ಲಿರಿಸುವುದೇ?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"ಇದೀಗ ಈ <xliff:g id="SIZE">%s </xliff:g> ಡೌನ್‌ಲೋಡ್‌ ಆರಂಭಗೊಂಡು ನಿಮ್ಮ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆ ಮತ್ತು/ಅಥವಾ ನಿಮ್ಮ ಮೊಬೈಲ್‌ ಡೇಟಾ ಸಂಪರ್ಕದ ಅತಿಯಾದ ಬಳಕೆಗೆ ಕಾರಣವಾಗಬಹುದು, ನಿಮ್ಮ ಡೇಟಾ ಯೋಜನೆಯನ್ನು ಅವಲಂಬಿಸಿ ನಿಮ್ಮ ಮೊಬೈಲ್ ಆಪರೇಟರ್ ಮೂಲಕ ಶುಲ್ಕಗಳನ್ನು ವಿಧಿಸುವುದಕ್ಕೆ ಕಾರಣವಾಗುತ್ತವೆ.\n\n ನೀವು ಸಂಪರ್ಕಿಸಿದ Wi-Fi ನೆಟ್‌ವರ್ಕ್‌ನಿಂದ ಮುಂದಿನ ಬಾರಿ ಈ ಡೌನ್‌ಲೋಡ್‌ ಪ್ರಾರಂಭಿಸಲು <xliff:g id="QUEUE_TEXT">%s</xliff:g> ಸ್ಪರ್ಶಿಸಿ."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"ಸರದಿ"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"ರದ್ದುಮಾಡು"</string>
+ <string name="button_start_now" msgid="792123674007840864">"ಈಗ ಪ್ರಾರಂಭಿಸಿ"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"1 ಫೈಲ್‌ ಡೌನ್‌ಲೋಡ್‌ ಆಗುತ್ತಿದೆ"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> ಫೈಲ್‌ಗಳು ಡೌನ್‌ಲೋಡ್‌ ಆಗುತ್ತಿವೆ"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 ಫೈಲ್‌ ನಿರೀಕ್ಷೆಯಲ್ಲಿದೆ"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> ಫೈಲ್‌ಗಳು ನಿರೀಕ್ಷೆಯಲ್ಲಿವೆ"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> ಉಳಿದಿದೆ"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"ಫೈಲ್ ತೆರೆಯಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"ಡೌನ್‌ಲೋಡ್‌ಗಳು"</string>
+ <string name="download_queued" msgid="3302638231377947451">"ಸರದಿಯಲ್ಲಿರಿಸಲಾಗಿದೆ"</string>
+ <string name="download_running" msgid="3925050393361158266">"ಪ್ರಗತಿಯಲ್ಲಿದೆ"</string>
+ <string name="download_error" msgid="5144180777324573236">"ವಿಫಲಗೊಂಡಿದೆ"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"ಪ್ರಗತಿಯಲ್ಲಿದೆ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
new file mode 100644
index 00000000..a325b5dd
--- /dev/null
+++ b/res/values-ky-rKG/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"Жүктөө менежери"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"Жүктөө менежерине жетүү."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"Колдонмого, жүктөө мененджерине жетип, аны менен файлдарды жүктөп алууга уруксат берет. Зыяндуу колдонмолор муну колдонуп, жүктөөлөрдү үзгүлтүккө учурата алышы жана жеке маалыматка жете алышы мүмкүн."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Жүктөө менежеринин озуккан функцияларына жетүү."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Колдонмого жүктөө менежеринин озуккан функцияларына жетүү уруксатын берет. Зыяндуу колдонмолор муну колдонуп, жүктөөлөрдү үзгүлтүккө учуратышы жана жеке маалыматтарга жетиши мүмкүн."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Жүктөө эскертмелерин жөнөтүү."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Колдонмо аяктаган жүктөөлөр тууралуу эскертмелерди жөнөтүүгө уруксат алат. Зыяндуу колдонмолор муну башка файл жүктөөчү колдонмолорго тоскоол кылыш үчүн колдонушу мүмкүн."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB сактагычка болгон жүктөөлөрдү көрүү"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD-картага болгон жүктөөлөрдү көрүү"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Колдонмого, муну кайсы колдонмо аткарып жатканына карабай, SD-картага түшүрүлүп жаткан бардык жүктөөлөрдү көрүү уруксатын берет."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Жүктөө кэшинен орун ээлөө"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Колдонмого, жүктөө менежерине көбүрөөк орун керек болсо, автоматтык тазалана турган файлдарды жүктөө кэшине жүктөөгө уруксат берет."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"файлдарды эскертмесиз жүктөө"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Колдонмо колдонуучуга эч эскертме көрсөтпөй туруп, жүктөө менежери аркылуу файлдарды жүктөп алуу уруксатын алат."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Бардык системдик жүктөөлөргө жетүү"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Колдонмого системдеги колдонмолор баштаган бардык жүктөөлөрдү көрүүгө жана өзгөртүүгө уруксат берет."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;Аталышы жок&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"Жүктөө аяктады."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"Жүктөө ийгиликсиз."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"Чоң файл, Wi-Fi керек."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"Фондо тыныгууда турат."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"Мобилдик түйүн үчүн, бул өтө чоң жүктөө"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"Өлчөмү <xliff:g id="SIZE">%s </xliff:g> болгон бул жүктөөнү Wi-Fi менен аткарышыңыз керек. \n\nБул жүктөөнү сиз кийин Wi-Fi түйүнгө туташканда башташ үчүн, <xliff:g id="QUEUE_TEXT">%s </xliff:g> тийип коюңуз."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"Кийин жүктөө кезегине тургузулсунбу?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"Өлчөмү <xliff:g id="SIZE">%s </xliff:g> болгон жүктөөнү азыр баштасаңыз, батарейиңиздин өмүрү кыскарышы жана/же мобилдик интернет трафиги өтө көп сарпталып, тарифтик планыңызга жараша, операторуңуз сизден төлөм алышы мүмкүн.\n\n Бул жүктөөнү сиз кийин Wi-Fi түйүнгө туташканда башташ үчүн, <xliff:g id="QUEUE_TEXT">%s</xliff:g> тийип коюңуз."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"Кезекке тургузуу"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"Айнуу"</string>
+ <string name="button_start_now" msgid="792123674007840864">"Азыр баштоо"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"1 файл жүктөлүүдө"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> файл жүктөлүүдө"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 файл күтүлүүдө"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> файл күтүлүүдө"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> калды"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"Файл ачылбады"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"Жүктөөлөр"</string>
+ <string name="download_queued" msgid="3302638231377947451">"Кезекте"</string>
+ <string name="download_running" msgid="3925050393361158266">"Жүктөлүүдө"</string>
+ <string name="download_error" msgid="5144180777324573236">"Ийгиликсиз"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"Жүктөлүүдө, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
new file mode 100644
index 00000000..32fdc9b5
--- /dev/null
+++ b/res/values-mk-rMK/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"Управник за преземање"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"Пристапи до управувачот за преземања."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"Овозможува апликацијата да пристапи до менаџерот за преземање и да го користи за преземање датотеки. Злонамерните апликации може да го искористат ова да ги попречат преземањата и да пристапат до приватни информации."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Напредни функции на управувачот за преземања."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Овозможува апликацијата да пристапи до напредни функции на менаџерот за преземање. Злонамерните апликации може да го искористат ова да ги попречат преземањата и да пристапат до приватни информации."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Испрати известувања за преземањата."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Овозможува апликацијата да испраќа известувања за завршени преземања. Злонамерните апликации може да го искористат ова да ги збунат другите апликации кои преземаат датотеки."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"Виде ги сите преземања на УСБ меморијата"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"Види ги сите преземања на СД картичката"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Овозможува апликацијата да ги види сите преземања на СД картичката, без разлика со која апликација се преземани."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Зачувај простор во преземаниот кеш"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Овозможува апликацијата да презема датотеки до преземан кеш кој не може автоматски да се избрише кога менаџерот за преземање бара повеќе простор."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"преземи датотеки без известување"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Овозможува апликацијата да презема датотеки преку менаџерот за преземање без да се прикаже какво било претходно известување на корисникот."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Пристапи до сите системски преземања"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Овозможува апликацијата да ги гледа и менува сите преземања иницирани од која било апликација на системот."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;Без наслов&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"Преземањето заврши."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"Преземањето е неуспешно."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"Големина за преземање бара Wi-Fi."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"Паузирано во заднина."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"Премногу големо преземање за мрежата на операторот"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"Мора да користите Wi-Fi да се заврши преземањето на овие <xliff:g id="SIZE">%s </xliff:g>\n\nДопрете <xliff:g id="QUEUE_TEXT">%s </xliff:g> да започне ова преземање следниот пат кога ќе бидете поврзани со Wi-Fi мрежа."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"Стави во ред на чекање да се преземе подоцна?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"Преземањето <xliff:g id="SIZE">%s </xliff:g> го намалува векот на батеријата и/или води до прекумерна употреба на конекцијата и може да ви наплатат.\n\n Допрете <xliff:g id="QUEUE_TEXT">%s</xliff:g> да започне преземање следниот пат кога ќе бидете поврзани со Wi-Fi мрежа."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"Ред на чекање"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"Откажи"</string>
+ <string name="button_start_now" msgid="792123674007840864">"Започни сега"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"1 датотека се презема"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> датотеки се преземаат"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 датотека чека"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> датотеки чекаат"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"Уште <xliff:g id="DURATION">%s</xliff:g>"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"Датотеката не се отвора"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"Преземања"</string>
+ <string name="download_queued" msgid="3302638231377947451">"Чека на ред"</string>
+ <string name="download_running" msgid="3925050393361158266">"Во тек"</string>
+ <string name="download_error" msgid="5144180777324573236">"Неуспешно"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"Во тек, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
new file mode 100644
index 00000000..c9414231
--- /dev/null
+++ b/res/values-ml-rIN/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"ഡൗൺലോഡ് മാനേജർ"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"ഡൗൺലോഡ് മാനേജർ ആക്‌സസ്സുചെയ്യുക."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"ഡൗൺലോഡ് മാനേജർ ആക്‌സസ്സുചെയ്യാനും ഫയലുകൾ ഡൗൺലോഡുചെയ്യുന്നതിന് അത് ഉപയോഗിക്കാനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഡൗൺലോഡുകൾ തടസ്സപ്പെടുത്താനും സ്വകാര്യ വിവരം ആക്‌സസ്സുചെയ്യാനും ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ ഇതുപയോഗിച്ചേക്കാം."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"വിപുലമായ ഡൗൺലോഡ് മാനേജർ പ്രവർത്തനങ്ങൾ."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"ഡൗൺലോഡ് മാനേജറുടെ വിപുലമായ പ്രവർത്തനങ്ങൾ ആക്‌സസ്സുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഡൗൺലോഡുകൾ തടസ്സപ്പെടുത്താനും സ്വകാര്യ വിവരം ആക്‌സസ്സുചെയ്യാനും ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ ഇതുപയോഗിച്ചേക്കാം."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"ഡൗൺലോഡ് അറിയിപ്പുകൾ അയയ്‌ക്കുക"</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"പൂർത്തിയാക്കിയ ഡൗൺലോഡുകളെക്കുറിച്ച് അറിയിപ്പുകൾ അയയ്‌ക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഫയലുകൾ ഡൗൺലോഡുചെയ്യുന്ന മറ്റ് അപ്ലിക്കേഷനുകളെ ആശയക്കുഴപ്പത്തിലാക്കാൻ ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ ഇതുപയോഗിച്ചേക്കാം."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB സംഭരണത്തിലേക്കുള്ള എല്ലാ ഡൗൺലോഡുകളും കാണുക"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD കാർഡിലേക്കുള്ള എല്ലാ ഡൗൺലോഡുകളും കാണുക"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"SD കാർഡിലേക്കുള്ള എല്ലാ ഡൗൺലോഡുകളും, ഏത് അപ്ലിക്കേഷനാണ് അവയെ ഡൗൺലോഡുചെയ്‌തതെന്ന് പരിഗണിക്കാതെ തന്നെ, കാണാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"ഡൗൺലോഡ് കാഷെയിൽ ഇടം നിലനിർത്തുക"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"ഡൗൺലോഡ് കാഷെയിലേക്ക് ഫയലുകൾ ഡൗൺലോഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു, ഡൗൺലോഡ് മാനേജർക്ക് കൂടുതൽ ഇടം ആവശ്യമായി വരുമ്പോൾ ഇത് യാന്ത്രികമായി ഇല്ലാതാക്കാനാകില്ല."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"അറിയിപ്പില്ലാതെ ഫയലുകൾ ഡൗൺലോഡുചെയ്യുക"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"ഉപയോക്താവിന് അറിയിപ്പൊന്നും ദൃശ്യമാക്കാതെ തന്നെ ഡൗൺലോഡ് മാനേജർ മുഖേന ഫയലുകൾ ഡൗൺലോഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"എല്ലാ സിസ്റ്റം ഡൗൺലോഡുകളും ആക്‌സസ്സുചെയ്യുക"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"സിസ്റ്റത്തിലെ ഏതെങ്കിലും അപ്ലിക്കേഷൻ സമാരംഭിച്ച എല്ലാ ഡൗൺലോഡുകളും കാണുന്നതിനും പരിഷ്‌ക്കരിക്കുന്നതിനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;ശീർഷകമില്ലാത്തത്&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"ഡൗൺലോഡ് പൂർത്തിയായി."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"ഡൗൺലോഡുചെയ്‌തു."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"ഡൗൺലോഡ് വലുപ്പം Wi-Fi ആവശ്യപ്പെടുന്നു."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"പശ്ചാത്തലത്തിൽ താൽക്കാലികമായി നിർത്തി."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"ഡൗൺലോഡ്, ഓപ്പറേറ്റർ നെറ്റ്‌വർക്കിൽ ചെയ്യാനാകുന്നതിലും വളരെ വലുതാണ്"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"ഈ ഡൗൺലോഡ് <xliff:g id="SIZE">%s </xliff:g> പൂർത്തിയാക്കാൻ നിങ്ങൾ Wi-Fi ഉപയോഗിക്കണം.\n\n നിങ്ങൾ അടുത്ത തവണ Wi-Fi നെറ്റ്‌വർക്കിൽ കണക്റ്റുചെയ്യുമ്പോൾ ഈ ഡൗൺലോഡ് ആരംഭിക്കാൻ <xliff:g id="QUEUE_TEXT">%s </xliff:g> സ്‌പർശിക്കുക."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"പിന്നീട് ഡൗൺലോഡുചെയ്യുന്നതിനായി ക്യൂവിലാക്കണോ?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"ഈ <xliff:g id="SIZE">%s </xliff:g> ഡൗൺലോഡ് ആരംഭിക്കുന്നത്, നിങ്ങളുടെ ബാറ്ററിയുടെ ആയുസ്സ് കുറയ്‌ക്കാനോ കൂടാതെ/അല്ലെങ്കിൽ നിങ്ങളുടെ മൊബൈൽ ഡാറ്റ കണക്ഷന്റെ അമിതോപയോഗത്തിനോ ഇടയാക്കാം, അത് നിങ്ങളുടെ ഡാറ്റ പ്ലാനിനെ ആശ്രയിച്ച് മൊബൈൽ ഓപ്പറേറ്റർ നിശ്ചയിക്കുന്ന നിരക്കുകളിലേക്ക് നയിക്കാനിടയുണ്ട്.\n\n നിങ്ങൾ അടുത്ത തവണ Wi-Fi നെറ്റ്‌വർക്കിൽ കണക്റ്റുചെയ്യുമ്പോൾ ഈ ഡൗൺലോഡ് ആരംഭിക്കാൻ <xliff:g id="QUEUE_TEXT">%s</xliff:g> സ്‌പർശിക്കുക."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"ക്യൂ"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"റദ്ദാക്കുക"</string>
+ <string name="button_start_now" msgid="792123674007840864">"ഇപ്പോൾ ആരംഭിക്കുക"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"ഒരു ഫയൽ ഡൗൺലോഡുചെയ്യുന്നു"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> ഫയലുകൾ ഡൗൺലോഡുചെയ്യുന്നു"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"ഒരു ഫയൽ കാത്തിരിക്കുന്നു"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> ഫയലുകൾ കാത്തിരിക്കുന്നു"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> ശേഷിക്കുന്നു"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"ഫയൽ തുറക്കാനായില്ല"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"ഡൗൺലോഡുകൾ"</string>
+ <string name="download_queued" msgid="3302638231377947451">"ക്യൂവിലാണ്"</string>
+ <string name="download_running" msgid="3925050393361158266">"പുരോഗമിക്കുന്നു"</string>
+ <string name="download_error" msgid="5144180777324573236">"പരാജയപ്പെട്ടു"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"പുരോഗതിയിലാണ്, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
new file mode 100644
index 00000000..b0c86746
--- /dev/null
+++ b/res/values-mr-rIN/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"डाउनलोड व्यवस्थापक"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"डाउनलोड व्यवस्थापकावर प्रवेश करा."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"अ‍ॅपला डाउनलोड व्‍यवस्‍थापकामध्‍ये प्रवेश करण्‍याची आणि फायली डाउनलोड करण्‍यासाठी त्याचा वापर करण्‍याची अनुमती देते. दुर्भावनापूर्ण अ‍ॅप्‍स याचा डाउनलोड विदारित करण्‍यासाठी आणि खाजगी माहितीमध्‍ये प्रवेश करण्‍यासाठी वापर करू शकतात."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"प्रगत डाऊनलोड व्यवस्थापक कार्ये."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"अ‍ॅपला डाउनलोड व्‍यवस्‍थापकाच्या प्रगत कार्यांमध्‍ये प्रवेश करण्‍याची अनुमती देते. दुर्भावनापूर्ण अ‍ॅप्‍स याचा डाउनलोड विदारित करण्‍यासाठी आणि खाजगी माहितीमध्‍ये प्रवेश करण्‍यासाठी वापर करू शकतात."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"डाउनलोड सूचना पाठवा."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"अ‍ॅपला पूर्ण झालेल्‍या डाउनलोड विषयी सूचना पाठविण्‍यास अनुमती देते. डाउनलोड करणार्‍या अन्य अ‍ॅप्‍सचा गोंधळ करण्‍यासाठी दुर्भावनापूर्ण अ‍ॅप्‍स याचा वापर करू शकतात."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB संचयनाचे सर्व डाउनलोड पहा"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD कार्डचे सर्व डाउनलोड पहा"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"अ‍ॅपला कोणत्या अ‍ॅपने त्यांना डाउनलोड केले ते विचारात न घेता SD कार्डचे सर्व डाउनलोड पाहण्‍याची अनुमती देते."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"डाउनलोड कॅशेमधील स्‍थान आरक्षित करा"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"अ‍ॅपला डाउनलोडवर कॅशेवर, डाउनलोड व्‍यवस्‍थापकास जास्त स्‍थानाची आवश्‍यकता असते तेव्‍हा ज्या स्‍वयंचलितपणे हटविल्‍या जाऊ शकत नाहीत त्या फायली डाउनलोड करण्‍याची अनुमती देते."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"सूचनेशिवाय फायली डाउनलोड करा"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"अ‍ॅपला वापरकर्त्यास कोणतीही सूचना न दर्शविता डाउनलोड व्यवस्‍थापकाद्वारे फायली डाउनलोड करण्‍याची अनुमती देते."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"सर्व सिस्‍टीम डाउनलोडवर प्रवेश करा"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"अ‍ॅपला सिस्‍टीम वरील कोणत्‍याही अ‍ॅपद्वारे आरंभ केलेले सर्व डाउनलोड पाहण्‍याची आणि सुधारित करण्‍याची अनुमती देते."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;अशीर्षकांकित&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"डाउनलोड पूर्ण."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"डाउनलोड अयशस्वी."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"डाउनलोड आकारामानास Wi-Fi आवश्‍यक अस‍ते."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"पार्श्वभूमीत विराम दिला."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"ऑपरेटर नेटवर्कसाठी डाउनलोड खूप मोठे आहे"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"आपण हे <xliff:g id="SIZE">%s </xliff:g> डाउनलोड पूर्ण करण्‍यासाठी Wi-Fi चा वापर करणे आवश्‍यक आहे. पुढील वेळी आपण Wi-Fi ला कनेक्‍ट होता तेव्‍हा हे डाउनलोड प्रारंभ करण्‍यासाठी \n\n स्‍पर्श करा <xliff:g id="QUEUE_TEXT">%s </xliff:g>."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"नंतर डाउनलोड करा साठी रांग लावायची?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"हे <xliff:g id="SIZE">%s </xliff:g> डाउनलोड प्रारंभ करण्याने आपले बॅटरी आयुष्‍य कमी होऊ शकते आणि/किंवा त्‍याचा परिणाम आपल्‍या मोबाईल डेटा कनेक्‍शनचा अत्‍याधिक वापर करण्‍यात होऊ शकतो, ज्‍यामुळे आपल्‍या मोबाईल डेटा योजनेवर आधारित आपल्‍या मोबाईल ऑपरेटरद्वारे शुल्‍क आकारले जाऊ शकते.पुढील वेळी आपण Wi-Fi नेटवर्कशी कनेक्‍ट होता तेव्‍हा हे डाउनलोड प्रारंभ करण्‍यासाठी \n\n स्‍पर्श करा <xliff:g id="QUEUE_TEXT">%s</xliff:g>"</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"रांग"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"रद्द करा"</string>
+ <string name="button_start_now" msgid="792123674007840864">"आता प्रारंभ करा"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"1 फाइल डाउनलोड होत आहे"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> फायली डाउनलोड होत आहेत"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 फाइल प्रतीक्षेत"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> फायली प्रतीक्षेत"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> बाकी"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"फाइल उघडू शकत नाही"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"डाउनलोड"</string>
+ <string name="download_queued" msgid="3302638231377947451">"रांगेत लावलेला"</string>
+ <string name="download_running" msgid="3925050393361158266">"प्रगतीपथावर"</string>
+ <string name="download_error" msgid="5144180777324573236">"अयशस्वी"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"प्रगतीपथावर, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
deleted file mode 100644
index 70c37302..00000000
--- a/res/values-ms/strings.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="3658948994665187911">"Pengurus Muat Turun"</string>
- <string name="permlab_downloadManager" msgid="7779544811202855500">"Akses pengurus muat turun."</string>
- <string name="permdesc_downloadManager" msgid="4237406545998908947">"Membenarkan aplikasi untuk mengakses pengurus muat turun dan menggunakannya untuk memuat turun fail. Aplikasi berniat jahat boleh menggunakan ini untuk mengganggu muat turun dan mengakses maklumat peribadi."</string>
- <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Fungsi pengurus muat turun lanjutan."</string>
- <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Membenarkan aplikasi mengakses fungsi-fungsi lanjutan pengurus muat turun. Aplikasi berbahaya boleh menggunakan ini untuk mengganggu muat turun dan mengakses maklumat peribadi."</string>
- <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Hantar pemberitahuan muat turun."</string>
- <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Membenarkan aplikasi menghantar pemberitahuan tentang muat turun yang telah siap. Aplikasi berbahaya boleh menggunakan ini untuk mengelirukan aplikasi lain yang memuat turun fail."</string>
- <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"Lihat m.turun ke strn USB"</string>
- <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"Lihat semua muat turun ke kad SD"</string>
- <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Membenarkan aplikasi untuk melihat semua muat turun ke kad SD, tidak kira aplikasi mana yang memuat turun."</string>
- <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Menempah ruang dalam cache muat turun"</string>
- <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Membenarkan aplikasi memuat turun fail ke cache muat turun, yang tidak boleh dipadamkan secara automatik apabila pengurus muat turun memerlukan lebih banyak ruang."</string>
- <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"memuat turun fail tanpa pemberitahuan"</string>
- <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Membenarkan aplikasi memuat turun fail melalui pengurus muat turun tanpa menunjukkan sebarang pemberitahuan kepada pengguna."</string>
- <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Mengakses semua muat turun sistem"</string>
- <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Membenarkan aplikasi untuk melihat dan mengubah suai semua muat turun yang dimulakan oleh mana-mana aplikasi pada sistem."</string>
- <string name="download_unknown_title" msgid="7015124071247271585">"&lt;Tidak bertajuk&gt;"</string>
- <string name="notification_download_complete" msgid="5443563299253103667">"Muat turun selesai."</string>
- <string name="notification_download_failed" msgid="8612136111952014978">"Muat turun tidak berjaya."</string>
- <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"Saiz m.trn perlukn Wi-Fi"</string>
- <string name="notification_paused_in_background" msgid="4328508073283591772">"Dijeda di latar belakang."</string>
- <string name="wifi_required_title" msgid="1995971416871498179">"Muat turun terlalu besar untuk operator rangkaian"</string>
- <string name="wifi_required_body" msgid="3067694630143784449">"Anda mesti menggunakan Wi-Fi untuk melengkapkan muat turun <xliff:g id="SIZE">%s </xliff:g> ini. \n\nSentuh <xliff:g id="QUEUE_TEXT">%s </xliff:g> untuk memulakan muat turun ini lain kali anda disambungkan ke rangkaian Wi-Fi."</string>
- <string name="wifi_recommended_title" msgid="7441589306734687400">"Baris gilir untuk dimuat turun kemudian?"</string>
- <string name="wifi_recommended_body" msgid="1314735166699936073">"Memulakan muat turun <xliff:g id="SIZE">%s </xliff:g> ini sekarang mungkin memendekkan hayat bateri dan/atau menyebabkan penggunaan berlebihan sambungan data mudah alih anda, yang boleh menyebabkan caj dikenakan oleh operator mudah alih anda, bergantung kepada pelan data anda.\n\n Sentuh <xliff:g id="QUEUE_TEXT">%s</xliff:g> untuk memulakan muat turun ini pada kali seterusnya anda disambungkan kepada rangkaian Wi-Fi."</string>
- <string name="button_queue_for_wifi" msgid="422576726189179221">"Baris gilir"</string>
- <string name="button_cancel_download" msgid="2430166148737975604">"Batal"</string>
- <string name="button_start_now" msgid="792123674007840864">"Mulakan sekarang"</string>
- <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <plurals name="notif_summary_active">
- <item quantity="one" msgid="8475775855911967027">"1 fail sedang dimuat turun"</item>
- <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> fail sedang dimuat turun"</item>
- </plurals>
- <plurals name="notif_summary_waiting">
- <item quantity="one" msgid="5537481763963544278">"1 fail sedang menunggu"</item>
- <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> fail sedang menunggu"</item>
- </plurals>
- <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> tinggal"</string>
- <string name="download_no_application_title" msgid="7935659741162801699">"Tidak dapat membuka fail"</string>
-</resources>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
new file mode 100644
index 00000000..a1def90c
--- /dev/null
+++ b/res/values-my-rMM/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"ဒေါင်းလုပ်မန်နေဂျာ"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"ဒေါင်းလုပ်မန်နေဂျာကို သုံးစွဲခွင့်ပြုမည်"</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"အပလီကေးရှင်းအား ဒေါင်းလုပ်မန်နေဂျာကို သုံးစွဲနိုင်ရန်နှင့် ဖိုင်များကိုဒေါင်းလုပ်ပြုလုပ်ရန်အတွက်သုံးခြင်းကို ခွင့်ပြုမည်။ အန္တရာယ် ရှိသော အပလီကေးရှင်းများက ၎င်းကို အသုံးပြုကာ ဒေါင်းလုပ်ပြုလုပ်ခြင်းကို နှောက်ယှက်ခြင်းနှင့် ကိုယ်ပိုင်အချက်အလက်များကို ဝင်ရောက်ယူနိုင်သည်။"</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"အဆင့်မြင့် ဒေါင်းလုပ်မန်နေဂျာ လုပ်ငန်းများ"</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"အပလီကေးရှင်းအား ဒေါင်းလုပ်မန်နေဂျာ၏ အဆင့်မြင့် လုပ်ဆောင်ချက်များကို သုံးစွဲခွင့်ပြုမည်။ အန္တရာယ် ရှိသော အပလီကေးရှင်းများက ၎င်းကို အသုံးပြုကာ ဒေါင်းလုပ်ပြုလုပ်ခြင်းကို နှောက်ယှက်ခြင်းနှင့် ကိုယ်ပိုင်အချက်အလက်များကို ဝင်ရောက်ယူနိုင်သည်။"</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"ဒေါင်းလုပ်နှင့် ပတ်သက်သော အကြောင်းကြားချက် အားလုံးကိုပို့မည်"</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"အပလီကေးရှင်း အား ဒေါင်းလုပ်ပြီးဆုံးပါက အကြောင်းကြားရန် ခွင့်ပြုမည်။ အန္တရာယ် ရှိသော အပလီကေးရှင်းများက ၎င်းကို အသုံးပြုကာ ဖိုင်များကိုဒေါင်းလုပ်ပြုထားသော အပလီကေးရှင်းကို ရောထွေးအောင်ပြုလုပ်နိုင်သည်။"</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"ဒေါင်းလုပ်အားလုံးကို USBသိုလှောင်ကတ်ထဲတွင် ကြည့်မည်"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"ဒေါင်းလုပ်အားလုံးကို SDကတ်ထဲတွင် ကြည့်မည်"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"အပလီကေးရှင်းအား SDကဒ်ထဲရှိ မည်သည့်အပလီကေးရှင်းမှမဆို ဒေါင်းလုပ်ပြုလုပ်ထားသည်များကို သုံးစွဲခွင့်ပြုမည်။"</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"ဒေါင်းလုပ်ယာယီသိမ်းရန်နေရာတွင် ကြိုတင်နေရာယူထားမည်"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"အပလီကေးရှင်းအား ဒေါင်းလုပ်ပြုလုပ်ထားသောဖိုင်များကို ဒေါင်းလုပ်မန်နေဂျာမှ နေရာလွတ်လိုအပ်လျှင်အလိုအလျောက်ဖျက်မရသော ယာယီသိမ်းဆည်းရန်နေရာထဲသို့ ထည့်ရန် ခွင့်ပြုမည်"</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"အကြောင်းမကြားပဲ ဖိုင်များကို ဒေါင်းလုပ်ပြုလုပ်မည်"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"အပလီကေးရှင်းအား အသုံးပြုသူအား မည်သည့်အကြောင်းကြားချက်မျှမပေးပို့ပဲ ဒေါင်းလုပ်မန်နေဂျာမှတစ်ဆင့် ဖိုင်များကိုဒေါင်းလုပ်ပြုလုပ်ရန် ခွင့်ပြုမည်။"</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"စနစ်၏ ဒေါင်းလုပ်အားလုံးကို သုံးစွဲခွင့်ပြုမည်"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"အပလီကေးရှင်းအား စစ်စတန်ပေါ်ရှိ မည်သည့်အပလီကေးရှင်းမှ ဒေါင်းလုပ်ကိုမဆို ကြည့်ခြင်း သို့မဟုတ်ပြင်ဆင်နိုင်ရန် ခွင့်ပြုသည်"</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"အမည်မသိ"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"ဒေါင်းလုပ်ပြုလုပ်ပြီး"</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"ဒေါင်းလုပ်မအောင်မြင်ပါ"</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"ဒေါင်းလုပ်ပမာဏမှာ ဝိုင်ဖိုင်လိုအပ်သည်"</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"နောက်ခံတွင် ခဏဆိုင်းထားသည်"</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"ဒေါင်းလုပ်မှာ အော်ပရေတာကွန်ယက်အတွက် ကြီးလွန်းသည်"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"ဤ <xliff:g id="SIZE">%s </xliff:g> ဒေါင်းလုပ်ကို ပြုလုပ်ရန် ဝိုင်ဖိုင် ချိတ်ဆက်ထားရပါမည်၊ \n\nနောက်တစ်ခါ ဝိုင်ဖိုင်ကိုချိတ်ဆက်လျှင် ဒေါင်းလုပ်စတင်ရန် <xliff:g id="QUEUE_TEXT">%s </xliff:g> ကို တို့ထိပါ။"</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"နောက်မှ ဒေါင်းလုပ်ပြုလုပ်ရန် တန်းစီထားမလား?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"ဤ <xliff:g id="SIZE">%s </xliff:g>ဒေါင်းလုပ်ကို စတင်ခြင်းမှာ သင့်ဘက်ထရီ သက်တမ်းကို တိုစေသည် သို့မဟုတ် သင့်ဒေတာပလန်ပေါ် မူတည်၍ ကျသင့်ငွေ ပိုကုန်စေမည့် မိုဘိုင်းဒေတာ ချိတ်ဆက်မှုကို အလွန်အကျွံ သုံးနိုင်သည်။ \n\n နောက်တစ်ခါ ဝိုင်ဖိုင်ချိတ်ဆက်လျှင် ဒေါင်းလုပ်စတင်ရန် <xliff:g id="QUEUE_TEXT">%s</xliff:g> ကို တို့ထိပါ။"</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"တန်းစီရန်"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"ထားတော့"</string>
+ <string name="button_start_now" msgid="792123674007840864">"ယခုအချိန်မှစတင်ပါ"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"ဖိုင် ၁ ခု ဒေါင်းလုပ်ပြုလုပ်နေသည်"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> ဖိုင် ဒေါင်းလုပ်ပြုလုပ်နေသည်"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"ဖိုင်၁ ခု စောင့်နေသည်"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> ဖိုင် စောင့်နေသည်"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> ကျန်ရှိသည်"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"ဖိုင်အား ဖွင့်မရပါ"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"ဒေါင်းလုပ်များ"</string>
+ <string name="download_queued" msgid="3302638231377947451">"တန်းစီထားပြီး"</string>
+ <string name="download_running" msgid="3925050393361158266">"ပြုလုပ်နေဆဲ"</string>
+ <string name="download_error" msgid="5144180777324573236">"မအောင်မြင်ပါ"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"ပြုလုပ်နေဆဲ <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
new file mode 100644
index 00000000..d15d2d87
--- /dev/null
+++ b/res/values-ne-rNP/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"डाउनलोड प्रबन्धक"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"डाउनलोड प्रबन्धक पहुँच गर्नुहोस्"</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"फाइल डाउनलोड गर्नका लागि अनुप्रयोगलाई डाउनलोड प्रबन्धकको पहुँचको अनुमति दिन्छ। हानिकारक अनुप्रयोगहरूले यसलाई डाउनलोडहरू अवरूद्ध गर्न र निजी जानकारी पहुँच गर्न यसको प्रयोग गर्न सक्छन्।"</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"उन्नत डाउनलोड प्रबन्धक प्रकार्यहरू"</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"अनुप्रयोगलाई डाउनलोड प्रबन्धकको उन्नत प्रकार्यहरू पहुँच गर्न अनुमति दिन्छ। हानिकारक अनुप्रयोगहरूले यसलाई डाउनलोड अवरूद्ध गरी निजी जानकारी पहुँच गर्न प्रयोग गर्न सक्छ।"</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"डाउनलोड सूचनाहरू पठाउनुहोस्।"</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"अनुप्रयोगलाई समाप्त भएका डाउनलोडहरूका सूचनाहरू पठाउन अनुमति दिन्छ। हानिकारक अनुप्रयोगहरूले फाइल डाउनलोड गर्ने अन्य अनुप्रयोगलाई झुक्याउनका लागि यसलाई प्रयोग गर्न सक्छन्।"</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"सबै डाउनलोडहरूलाई USB भण्डारणमा हेर्नुहोस्"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"सबै डाउनलोडहरूलाई SD कार्डमा हेर्नुहोस्"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"जुनसुकै अनुप्रयोगले डाउनलोड गरेको भए पनि अनुप्रयोगलाई सम्पूर्ण डाउनलोडहरूलाई SD कार्डमा देख्ने अनुमति दिन्छ ।"</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"डाउनलोड केसमा ठाउँ ओगट्नुहोस्"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"अनुप्रयोगलाई फाइलहरूलाई डाउनलोड केसमा डाउनलोड गर्न अनुमति दिन्छ, जुन डाउनलोड प्रबन्धकलाई थप ठाउँ चाहिएको खण्डमा स्वचालित रूपमा हटाउन सकिदैन।"</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"बिना सूचना फाइलहरू डाउनलोड गर्नुहोस्"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"अनुप्रयोगलाई डाउनलोड प्रबन्धकका माध्ययमद्वारा प्रयोगकर्तामा सूचना नदेखाई फाइलहरू डाउनलोड गर्ने अनुमति दिन्छ।"</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"सम्पूर्ण प्रणाली डाउनलोडहरू पहुँच गर्नुहोस्"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"अनुप्रयोगलाई कुनै पनि अनुप्रयोगले प्रणालीमा पहल गरेको सम्पूर्ण डाउनलोडहरू हेर्ने र परिमार्जन गर्ने अनुमति दिन्छ।"</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;शीर्षकविहिन&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"डाउनलोड पुरा भयो।"</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"डाउनलोड असफल"</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"डाउनलोड आकारलाई वाइफाइ चाहिन्छ।"</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"पृष्ठभूमिमा रोकिएको छ।"</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"अपरेटर सञ्जालका लागि डाउनलोड ज्यादै ठूलो"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"तपाईँले वाइफाइ प्रयोग गर्नु पर्छ यस <xliff:g id="SIZE">%s </xliff:g> डाउनलोड समाप्त गर्न। \n\nछुनुहोस् <xliff:g id="QUEUE_TEXT">%s </xliff:g> यस डाउनलोडलाई सुरु गर्न अर्को पटक तपाईँ वाइफाइ सञ्जालामा जडित भए पछि।"</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"पछि डाउनलोडका लागि लाममा राख्ने हो?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"यस <xliff:g id="SIZE">%s </xliff:g> डाउनलोडलाई सुरु गर्दा तपाईँको ब्याट्रिको काल छोट्टिन सक्छ र/वा तपाईँको मोबाइल डेटा जडानको अधिकतम प्रयोग भई तपाईँको डेटा योजना अनुसार मोबाइल अपरेटरले थप शुल्क लिन सक्छ। \n\n छुनुहोस् <xliff:g id="QUEUE_TEXT">%s</xliff:g>तल यस डाउनलोडलाई सुरु गर्न अर्को पटक तपाईँ वाइफाइ सन्जालमा जडित हुने बेला।"</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"लाम"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"रद्द गर्नुहोस्"</string>
+ <string name="button_start_now" msgid="792123674007840864">"अहिले सुरु गर्नुहोस्"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"१ फाइल डाउनलोड हुँदै"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> फाइलहरू डाउनलोड हुँदै"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"१ फाइल पर्खँदै"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> फाइलहरू पर्खँदै"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> बाँकी छ"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"फाइल खोल्न सक्दैन"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"डाउनलोडहरू"</string>
+ <string name="download_queued" msgid="3302638231377947451">"लाममा राखियो"</string>
+ <string name="download_running" msgid="3925050393361158266">"प्रगतिमा"</string>
+ <string name="download_error" msgid="5144180777324573236">"असफल"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"प्रगतिमा, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 83eb6886..27302af8 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -18,20 +18,20 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3658948994665187911">"Gerenciador de downloads"</string>
<string name="permlab_downloadManager" msgid="7779544811202855500">"Acessar o gerenciador de download."</string>
- <string name="permdesc_downloadManager" msgid="4237406545998908947">"Permite que o aplicativo acesse o gerenciador de download e o use para fazer download de arquivos. Aplicativos maliciosos podem usar essa ação para interromper downloads e acessar informações privadas."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"Permite que o app acesse o gerenciador de download e o use para fazer download de arquivos. Apps maliciosos podem usar essa ação para interromper downloads e acessar informações privadas."</string>
<string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Funções avançadas do gerenciador de download."</string>
- <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Permite que o aplicativo acesse funções avançadas do gerenciador de download. Aplicativos maliciosos podem usar essa ação para interromper downloads e acessar informações privadas."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Permite que o app acesse funções avançadas do gerenciador de download. Apps maliciosos podem usar essa ação para interromper downloads e acessar informações privadas."</string>
<string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Enviar notificações de download."</string>
- <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Permite que o aplicativo envie notificações sobre downloads concluídos. Aplicativos maliciosos podem usar esse envio para confundir outros aplicativos que fazem download de arquivos."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Permite que o app envie notificações sobre downloads concluídos. Apps maliciosos podem usar esse envio para confundir outros apps que fazem download de arquivos."</string>
<string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"Ver downloads armaz. USB"</string>
<string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"Ver todos os downloads para o cartão SD"</string>
- <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Permite que o aplicativo veja todos os downloads do cartão SD, independentemente de sua origem."</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Permite que o app veja todos os downloads do cartão SD, independentemente de sua origem."</string>
<string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Reservar espaço no cache de download"</string>
<string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Permite que o aplic. faça download de arquivos no cache de downloads, que não podem ser excl. automatic. quando o gerenc. de download precisar de mais espaço."</string>
<string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"fazer download de arquivos sem notificação"</string>
- <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Permite que o aplicativo faça download de arquivos por meio do gerenciador de download sem exibir notificações ao usuário."</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Permite que o app faça download de arquivos por meio do gerenciador de download sem exibir notificações ao usuário."</string>
<string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Acessar todos os downloads do sistema"</string>
- <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Permite que o aplicativo visualize e modifique todos os downloads iniciados por qualquer aplicativo no sistema."</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Permite que o app visualize e modifique todos os downloads iniciados por qualquer app no sistema."</string>
<string name="download_unknown_title" msgid="7015124071247271585">"&lt;Sem título&gt;"</string>
<string name="notification_download_complete" msgid="5443563299253103667">"Download concluído."</string>
<string name="notification_download_failed" msgid="8612136111952014978">"Falha no download."</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 80c39242..81e99ecf 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -26,8 +26,8 @@
<string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"Отслеживать все загрузки на USB-накопитель"</string>
<string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"Просмотреть все загрузки на SD-карту"</string>
<string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Приложение получит доступ ко всем загрузкам на SD-карте независимо от того, через какое ПО они были загружены."</string>
- <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Резервировать место в кэше загрузки"</string>
- <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Приложение сможет загружать файлы в кэш загрузки (который не может быть автоматически очищен), если менеджеру загрузки потребуется больше места."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Резервировать место в кеше загрузки"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Приложение сможет загружать файлы в кеш загрузки (который не может быть автоматически очищен), если менеджеру загрузки потребуется больше места."</string>
<string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"Загрузка файлов без оповещения"</string>
<string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Приложение сможет загружать файлы через диспетчер загрузок без уведомления пользователя."</string>
<string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Доступ ко всем загрузкам"</string>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
new file mode 100644
index 00000000..bbe85277
--- /dev/null
+++ b/res/values-si-rLK/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"බාගැනීමේ කළමනාකරු"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"බාගැනීම් කළමනාකරු ප්‍රවේශ කරන්න."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"යෙදුම් හට මෙය භාවිතා කර බාගැනීම් කළමනාකරු ප්‍රවේශ කර ගොනු බාගැනීමට අවසර දෙන්න. කරදරකාරී යෙදුම් හට මෙය භාවිතා කර බාගැනීම් වලට බාධා පමුණුවා පෞද්ගලික තොරතුරු ප්‍රවේශ කිරීමට යොදාගත හැක."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"උසස් බාගැනීම් කළමනාකරු විශේෂාංග."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"යෙදුම් හට මෙය භාවිතා කර බාගැනීම් කළමනාකරුගේ උසස් විශේෂාංග ප්‍රවේශ කර ගොනු බාගැනීමට අවසර දෙන්න. කරදරකාරී යෙදුම් හට මෙය භාවිතා කර බාගැනීම් වලට බාධා පමුණුවා පෞද්ගලික තොරතුරු ප්‍රවේශ කිරීමට යොදාගත හැක."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"බාගැනීමේ දැනුම්දීම් යවන්න."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"සම්පුර්ණ වූ බාගැනීම් පිලිබඳ දැනුම්දීම් යැවීමට යෙදුමට අවසර දෙන්න. කරදරකාරී යෙදුම් වලට මෙය යොදාගනිමින් ගොනු බාගත කරන වෙනත් යෙදුම් අමාරුවේ දැමිය හැක."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB ආචයනය වෙත සියලු බාගැනීම් බලන්න"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD පත වෙත සියලු බාගැනීම් බලන්න"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"බාගත්තේ කුමන යෙදුමද යන්න සැලකිල්ලට නොගෙන, SD කාඩ්පත වෙත සියලු බාගැනීම් බැලීමට යෙදුමට අවසර දෙන්න."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"බාගැනීම් හැඹිලියේ ඉඩ වෙන් කරගන්න"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"යෙදුමට ගොනු බාගැනීමේ හැඹිලියට බාගැනීමට අවසර දෙන්න, එය බාගැනීමේ කළමනාකරුට තවත් ඉඩ අවශ්‍ය වූ විට ස්වයංක්‍රීයව මැකිය නොහැක."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"දැනුම්දීමකින් තොරව ගොනු බාගන්න"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"පරිශීලකයාට කිසිඳු දැනුම්දීමක් කිරීමකින් තොරව බාගැනීම් කළමනාකරු හරහා ගොනු බාගත කරගැනීමට යෙදුමට අවසර දෙන්න."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"සියලු පද්ධති බාගැනීම් ප්‍රවේශ කරන්න"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"පද්ධතියේ ඕනෑම යෙදුමකින් ආරම්භ කරන ලද සියලු බාගැනීම් දර්ශනය කිරීමට සහ වෙනස් කිරීමට යෙදුමට අවසර දෙන්න."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;නම් නොකළ&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"බාගැනීම සම්පූර්ණයි."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"බාගැනීම අසාර්ථකයි."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"බාගැනීමේ ප්‍රමාණයට Wi-Fi අවශ්‍යවේ."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"පසුබිමේ නවතා ඇත."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"ක්‍රියාකරු ජාලයට බාගැනීම විශාල වැඩිය"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"මෙම <xliff:g id="SIZE">%s </xliff:g> බාගැනීම සිදු කිරීමට ඔබ Wi-Fi භාවිතා කළ යුතුය. \n\nඔබ මීළඟට WiFi ජාලයකට සම්බන්ධ වූ පසු බාගැනීම ආරම්භ කිරීමට පහත <xliff:g id="QUEUE_TEXT">%s </xliff:g> ස්පර්ශ කරන්න."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"පසුව බාගැනීමට පෝලිමේ තබන්නද?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"මෙම <xliff:g id="SIZE">%s </xliff:g> බාගැනීම දැන් ආරම්භ කිරීමෙන් ඔබගේ බැටරි ආයු කාලය අඩුවේ සහ/හෝ ඔබගේ ජංගම දත්ත සම්බන්ධතාවය භාවිතය අධික වේ, එය ඔබගේ දත්ත සැලසුමට අනුව විශාල ගෙවීමක් සිදුවිය හැක.\n\n ඔබ මීළඟට WiFi ජාලයකට සම්බන්ධ වූ පසු බාගැනීම ආරම්භ කිරීමට පහත <xliff:g id="QUEUE_TEXT">%s</xliff:g> ස්පර්ශ කරන්න."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"පෝලිම"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"අවලංගු කරන්න"</string>
+ <string name="button_start_now" msgid="792123674007840864">"දැන් අරඹන්න"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"ගොනු 1 ක් බාගත වෙමින්"</item>
+ <item quantity="other" msgid="9087228371320573153">"ගොනු <xliff:g id="NUMBER">%d</xliff:g> බාගත වෙමින්"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"ගොනු 1 රැඳී සිටිමින්"</item>
+ <item quantity="other" msgid="549229034166062887">"ගොනු <xliff:g id="NUMBER">%d</xliff:g> රැඳී සිටිමින්"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> ඉතිරියි"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"ගොනුව විවෘත කළ නොහැකි විය"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"බාගැනීම්"</string>
+ <string name="download_queued" msgid="3302638231377947451">"පෙළ ගසන ලදි"</string>
+ <string name="download_running" msgid="3925050393361158266">"ක්‍රියාවේ පවතී"</string>
+ <string name="download_error" msgid="5144180777324573236">"අසාර්ථකයි"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"ක්‍රියාවේ පවතී, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 79e772fb..21329261 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -18,20 +18,20 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3658948994665187911">"Upravitelj prenosov"</string>
<string name="permlab_downloadManager" msgid="7779544811202855500">"Dostop do upravitelja prenosov."</string>
- <string name="permdesc_downloadManager" msgid="4237406545998908947">"Dovoli programu dostopanje do upravitelja prenosov in njegovo uporabo za prenos datotek. Zlonamerni programi lahko s tem motijo prenose in dostopajo do zasebnih podatkov."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"Dovoli aplikaciji dostopanje do upravitelja prenosov in njegovo uporabo za prenos datotek. Zlonamerne aplikacije lahko s tem motijo prenose in dostopajo do zasebnih podatkov."</string>
<string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Dodatne funkcije upravitelja prenosov."</string>
- <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Dovoli programu dostopanje do dodatnih funkcij upravitelja prenosov. Zlonamerni programi lahko s tem motijo prenose in dostopajo do zasebnih podatkov."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Dovoli aplikaciji dostopanje do dodatnih funkcij upravitelja prenosov. Zlonamerne aplikacije lahko s tem motijo prenose in dostopajo do zasebnih podatkov."</string>
<string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Pošlji obvestila o prenosih."</string>
- <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Dovoli programu pošiljanje obvestil o končanih prenosih. Zlonamerni programi lahko s tem zmedejo druge programe, ki prenašajo datoteke."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Dovoli aplikaciji pošiljanje obvestil o končanih prenosih. Zlonamerne aplikacije lahko s tem zmedejo druge aplikacije, ki prenašajo datoteke."</string>
<string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"Prikaži vse prenose v pomnilnik USB"</string>
<string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"Prikaži vse prenose na kartico SD"</string>
- <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Dovoli programu ogled vseh prenosov na kartico SD ne glede na to, kateri program jih je prenesel."</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Dovoli aplikaciji ogled vseh prenosov na kartico SD ne glede na to, katera aplikacija jih je prenesla."</string>
<string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Rezerviraj prostor v predpomnilniku za prenose"</string>
- <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Dovoli programu prenašanje datotek v predpomnilnik za prenose, ki ga ni mogoče samodejno izbrisati, ko upravitelj prenosov potrebuje več prostora."</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Dovoli aplikaciji prenašanje datotek v predpomnilnik za prenose, ki ga ni mogoče samodejno izbrisati, ko upravitelj prenosov potrebuje več prostora."</string>
<string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"prenos datotek brez obvestila"</string>
- <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Dovoli programu prenos datotek z upraviteljem prenosov, brez prikaza obvestila uporabniku."</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Dovoli aplikaciji prenos datotek z upraviteljem prenosov, brez prikaza obvestila uporabniku."</string>
<string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Dostop do vseh sistemskih prenosov"</string>
- <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Dovoli programu prikaz in spreminjanje vseh prenosov, ki jih je začel poljubni program v sistemu."</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Dovoli aplikaciji prikaz in spreminjanje vseh prenosov, ki jih je začela poljubna aplikacija v sistemu."</string>
<string name="download_unknown_title" msgid="7015124071247271585">"&lt;Brez naslova&gt;"</string>
<string name="notification_download_complete" msgid="5443563299253103667">"Prenos je končan."</string>
<string name="notification_download_failed" msgid="8612136111952014978">"Prenos ni uspel."</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index f5758dbf..0ccbd6a8 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -53,7 +53,7 @@
<item quantity="one" msgid="5537481763963544278">"Faili 1 inasubiri"</item>
<item quantity="other" msgid="549229034166062887">"Faili <xliff:g id="NUMBER">%d</xliff:g> zinasubiri"</item>
</plurals>
- <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> zinazosalia"</string>
+ <string name="download_remaining" msgid="3139295890887972718">"Zimesalia <xliff:g id="DURATION">%s</xliff:g>"</string>
<string name="download_no_application_title" msgid="7935659741162801699">"Haiwezi kufungua faili"</string>
<string name="root_downloads" msgid="4098414876292351487">"Vipakuliwa"</string>
<string name="download_queued" msgid="3302638231377947451">"Zilizowekwa kwenye foleni"</string>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
new file mode 100644
index 00000000..de1eb488
--- /dev/null
+++ b/res/values-ta-rIN/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"பதிவிறக்க நிர்வாகி"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"பதிவிறக்க நிர்வாகியை அணுகவும்."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"பதிவிறக்க நிர்வாகியை அணுகவும், கோப்புகளைப் பதிவிறக்குவதற்காக அதைப் பயன்படுத்தவும் பயன்பாட்டை அனுமதிக்கிறது. பதிவிறக்கங்களைத் தடைசெய்யவும், தனிப்பட்டத் தகவலை அணுகவும் தீங்கிழைக்கும் பயன்பாடுகள் இதைப் பயன்படுத்தலாம்."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"மேம்பட்ட பதிவிறக்க நிர்வாகி செயல்பாடுகள்."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"பதிவிறக்க நிர்வாகியின் மேம்பட்ட செயல்பாடுகளை அணுகுவதற்குப் பயன்பாட்டை அனுமதிக்கிறது. பதிவிறக்கங்களைத் தடைசெய்யவும், தனிப்பட்டத் தகவலை அணுகவும் தீங்கிழைக்கும் பயன்பாடுகள் இதைப் பயன்படுத்தலாம்."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"பதிவிறக்க அறிவிப்புகளை அனுப்பவும்."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"முடிந்த பதிவிறக்கங்கள் குறித்த அறிவிப்புகளை அனுப்புவதற்குப் பயன்பாட்டை அனுமதிக்கிறது. கோப்புகளைப் பதிவிறக்கும் பிற பயன்பாடுகளைக் குழப்புவதற்கு தீங்கிழைக்கும் பயன்பாடுகள் இதைப் பயன்படுத்தலாம்."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB சேமிப்பிடத்தில் உள்ள எல்லா பதிவிறக்கங்களையும் பார்த்தல்"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD கார்டில் உள்ள எல்லா பதிவிறக்கங்களையும் பார்த்தல்"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"எந்த பயன்பாடு பதிவிறக்கியது என்பதைப் பொருட்படுத்தாமல் SD கார்டில் உள்ள எல்லா பதிவிறக்கங்களையும் பார்க்க பயன்பாட்டை அனுமதிக்கிறது."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"தற்காலிகச் சேமிப்பில் இடத்தை முன்பதிவு செய்தல்"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"பதிவிறக்க நிர்வாகிக்கு அதிகப்படியான இடம் தேவைப்படும்போது தானாகவே நீக்கப்படாத, தற்காலிகச் சேமிப்பில் கோப்புகளைப் பதிவிறக்க பயன்பாட்டை அனுமதிக்கிறது."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"அறிவிப்பு இல்லாமல் கோப்புகளைப் பதிவிறக்குதல்"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"எந்த அறிவிப்பையும் பயனருக்குக் காட்டாமல் பதிவிறக்க நிர்வாகியின் மூலம் கோப்புகளைப் பதிவிறக்கப் பயன்பாட்டை அனுமதிக்கிறது."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"அமைப்பின் எல்லா பதிவிறக்கங்களையும் அணுகுதல்"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"அமைப்பில் உள்ள எந்தப் பயன்பாட்டினாலும் தொடங்கப்படும் எல்லா பதிவிறக்கங்களையும் கண்டு மாற்றுவதற்குப் பயன்பாட்டை அனுமதிக்கிறது."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;பெயரிடப்படாதது&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"பதிவிறக்கம் முடிந்தது."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"பதிவிறக்கம் தோல்வி."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"பதிவிறக்க அளவு வைஃபைக்குத் தேவை."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"பின்புலத்தில் இடைநிறுத்தப்பட்டது."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"ஆபரேட்டர் நெட்வொர்க்கில் மிக அதிக அளவில் பதிவிறக்கப்படுகிறது"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"<xliff:g id="SIZE">%s </xliff:g> பதிவிறக்கத்தை முடிக்க நீங்கள் வைஃபை ஐப் பயன்படுத்த வேண்டும். \n\nஅடுத்த முறை நீங்கள் வைஃபை நெட்வொர்க்குடன் இணைந்தவுடன் பதிவிறக்கத்தைத் தொடங்குவதற்கு <xliff:g id="QUEUE_TEXT">%s </xliff:g> ஐத் தொடவும்."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"பின்னர் பதிவிறக்க வரிசைப்படுத்தவா?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"<xliff:g id="SIZE">%s </xliff:g> அளவிலான இந்தப் பதிவிறக்கத்தை இப்போது தொடங்குவது உங்கள் பேட்டரியின் ஆயுளைக் குறைக்கலாம் மற்றும்/அல்லது உங்கள் மொபைல் தரவு இணைப்பை அதிகமாகப் பயன்படுத்த நேரிடலாம், இதன் காரணமாக உங்கள் தரவு திட்டத்தைப் பொறுத்து உங்கள் மொபைல் ஆபரேட்டர் கட்டணங்கள் விதிக்கலாம்.\n\nஅடுத்த முறை நீங்கள் வைஃபை நெட்வொர்க்கில் இணைந்தவுடன் இந்தப் பதிவிறக்கத்தைத் தொடங்குவதற்கு <xliff:g id="QUEUE_TEXT">%s</xliff:g> ஐத் தொடவும்."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"வரிசை"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"ரத்துசெய்"</string>
+ <string name="button_start_now" msgid="792123674007840864">"இப்போது தொடங்கு"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"1 கோப்புப் பதிவிறக்கப்படுகிறது"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> கோப்புகள் பதிவிறக்கப்படுகின்றன"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 கோப்பு காத்திருக்கிறது"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> கோப்புகள் காத்திருக்கின்றன"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> மீதமுள்ளது"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"கோப்பைத் திறக்க முடியவில்லை"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"பதிவிறக்கங்கள்"</string>
+ <string name="download_queued" msgid="3302638231377947451">"வரிசைப்படுத்தப்பட்டது"</string>
+ <string name="download_running" msgid="3925050393361158266">"செயலிலுள்ளது"</string>
+ <string name="download_error" msgid="5144180777324573236">"தோல்வி"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"செயலிலுள்ளது, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
new file mode 100644
index 00000000..548f4357
--- /dev/null
+++ b/res/values-te-rIN/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"డౌన్‌లోడ్ నిర్వాహికి"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"డౌన్‌లోడ్ నిర్వాహికిని ప్రాప్యత చేయండి."</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"డౌన్‌లోడ్ నిర్వాహికిని ప్రాప్యత చేయడానికి మరియు దీన్ని ఉపయోగించి ఫైల్‌లను డౌన్‌లోడ్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. హానికరమైన అనువర్తనాలు డౌన్‌లోడ్‌లకు అంతరాయం కలిగించడానికి మరియు ప్రైవేట్ సమాచారాన్ని ప్రాప్యత చేయడానికి దీన్ని ఉపయోగించవచ్చు."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"అధునాతన డౌన్‌లోడ్ నిర్వాహికి ఫంక్షన్‌లు."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"డౌన్‌లోడ్ నిర్వాహికి యొక్క అధునాతన ఫంక్షన్‌లను ప్రాప్యత చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. హానికరమైన అనువర్తనాలు డౌన్‌లోడ్‌లకు అంతరాయం కలిగించడానికి మరియు ప్రైవేట్ సమాచారాన్ని ప్రాప్యత చేయడానికి దీన్ని ఉపయోగించవచ్చు."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"డౌన్‌లోడ్ నోటిఫికేషన్‌లను పంపండి."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"పూర్తయిన డౌన్‌లోడ్‌ల గురించి నోటిఫికేషన్‌లను పంపడానికి అనువర్తనాన్ని అనుమతిస్తుంది. హానికరమైన అనువర్తనాలు ఫైల్‌లను డౌన్‌లోడ్ చేసే ఇతర అనువర్తనాలను తప్పుదారి పట్టించేందుకు దీన్ని ఉపయోగించవచ్చు."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB నిల్వకి చేయబడిన అన్ని డౌన్‌లోడ్‌లను చూడటం"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD కార్డుకి చేయబడిన అన్ని డౌన్‌లోడ్‌లను చూడటం"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"SD కార్డుకు చేయబడిన అన్ని డౌన్‌లోడ్‌లను వాటిని ఏ అనువర్తనం డౌన్‌లోడ్ చేసిందనే దానితో సంబంధం లేకుండా చూడటానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"డౌన్‌లోడ్ కాష్‌లో స్థలాన్ని నిల్వ చేయడం"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"డౌన్‌లోడ్ కాష్‌కు ఫైల్‌లను డౌన్‌లోడ్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది, డౌన్‌లోడ్ నిర్వాహికికి మరింత స్థలం అవసరమైనప్పుడు అవి స్వయంచాలకంగా తొలగించబడవు."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"నోటిఫికేషన్ లేకుండానే ఫైల్‌లను డౌన్‌లోడ్ చేయడం"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"వినియోగదారుకి ఎటువంటి నోటిఫికేషన్‌ను చూపకుండానే డౌన్‌లోడ్ నిర్వాహికి ద్వారా ఫైల్‌లను డౌన్‌లోడ్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"అన్ని సిస్టమ్ డౌన్‌లోడ్‌లను ప్రాప్యత చేయడం"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"సిస్టమ్‌లో ఏదైనా అనువర్తనం ద్వారా ప్రారంభించబడిన అన్ని డౌన్‌లోడ్‌లను వీక్షించడానికి మరియు సవరించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;శీర్షిక లేనిది&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"డౌన్‌లోడ్ పూర్తయింది."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"డౌన్‌లోడ్ విఫలమైంది."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"డౌన్‌లోడ్ పరిమాణానికి Wi-Fi అవసరం."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"నేపథ్యంలో పాజ్ చేయబడింది."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"ఆపరేటర్ నెట్‌వర్క్‌‌కు డౌన్‌లోడ్ చాలా పెద్దదిగా ఉంది"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"మీరు ఈ <xliff:g id="SIZE">%s </xliff:g> డౌన్‌లోడ్‌ను పూర్తి చేయడానికి తప్పనిసరిగా Wi-Fiని ఉపయోగించాలి. \n\nమీరు Wi-Fi నెట్‌వర్క్‌కు కనెక్ట్ చేసిన తదుపరి సారి ఈ డౌన్‌లోడ్‌ను ప్రారంభించడానికి <xliff:g id="QUEUE_TEXT">%s </xliff:g>ని తాకండి."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"తర్వాత డౌన్‌లోడ్ చేయడం కోసం క్రమవరుసలో ఉంచాలా?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"ఇప్పుడు ఈ <xliff:g id="SIZE">%s </xliff:g> డౌన్‌లోడ్‌ను ప్రారంభించడం వలన మీ బ్యాటరీ శక్తి తగ్గవచ్చు మరియు/లేదా మీ మొబైల్ డేటా కనెక్షన్ అత్యధికంగా వినియోగించబడవచ్చు, దీని వలన మీ డేటా ప్లాన్ ఆధారంగా మీ మొబైల్ ఆపరేటర్ ఛార్జీలు విధించవచ్చు.\n\n మీరు Wi-Fi నెట్‌వర్క్‌కు కనెక్ట్ చేసిన తదుపరి సారి ఈ డౌన్‌లోడ్‌ను ప్రారంభించడానికి <xliff:g id="QUEUE_TEXT">%s</xliff:g>ని తాకండి."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"క్రమవరుసలో ఉంచు"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"రద్దు చేయి"</string>
+ <string name="button_start_now" msgid="792123674007840864">"ఇప్పుడే ప్రారంభించు"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"1 ఫైల్‌ను డౌన్‌లోడ్ చేస్తోంది"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> ఫైల్‌లను డౌన్‌లోడ్ చేస్తోంది"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 ఫైల్ వేచి ఉంది"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> ఫైల్‌లు వేచి ఉన్నాయి"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> మిగిలి ఉంది"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"ఫైల్‌ను తెరవడం సాధ్యపడదు"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"డౌన్‌లోడ్‌లు"</string>
+ <string name="download_queued" msgid="3302638231377947451">"క్రమవరుసలో ఉంచబడింది"</string>
+ <string name="download_running" msgid="3925050393361158266">"ప్రోగ్రెస్‌లో ఉంది"</string>
+ <string name="download_error" msgid="5144180777324573236">"విఫలమైంది"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"ప్రోగ్రెస్‌లో ఉంది, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
new file mode 100644
index 00000000..a7942269
--- /dev/null
+++ b/res/values-ur-rPK/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"ڈاؤن لوڈ مینیجر"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"ڈاؤن لوڈ مینیجر تک رسائی حاصل کریں۔"</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"ایپ کو ڈاؤن لوڈ مینیجر تک رسائی حاصل کرنے اور فائلیں ڈاؤن لوڈ کرنے کیلئے اسے استعمال کرنے کی اجازت دیتا ہے۔ نقصان دہ ایپس ڈاؤن لوڈز کو معطل کرنے اور نجی معلومات تک رسائی حاصل کرنے کیلئے اس کا استعمال کر سکتی ہیں۔"</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"ڈاؤن لوڈ مینیجر کے جدید فنکشنز۔"</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"ایپ کو ڈاؤن لوڈ مینیجر کے جدید فنکشنز تک رسائی کی اجازت دیتا ہے۔ نقصان دہ ایپس ڈاؤن لوڈز کو معطل کرنے اور نجی معلومات تک رسائی حاصل کرنے کیلئے اس کا استعمال کر سکتی ہیں۔"</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"ڈاؤن لوڈ اطلاعات بھیجیں۔"</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"ایپ کو مکمل ڈاؤن لوڈز کے بارے میں اطلاعات بھیجنے کی اجازت دیتا ہے۔ نقصان دہ ایپس فائلیں ڈاؤن لوڈ کرنے والی دیگر ایپس کو الجھانے کیلئے اس کا استعمال کر سکتی ہیں۔"</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"‏USB سٹوریج کے سب ڈاؤنلوڈز دیکھیں"</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"‏SD کارڈ میں سبھی ڈاؤن لوڈز کو دیکھیں"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"‏ایپ کو SD کارڈ میں سبھی ڈاؤن لوڈز کو دیکھنے کی اجازت دیتا ہے، اس سے قطع نظر کہ کس ایپ نے ان کو ڈاؤن لوڈ کیا ہے۔"</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"ڈاؤن لوڈ کیش میں جگہ محفوظ کریں"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"ایپ کو ڈاؤن لوڈ کیش میں فائلیں ڈاؤن لوڈ کرنے کی اجازت دیتا ہے، جسے ڈاؤن لوڈ مینیجر کو مزید جگہ درکار ہونے پر خود کار طور پر حذف نہیں کیا جا سکتا ہے۔"</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"بغیر اطلاع کے فائلیں ڈاؤن لوڈ کریں"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"صارف کو کوئی اطلاع دکھائے بغیر ایپ کو ڈاؤن لوڈ مینیجر کے ذریعے فائلیں ڈاؤن لوڈ کرنے کی اجازت دیتا ہے۔"</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"سسٹم کے سبھی ڈاؤن لوڈز تک رسائی حاصل کریں"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"ایپ کو سسٹم پر کسی بھی ایپ کے ذریعے شروع کیے گئے سبھی ڈاؤن لوڈز کو دیکھنے اور ان میں ترمیم کرنے کی اجازت دیتا ہے۔"</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"‏‎&gt;‎بلا عنوان‎&lt;‎"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"ڈاؤن لوڈ مکمل ہو گیا۔"</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"ڈاؤن لوڈ ناکام ہو گیا۔"</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"‏ڈاؤنلوڈ کیلئے Wi-Fi درکار ہے۔"</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"پس منظر میں موقوف ہوگیا۔"</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"آپریٹر نیٹ ورک کیلئے ڈاؤن لوڈ کافی بڑا ہے"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"‏اس <xliff:g id="SIZE">%s </xliff:g> ڈاؤن لوڈ کو مکمل کرنے کیلئے آپ کیلئے Wi-Fi استعمال کرنا ضروری ہے۔ \n\n<xliff:g id="QUEUE_TEXT">%s </xliff:g> کو ٹچ کریں تاکہ اگلی بار جب آپ کسی Wi-Fi نیٹ ورک سے مربوط ہوں تو یہ ڈاؤن لوڈ شروع کر سکیں۔"</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"بعد میں ڈاؤن لوڈ کرنے کیلئے قطار میں شامل ہوں؟"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"‏اس <xliff:g id="SIZE">%s </xliff:g> کے ڈاؤن لوڈ کو شروع کرنے سے آپکی بیٹری کی مدت میں کمی آسکتی ہے اور/یا اس سے آپ کے موبائل ڈیٹا کنکشن کا بہت زیادہ استعمال ہو سکتا ہے جسکی وجہ سے آپکا موبائل آپریٹر آپکے ڈیٹا پلان کے مطابق چارجز عائد کرسکتا ہے۔\n\n اگلی بار کسی Wi-Fi نیٹ ورک سے مربوط ہونے پر یہ ڈاؤن لوڈ شروع کرنے کیلئے <xliff:g id="QUEUE_TEXT">%s</xliff:g> کو ٹچ کریں۔"</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"قطار"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"منسوخ کریں"</string>
+ <string name="button_start_now" msgid="792123674007840864">"ابھی شروع کریں"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"1 فائل ڈاؤن لوڈ ہو رہی ہے"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> فائلیں ڈاؤن لوڈ ہو رہی ہیں"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 فائل منتظر ہے"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> فائلیں منتظر ہیں"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> باقی"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"فائل نہيں کھول سکتے ہیں"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"ڈاؤن لوڈز"</string>
+ <string name="download_queued" msgid="3302638231377947451">"قطار بند"</string>
+ <string name="download_running" msgid="3925050393361158266">"پیشرفت میں ہے"</string>
+ <string name="download_error" msgid="5144180777324573236">"ناکام"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"پیشرفت میں، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
new file mode 100644
index 00000000..70b9d978
--- /dev/null
+++ b/res/values-uz-rUZ/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3658948994665187911">"Yuklab olish menejeri"</string>
+ <string name="permlab_downloadManager" msgid="7779544811202855500">"Yuklab olish menejeriga kirishga ruxsat"</string>
+ <string name="permdesc_downloadManager" msgid="4237406545998908947">"Ilovaga yuklab olish menejeriga kirish va yuklab olish fayllaridan foydalanish uchun ruxsat beradi. Zararli dasturlar bundan yuklab olishlarga to‘sqinlik qilish va maxfiy ma’lumotlarga kirish uchun foydalanishi mumkin."</string>
+ <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Qo‘shimcha yuklab olish menejeri funksiyalari."</string>
+ <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Ilovaga yuklab olish menejerining qo‘shimcha funksiyalariga kirish uchun ruxsat beradi. Zararli dasturlar bundan yuklab olishlarga to‘sqinlik qilish va maxfiy ma’lumotlarga kirish uchun foydalanishi mumkin."</string>
+ <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Yuklab olish xabarnomalarini jo‘natadi."</string>
+ <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Ilovaga tugagan yuklab olishlar haqidagi xabarnomalarini jo‘natishga ruxsat beradi. Zararli dasturlar bundan yuklab olinayotgan fayllarni boshqalari bilan chalkashtirish uchun foydalanishi mumkin."</string>
+ <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"USB’dagi yuk. olish ko‘r."</string>
+ <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"SD xotira kartasidagi barcha yuklab olishlarni ko‘rish"</string>
+ <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Ilovaga qaysi ilovalar fayllarni SD xotira kartasiga yuklab olganidan qat’iy nazar, undagi barcha fayllarni ko‘rishga ruxsat beradi."</string>
+ <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Yuklab olish keshida joy qoldirish"</string>
+ <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Yuklashlar menejeriga ko‘proq bo‘sh joy kerak bo‘lganda avtomatik o‘chirilmaydigan fayllarni yuklab olish keshiga yuklab olish uchun ilovaga ruxsat beradi."</string>
+ <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"fayllarni ogohlantirishsiz yuklab olish"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Foydalanuvchini hech qanday ogohlantirmasdan Ilovaga yuklab olish menejeri orqali fayllar yuklab olish uchun ruxsat beradi."</string>
+ <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Tizimdagi barcha yuklab olishlariga ruxsat berish"</string>
+ <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Ilovaga tizimda har qanday ilova tomonidan ishga tushirilgan barcha yuklanishlarni ko‘rish va o‘zgartirish uchun ruxsat beradi."</string>
+ <string name="download_unknown_title" msgid="7015124071247271585">"&lt;Sarlavhasiz&gt;"</string>
+ <string name="notification_download_complete" msgid="5443563299253103667">"Yuklab olish tugadi."</string>
+ <string name="notification_download_failed" msgid="8612136111952014978">"Yuklab olish muvaffaqiyatsiz yakunlandi."</string>
+ <string name="notification_need_wifi_for_size" msgid="2556172885154833575">"Katta hajmni yuklab olish uchun Wi-Fi kerak."</string>
+ <string name="notification_paused_in_background" msgid="4328508073283591772">"Orqa fonda pauzalangan."</string>
+ <string name="wifi_required_title" msgid="1995971416871498179">"Tarmoq operatori aloqasi orqali yuklab olish uchun fayl hajmi katta"</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"Ushbu <xliff:g id="SIZE">%s </xliff:g> hajmdagi yuklab olishni tugatish uchun Wi-Fi tarmoqdan foydalanishingiz kerak. \n\nKeyingi safar Wi-Fi tarmoqqa ulanganingizda yuklab olishni boshlash uchun <xliff:g id="QUEUE_TEXT">%s </xliff:g>ni bosing."</string>
+ <string name="wifi_recommended_title" msgid="7441589306734687400">"Keyinroq yuklab olish uchun navbatga qo‘shilsinmi?"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"Ushbu <xliff:g id="SIZE">%s </xliff:g> hajmdagi yuklab olishni boshlash batareya quvvatini kamaytirishi va/yoki uyali aloqa internetidan juda ko‘p foydalanib, natijada internet paketingizga ko‘ra uyali tarmoq operatoringiz tomonidan sizdan ortiqcha haq talab qilinishiga sabab bo‘lishi mumkin. \n\n Keyingi safar Wi-Fi tarmoqqa ulanganingizda yuklab olishni boshlash uchun <xliff:g id="QUEUE_TEXT">%s</xliff:g>ni tanlang."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"Navbat"</string>
+ <string name="button_cancel_download" msgid="2430166148737975604">"Bekor qilish"</string>
+ <string name="button_start_now" msgid="792123674007840864">"Hozir boshlash"</string>
+ <string name="download_percent" msgid="6889426633242976698">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <plurals name="notif_summary_active">
+ <item quantity="one" msgid="8475775855911967027">"1 ta fayl yuklab olinmoqda"</item>
+ <item quantity="other" msgid="9087228371320573153">"<xliff:g id="NUMBER">%d</xliff:g> ta fayl yuklab olinmoqda"</item>
+ </plurals>
+ <plurals name="notif_summary_waiting">
+ <item quantity="one" msgid="5537481763963544278">"1 fayl navbatda"</item>
+ <item quantity="other" msgid="549229034166062887">"<xliff:g id="NUMBER">%d</xliff:g> fayl navbatda"</item>
+ </plurals>
+ <string name="download_remaining" msgid="3139295890887972718">"<xliff:g id="DURATION">%s</xliff:g> o‘tib ketdi"</string>
+ <string name="download_no_application_title" msgid="7935659741162801699">"Fayl ochilmadi"</string>
+ <string name="root_downloads" msgid="4098414876292351487">"Yuklab olinganlar"</string>
+ <string name="download_queued" msgid="3302638231377947451">"Navbatga qo‘shildi"</string>
+ <string name="download_running" msgid="3925050393361158266">"Yuklab olinmoqda"</string>
+ <string name="download_error" msgid="5144180777324573236">"Muvaffaqiyatsiz"</string>
+ <string name="download_running_percent" msgid="4529799113107391817">"Yuklab olinmoqda, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 6e04391b..7a0b89c8 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -29,7 +29,7 @@
<string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"在下載快取預留空間"</string>
<string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"允許應用程式將檔案下載至下載快取空間,確保檔案不會因為下載管理員需要更多空間而自動遭到刪除。"</string>
<string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"不顯示通知,直接下載檔案"</string>
- <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"允許應用程式不需通知用戶,即可透過下載管理員下載檔案。"</string>
+ <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"允許應用程式不需通知使用者,即可透過下載管理員下載檔案。"</string>
<string name="permlab_accessAllDownloads" msgid="2436240495424393717">"存取所有系統下載檔案"</string>
<string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"允許應用程式查看及修改系統上任何應用程式下載的所有內容。"</string>
<string name="download_unknown_title" msgid="7015124071247271585">"&lt;未命名&gt;"</string>
diff --git a/src/com/android/providers/downloads/Constants.java b/src/com/android/providers/downloads/Constants.java
index 89210a25..7b8fcd24 100644
--- a/src/com/android/providers/downloads/Constants.java
+++ b/src/com/android/providers/downloads/Constants.java
@@ -45,9 +45,6 @@ public class Constants {
/** The column that is used for the initiating app's UID */
public static final String UID = "uid";
- /** The column that is used to remember whether the media scanner was invoked */
- public static final String MEDIA_SCANNED = "scanned";
-
/** The intent that gets sent when the service must wake up for a retry */
public static final String ACTION_RETRY = "android.intent.action.DOWNLOAD_WAKEUP";
@@ -80,9 +77,6 @@ public class Constants {
*/
public static final String FILENAME_SEQUENCE_SEPARATOR = "-";
- /** Where we store downloaded files on the external storage */
- public static final String DEFAULT_DL_SUBDIR = "/" + Environment.DIRECTORY_DOWNLOADS;
-
/** A magic filename that is allowed to exist within the system cache */
public static final String RECOVERY_DIRECTORY = "recovery";
@@ -123,16 +117,13 @@ public class Constants {
public static final String MIMETYPE_APK = "application/vnd.android.package";
/** The buffer size used to stream the data */
- public static final int BUFFER_SIZE = 4096;
+ public static final int BUFFER_SIZE = 8192;
/** The minimum amount of progress that has to be done before the progress bar gets updated */
- public static final int MIN_PROGRESS_STEP = 4096;
+ public static final int MIN_PROGRESS_STEP = 65536;
/** The minimum amount of time that has to elapse before the progress bar gets updated, in ms */
- public static final long MIN_PROGRESS_TIME = 1500;
-
- /** The maximum number of rows in the database (FIFO) */
- public static final int MAX_DOWNLOADS = 1000;
+ public static final long MIN_PROGRESS_TIME = 2000;
/**
* The number of times that the download manager will retry its network
@@ -177,4 +168,9 @@ public class Constants {
public static final String STORAGE_AUTHORITY = "com.android.providers.downloads.documents";
public static final String STORAGE_ROOT_ID = "downloads";
+
+ /**
+ * Name of directory on cache partition containing in-progress downloads.
+ */
+ public static final String DIRECTORY_CACHE_RUNNING = "partial_downloads";
}
diff --git a/src/com/android/providers/downloads/DownloadIdleService.java b/src/com/android/providers/downloads/DownloadIdleService.java
new file mode 100644
index 00000000..b5371552
--- /dev/null
+++ b/src/com/android/providers/downloads/DownloadIdleService.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.providers.downloads;
+
+import static com.android.providers.downloads.Constants.TAG;
+import static com.android.providers.downloads.StorageUtils.listFilesRecursive;
+
+import android.app.DownloadManager;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.database.Cursor;
+import android.os.Environment;
+import android.provider.Downloads;
+import android.system.ErrnoException;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Slog;
+
+import com.android.providers.downloads.StorageUtils.ConcreteFile;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Sets;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+
+/**
+ * Idle-time service for {@link DownloadManager}. Reconciles database
+ * metadata and files on disk, which can become inconsistent when files are
+ * deleted directly on disk.
+ */
+public class DownloadIdleService extends JobService {
+
+ private class IdleRunnable implements Runnable {
+ private JobParameters mParams;
+
+ public IdleRunnable(JobParameters params) {
+ mParams = params;
+ }
+
+ @Override
+ public void run() {
+ cleanStale();
+ cleanOrphans();
+ jobFinished(mParams, false);
+ }
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ new Thread(new IdleRunnable(params)).start();
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ // We're okay being killed at any point, so we don't worry about
+ // checkpointing before tearing down.
+ return false;
+ }
+
+ private interface StaleQuery {
+ final String[] PROJECTION = new String[] {
+ Downloads.Impl._ID,
+ Downloads.Impl.COLUMN_STATUS,
+ Downloads.Impl.COLUMN_LAST_MODIFICATION,
+ Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI };
+
+ final int _ID = 0;
+ }
+
+ /**
+ * Remove stale downloads that third-party apps probably forgot about. We
+ * only consider non-visible downloads that haven't been touched in over a
+ * week.
+ */
+ public void cleanStale() {
+ final ContentResolver resolver = getContentResolver();
+
+ final long modifiedBefore = System.currentTimeMillis() - DateUtils.WEEK_IN_MILLIS;
+ final Cursor cursor = resolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
+ StaleQuery.PROJECTION, Downloads.Impl.COLUMN_STATUS + " >= '200' AND "
+ + Downloads.Impl.COLUMN_LAST_MODIFICATION + " <= '" + modifiedBefore
+ + "' AND " + Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI + " == '0'",
+ null, null);
+
+ int count = 0;
+ try {
+ while (cursor.moveToNext()) {
+ final long id = cursor.getLong(StaleQuery._ID);
+ resolver.delete(ContentUris.withAppendedId(
+ Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id), null, null);
+ count++;
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ Slog.d(TAG, "Removed " + count + " stale downloads");
+ }
+
+ private interface OrphanQuery {
+ final String[] PROJECTION = new String[] {
+ Downloads.Impl._ID,
+ Downloads.Impl._DATA };
+
+ final int _ID = 0;
+ final int _DATA = 1;
+ }
+
+ /**
+ * Clean up orphan downloads, both in database and on disk.
+ */
+ public void cleanOrphans() {
+ final ContentResolver resolver = getContentResolver();
+
+ // Collect known files from database
+ final HashSet<ConcreteFile> fromDb = Sets.newHashSet();
+ final Cursor cursor = resolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
+ OrphanQuery.PROJECTION, null, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ final String path = cursor.getString(OrphanQuery._DATA);
+ if (TextUtils.isEmpty(path)) continue;
+
+ final File file = new File(path);
+ try {
+ fromDb.add(new ConcreteFile(file));
+ } catch (ErrnoException e) {
+ // File probably no longer exists
+ final String state = Environment.getExternalStorageState(file);
+ if (Environment.MEDIA_UNKNOWN.equals(state)
+ || Environment.MEDIA_MOUNTED.equals(state)) {
+ // File appears to live on internal storage, or a
+ // currently mounted device, so remove it from database.
+ // This logic preserves files on external storage while
+ // media is removed.
+ final long id = cursor.getLong(OrphanQuery._ID);
+ Slog.d(TAG, "Missing " + file + ", deleting " + id);
+ resolver.delete(ContentUris.withAppendedId(
+ Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id), null, null);
+ }
+ }
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ // Collect known files from disk
+ final int uid = android.os.Process.myUid();
+ final ArrayList<ConcreteFile> fromDisk = Lists.newArrayList();
+ fromDisk.addAll(listFilesRecursive(getCacheDir(), null, uid));
+ fromDisk.addAll(listFilesRecursive(getFilesDir(), null, uid));
+ fromDisk.addAll(listFilesRecursive(Environment.getDownloadCacheDirectory(), null, uid));
+
+ Slog.d(TAG, "Found " + fromDb.size() + " files in database");
+ Slog.d(TAG, "Found " + fromDisk.size() + " files on disk");
+
+ // Delete files no longer referenced by database
+ for (ConcreteFile file : fromDisk) {
+ if (!fromDb.contains(file)) {
+ Slog.d(TAG, "Missing db entry, deleting " + file.file);
+ file.file.delete();
+ }
+ }
+ }
+}
diff --git a/src/com/android/providers/downloads/DownloadInfo.java b/src/com/android/providers/downloads/DownloadInfo.java
index 7a912d5a..2423c0d7 100644
--- a/src/com/android/providers/downloads/DownloadInfo.java
+++ b/src/com/android/providers/downloads/DownloadInfo.java
@@ -36,6 +36,7 @@ import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
+import java.io.CharArrayWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -45,7 +46,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
/**
- * Stores information about an individual download.
+ * Details about a specific download. Fields should only be mutated by updating
+ * from database query.
*/
public class DownloadInfo {
// TODO: move towards these in-memory objects being sources of truth, and
@@ -60,10 +62,9 @@ public class DownloadInfo {
mCursor = cursor;
}
- public DownloadInfo newDownloadInfo(Context context, SystemFacade systemFacade,
- StorageManager storageManager, DownloadNotifier notifier) {
- final DownloadInfo info = new DownloadInfo(
- context, systemFacade, storageManager, notifier);
+ public DownloadInfo newDownloadInfo(
+ Context context, SystemFacade systemFacade, DownloadNotifier notifier) {
+ final DownloadInfo info = new DownloadInfo(context, systemFacade, notifier);
updateFromDatabase(info);
readRequestHeaders(info);
return info;
@@ -75,7 +76,7 @@ public class DownloadInfo {
info.mNoIntegrity = getInt(Downloads.Impl.COLUMN_NO_INTEGRITY) == 1;
info.mHint = getString(Downloads.Impl.COLUMN_FILE_NAME_HINT);
info.mFileName = getString(Downloads.Impl._DATA);
- info.mMimeType = getString(Downloads.Impl.COLUMN_MIME_TYPE);
+ info.mMimeType = Intent.normalizeMimeType(getString(Downloads.Impl.COLUMN_MIME_TYPE));
info.mDestination = getInt(Downloads.Impl.COLUMN_DESTINATION);
info.mVisibility = getInt(Downloads.Impl.COLUMN_VISIBILITY);
info.mStatus = getInt(Downloads.Impl.COLUMN_STATUS);
@@ -93,7 +94,7 @@ public class DownloadInfo {
info.mCurrentBytes = getLong(Downloads.Impl.COLUMN_CURRENT_BYTES);
info.mETag = getString(Constants.ETAG);
info.mUid = getInt(Constants.UID);
- info.mMediaScanned = getInt(Constants.MEDIA_SCANNED);
+ info.mMediaScanned = getInt(Downloads.Impl.COLUMN_MEDIA_SCANNED);
info.mDeleted = getInt(Downloads.Impl.COLUMN_DELETED) == 1;
info.mMediaProviderUri = getString(Downloads.Impl.COLUMN_MEDIAPROVIDER_URI);
info.mIsPublicApi = getInt(Downloads.Impl.COLUMN_IS_PUBLIC_API) != 0;
@@ -206,6 +207,7 @@ public class DownloadInfo {
public long mId;
public String mUri;
+ @Deprecated
public boolean mNoIntegrity;
public String mHint;
public String mFileName;
@@ -254,14 +256,11 @@ public class DownloadInfo {
private final Context mContext;
private final SystemFacade mSystemFacade;
- private final StorageManager mStorageManager;
private final DownloadNotifier mNotifier;
- private DownloadInfo(Context context, SystemFacade systemFacade, StorageManager storageManager,
- DownloadNotifier notifier) {
+ private DownloadInfo(Context context, SystemFacade systemFacade, DownloadNotifier notifier) {
mContext = context;
mSystemFacade = systemFacade;
- mStorageManager = storageManager;
mNotifier = notifier;
mFuzz = Helpers.sRandom.nextInt(1001);
}
@@ -270,6 +269,14 @@ public class DownloadInfo {
return Collections.unmodifiableList(mRequestHeaders);
}
+ public String getUserAgent() {
+ if (mUserAgent != null) {
+ return mUserAgent;
+ } else {
+ return Constants.DEFAULT_USER_AGENT;
+ }
+ }
+
public void sendIntentIfRequested() {
if (mPackage == null) {
return;
@@ -329,7 +336,7 @@ public class DownloadInfo {
case Downloads.Impl.STATUS_WAITING_FOR_NETWORK:
case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
- return checkCanUseNetwork() == NetworkState.OK;
+ return checkCanUseNetwork(mTotalBytes) == NetworkState.OK;
case Downloads.Impl.STATUS_WAITING_TO_RETRY:
// download was waiting for a delayed restart
@@ -362,7 +369,7 @@ public class DownloadInfo {
/**
* Returns whether this download is allowed to use the network.
*/
- public NetworkState checkCanUseNetwork() {
+ public NetworkState checkCanUseNetwork(long totalBytes) {
final NetworkInfo info = mSystemFacade.getActiveNetworkInfo(mUid);
if (info == null || !info.isConnected()) {
return NetworkState.NO_CONNECTION;
@@ -376,7 +383,7 @@ public class DownloadInfo {
if (mSystemFacade.isActiveNetworkMetered() && !mAllowMetered) {
return NetworkState.TYPE_DISALLOWED_BY_REQUESTOR;
}
- return checkIsNetworkTypeAllowed(info.getType());
+ return checkIsNetworkTypeAllowed(info.getType(), totalBytes);
}
private boolean isRoamingAllowed() {
@@ -392,7 +399,7 @@ public class DownloadInfo {
* @param networkType a constant from ConnectivityManager.TYPE_*.
* @return one of the NETWORK_* constants
*/
- private NetworkState checkIsNetworkTypeAllowed(int networkType) {
+ private NetworkState checkIsNetworkTypeAllowed(int networkType, long totalBytes) {
if (mIsPublicApi) {
final int flag = translateNetworkTypeToApiFlag(networkType);
final boolean allowAllNetworkTypes = mAllowedNetworkTypes == ~0;
@@ -400,7 +407,7 @@ public class DownloadInfo {
return NetworkState.TYPE_DISALLOWED_BY_REQUESTOR;
}
}
- return checkSizeAllowedForNetwork(networkType);
+ return checkSizeAllowedForNetwork(networkType, totalBytes);
}
/**
@@ -427,24 +434,27 @@ public class DownloadInfo {
* Check if the download's size prohibits it from running over the current network.
* @return one of the NETWORK_* constants
*/
- private NetworkState checkSizeAllowedForNetwork(int networkType) {
- if (mTotalBytes <= 0) {
- return NetworkState.OK; // we don't know the size yet
- }
- if (networkType == ConnectivityManager.TYPE_WIFI) {
- return NetworkState.OK; // anything goes over wifi
- }
- Long maxBytesOverMobile = mSystemFacade.getMaxBytesOverMobile();
- if (maxBytesOverMobile != null && mTotalBytes > maxBytesOverMobile) {
- return NetworkState.UNUSABLE_DUE_TO_SIZE;
- }
- if (mBypassRecommendedSizeLimit == 0) {
- Long recommendedMaxBytesOverMobile = mSystemFacade.getRecommendedMaxBytesOverMobile();
- if (recommendedMaxBytesOverMobile != null
- && mTotalBytes > recommendedMaxBytesOverMobile) {
- return NetworkState.RECOMMENDED_UNUSABLE_DUE_TO_SIZE;
+ private NetworkState checkSizeAllowedForNetwork(int networkType, long totalBytes) {
+ if (totalBytes <= 0) {
+ // we don't know the size yet
+ return NetworkState.OK;
+ }
+
+ if (ConnectivityManager.isNetworkTypeMobile(networkType)) {
+ Long maxBytesOverMobile = mSystemFacade.getMaxBytesOverMobile();
+ if (maxBytesOverMobile != null && totalBytes > maxBytesOverMobile) {
+ return NetworkState.UNUSABLE_DUE_TO_SIZE;
+ }
+ if (mBypassRecommendedSizeLimit == 0) {
+ Long recommendedMaxBytesOverMobile = mSystemFacade
+ .getRecommendedMaxBytesOverMobile();
+ if (recommendedMaxBytesOverMobile != null
+ && totalBytes > recommendedMaxBytesOverMobile) {
+ return NetworkState.RECOMMENDED_UNUSABLE_DUE_TO_SIZE;
+ }
}
}
+
return NetworkState.OK;
}
@@ -467,8 +477,7 @@ public class DownloadInfo {
mContext.getContentResolver().update(getAllDownloadsUri(), values, null, null);
}
- mTask = new DownloadThread(
- mContext, mSystemFacade, this, mStorageManager, mNotifier);
+ mTask = new DownloadThread(mContext, mSystemFacade, mNotifier, this);
mSubmittedTask = executor.submit(mTask);
}
return isReady;
@@ -506,6 +515,13 @@ public class DownloadInfo {
return ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, mId);
}
+ @Override
+ public String toString() {
+ final CharArrayWriter writer = new CharArrayWriter();
+ dump(new IndentingPrintWriter(writer, " "));
+ return writer.toString();
+ }
+
public void dump(IndentingPrintWriter pw) {
pw.println("DownloadInfo:");
pw.increaseIndent();
diff --git a/src/com/android/providers/downloads/DownloadNotifier.java b/src/com/android/providers/downloads/DownloadNotifier.java
index ac52eba2..bfd5568d 100644
--- a/src/com/android/providers/downloads/DownloadNotifier.java
+++ b/src/com/android/providers/downloads/DownloadNotifier.java
@@ -139,6 +139,8 @@ public class DownloadNotifier {
final Collection<DownloadInfo> cluster = clustered.get(tag);
final Notification.Builder builder = new Notification.Builder(mContext);
+ builder.setColor(res.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
// Use time when cluster was first shown to avoid shuffling
final long firstShown;
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
index ad3cf7ac..2d914c41 100644
--- a/src/com/android/providers/downloads/DownloadProvider.java
+++ b/src/com/android/providers/downloads/DownloadProvider.java
@@ -39,7 +39,6 @@ import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.OnCloseListener;
import android.os.Process;
-import android.os.SELinux;
import android.provider.BaseColumns;
import android.provider.Downloads;
import android.provider.OpenableColumns;
@@ -178,7 +177,6 @@ public final class DownloadProvider extends ContentProvider {
/** List of uids that can access the downloads */
private int mSystemUid = -1;
private int mDefContainerUid = -1;
- private File mDownloadsDataDir;
@VisibleForTesting
SystemFacade mSystemFacade;
@@ -416,7 +414,7 @@ public final class DownloadProvider extends ContentProvider {
Downloads.Impl.COLUMN_OTHER_UID + " INTEGER, " +
Downloads.Impl.COLUMN_TITLE + " TEXT, " +
Downloads.Impl.COLUMN_DESCRIPTION + " TEXT, " +
- Constants.MEDIA_SCANNED + " BOOLEAN);");
+ Downloads.Impl.COLUMN_MEDIA_SCANNED + " BOOLEAN);");
} catch (SQLException ex) {
Log.e(Constants.TAG, "couldn't create table in downloads database");
throw ex;
@@ -464,12 +462,6 @@ public final class DownloadProvider extends ContentProvider {
// saves us by getting some initialization code in DownloadService out of the way.
Context context = getContext();
context.startService(new Intent(context, DownloadService.class));
- mDownloadsDataDir = StorageManager.getDownloadDataDirectory(getContext());
- try {
- SELinux.restorecon(mDownloadsDataDir.getCanonicalPath());
- } catch (IOException e) {
- Log.wtf(Constants.TAG, "Could not get canonical path for download directory", e);
- }
return true;
}
@@ -540,7 +532,7 @@ public final class DownloadProvider extends ContentProvider {
// validate the destination column
Integer dest = values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION);
if (dest != null) {
- if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
+ if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
!= PackageManager.PERMISSION_GRANTED
&& (dest == Downloads.Impl.DESTINATION_CACHE_PARTITION
|| dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING
@@ -551,7 +543,7 @@ public final class DownloadProvider extends ContentProvider {
// for public API behavior, if an app has CACHE_NON_PURGEABLE permission, automatically
// switch to non-purgeable download
boolean hasNonPurgeablePermission =
- getContext().checkCallingPermission(
+ getContext().checkCallingOrSelfPermission(
Downloads.Impl.PERMISSION_CACHE_NON_PURGEABLE)
== PackageManager.PERMISSION_GRANTED;
if (isPublicApi && dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE
@@ -638,7 +630,7 @@ public final class DownloadProvider extends ContentProvider {
copyString(Downloads.Impl.COLUMN_REFERER, values, filteredValues);
// UID, PID columns
- if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
+ if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
== PackageManager.PERMISSION_GRANTED) {
copyInteger(Downloads.Impl.COLUMN_OTHER_UID, values, filteredValues);
}
@@ -829,6 +821,16 @@ public final class DownloadProvider extends ContentProvider {
throw new SecurityException("Invalid value for " + column + ": " + value);
}
+ private Cursor queryCleared(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sort) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return query(uri, projection, selection, selectionArgs, sort);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
/**
* Starts a database query
*/
@@ -1051,12 +1053,16 @@ public final class DownloadProvider extends ContentProvider {
filteredValues = values;
String filename = values.getAsString(Downloads.Impl._DATA);
if (filename != null) {
- Cursor c = query(uri, new String[]
- { Downloads.Impl.COLUMN_TITLE }, null, null, null);
- if (!c.moveToFirst() || c.getString(0).isEmpty()) {
- values.put(Downloads.Impl.COLUMN_TITLE, new File(filename).getName());
+ Cursor c = null;
+ try {
+ c = query(uri, new String[]
+ { Downloads.Impl.COLUMN_TITLE }, null, null, null);
+ if (!c.moveToFirst() || c.getString(0).isEmpty()) {
+ values.put(Downloads.Impl.COLUMN_TITLE, new File(filename).getName());
+ }
+ } finally {
+ IoUtils.closeQuietly(c);
}
- c.close();
}
Integer status = values.getAsInteger(Downloads.Impl.COLUMN_STATUS);
@@ -1123,7 +1129,7 @@ public final class DownloadProvider extends ContentProvider {
selection.appendClause(Downloads.Impl._ID + " = ?", getDownloadIdFromUri(uri));
}
if ((uriMatch == MY_DOWNLOADS || uriMatch == MY_DOWNLOADS_ID)
- && getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ALL)
+ && getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS_ALL)
!= PackageManager.PERMISSION_GRANTED) {
selection.appendClause(
Constants.UID + "= ? OR " + Downloads.Impl.COLUMN_OTHER_UID + "= ?",
@@ -1139,7 +1145,9 @@ public final class DownloadProvider extends ContentProvider {
public int delete(final Uri uri, final String where,
final String[] whereArgs) {
- Helpers.validateSelection(where, sAppReadableColumnsSet);
+ if (shouldRestrictVisibility()) {
+ Helpers.validateSelection(where, sAppReadableColumnsSet);
+ }
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
@@ -1184,8 +1192,12 @@ public final class DownloadProvider extends ContentProvider {
logVerboseOpenFileInfo(uri, mode);
}
- final Cursor cursor = query(uri, new String[] { Downloads.Impl._DATA }, null, null, null);
- String path;
+ final Cursor cursor = queryCleared(uri, new String[] {
+ Downloads.Impl._DATA, Downloads.Impl.COLUMN_STATUS,
+ Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.COLUMN_MEDIA_SCANNED }, null,
+ null, null);
+ final String path;
+ final boolean shouldScan;
try {
int count = (cursor != null) ? cursor.getCount() : 0;
if (count != 1) {
@@ -1196,8 +1208,20 @@ public final class DownloadProvider extends ContentProvider {
throw new FileNotFoundException("Multiple items at " + uri);
}
- cursor.moveToFirst();
- path = cursor.getString(0);
+ if (cursor.moveToFirst()) {
+ final int status = cursor.getInt(1);
+ final int destination = cursor.getInt(2);
+ final int mediaScanned = cursor.getInt(3);
+
+ path = cursor.getString(0);
+ shouldScan = Downloads.Impl.isStatusSuccess(status) && (
+ destination == Downloads.Impl.DESTINATION_EXTERNAL
+ || destination == Downloads.Impl.DESTINATION_FILE_URI
+ || destination == Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD)
+ && mediaScanned != 2;
+ } else {
+ throw new FileNotFoundException("Failed moveToFirst");
+ }
} finally {
IoUtils.closeQuietly(cursor);
}
@@ -1205,27 +1229,41 @@ public final class DownloadProvider extends ContentProvider {
if (path == null) {
throw new FileNotFoundException("No filename found.");
}
- if (!Helpers.isFilenameValid(path, mDownloadsDataDir)) {
- throw new FileNotFoundException("Invalid filename: " + path);
+
+ final File file;
+ try {
+ file = new File(path).getCanonicalFile();
+ } catch (IOException e) {
+ throw new FileNotFoundException(e.getMessage());
+ }
+
+ if (!Helpers.isFilenameValid(getContext(), file)) {
+ throw new FileNotFoundException("Invalid file path: " + file);
}
- final File file = new File(path);
- if ("r".equals(mode)) {
- return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+ final int pfdMode = ParcelFileDescriptor.parseMode(mode);
+ if (pfdMode == ParcelFileDescriptor.MODE_READ_ONLY) {
+ return ParcelFileDescriptor.open(file, pfdMode);
} else {
try {
// When finished writing, update size and timestamp
- return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode),
- mHandler, new OnCloseListener() {
- @Override
- public void onClose(IOException e) {
- final ContentValues values = new ContentValues();
- values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, file.length());
- values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION,
- System.currentTimeMillis());
- update(uri, values, null, null);
- }
- });
+ return ParcelFileDescriptor.open(file, pfdMode, mHandler, new OnCloseListener() {
+ @Override
+ public void onClose(IOException e) {
+ final ContentValues values = new ContentValues();
+ values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, file.length());
+ values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION,
+ System.currentTimeMillis());
+ update(uri, values, null, null);
+
+ if (shouldScan) {
+ final Intent intent = new Intent(
+ Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ intent.setData(Uri.fromFile(file));
+ getContext().sendBroadcast(intent);
+ }
+ }
+ });
} catch (IOException e) {
throw new FileNotFoundException("Failed to open for writing: " + e);
}
@@ -1275,29 +1313,35 @@ public final class DownloadProvider extends ContentProvider {
if (cursor == null) {
Log.v(Constants.TAG, "null cursor in openFile");
} else {
- if (!cursor.moveToFirst()) {
- Log.v(Constants.TAG, "empty cursor in openFile");
- } else {
- do {
- Log.v(Constants.TAG, "row " + cursor.getInt(0) + " available");
- } while(cursor.moveToNext());
+ try {
+ if (!cursor.moveToFirst()) {
+ Log.v(Constants.TAG, "empty cursor in openFile");
+ } else {
+ do {
+ Log.v(Constants.TAG, "row " + cursor.getInt(0) + " available");
+ } while(cursor.moveToNext());
+ }
+ } finally {
+ cursor.close();
}
- cursor.close();
}
cursor = query(uri, new String[] { "_data" }, null, null, null);
if (cursor == null) {
Log.v(Constants.TAG, "null cursor in openFile");
} else {
- if (!cursor.moveToFirst()) {
- Log.v(Constants.TAG, "empty cursor in openFile");
- } else {
- String filename = cursor.getString(0);
- Log.v(Constants.TAG, "filename in openFile: " + filename);
- if (new java.io.File(filename).isFile()) {
- Log.v(Constants.TAG, "file exists in openFile");
+ try {
+ if (!cursor.moveToFirst()) {
+ Log.v(Constants.TAG, "empty cursor in openFile");
+ } else {
+ String filename = cursor.getString(0);
+ Log.v(Constants.TAG, "filename in openFile: " + filename);
+ if (new java.io.File(filename).isFile()) {
+ Log.v(Constants.TAG, "file exists in openFile");
+ }
}
+ } finally {
+ cursor.close();
}
- cursor.close();
}
}
diff --git a/src/com/android/providers/downloads/DownloadReceiver.java b/src/com/android/providers/downloads/DownloadReceiver.java
index f3d23766..28e2a673 100644
--- a/src/com/android/providers/downloads/DownloadReceiver.java
+++ b/src/com/android/providers/downloads/DownloadReceiver.java
@@ -18,9 +18,11 @@ package com.android.providers.downloads;
import static android.app.DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED;
import static android.app.DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION;
+import static com.android.providers.downloads.Constants.TAG;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
@@ -34,6 +36,7 @@ import android.os.HandlerThread;
import android.provider.Downloads;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Slog;
import android.widget.Toast;
import com.google.common.annotations.VisibleForTesting;
@@ -42,12 +45,10 @@ import com.google.common.annotations.VisibleForTesting;
* Receives system broadcasts (boot, network connectivity)
*/
public class DownloadReceiver extends BroadcastReceiver {
- private static final String TAG = "DownloadReceiver";
-
private static Handler sAsyncHandler;
static {
- final HandlerThread thread = new HandlerThread(TAG);
+ final HandlerThread thread = new HandlerThread("DownloadReceiver");
thread.start();
sAsyncHandler = new Handler(thread.getLooper());
}
@@ -61,31 +62,37 @@ public class DownloadReceiver extends BroadcastReceiver {
mSystemFacade = new RealSystemFacade(context);
}
- String action = intent.getAction();
- if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "Received broadcast intent for " +
- Intent.ACTION_BOOT_COMPLETED);
- }
+ final String action = intent.getAction();
+ if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
startService(context);
- } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "Received broadcast intent for " +
- Intent.ACTION_MEDIA_MOUNTED);
- }
+
+ } else if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {
startService(context);
- } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+
+ } else if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
final ConnectivityManager connManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo info = connManager.getActiveNetworkInfo();
if (info != null && info.isConnected()) {
startService(context);
}
- } else if (action.equals(Constants.ACTION_RETRY)) {
+
+ } else if (Intent.ACTION_UID_REMOVED.equals(action)) {
+ final PendingResult result = goAsync();
+ sAsyncHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ handleUidRemoved(context, intent);
+ result.finish();
+ }
+ });
+
+ } else if (Constants.ACTION_RETRY.equals(action)) {
startService(context);
- } else if (action.equals(Constants.ACTION_OPEN)
- || action.equals(Constants.ACTION_LIST)
- || action.equals(Constants.ACTION_HIDE)) {
+
+ } else if (Constants.ACTION_OPEN.equals(action)
+ || Constants.ACTION_LIST.equals(action)
+ || Constants.ACTION_HIDE.equals(action)) {
final PendingResult result = goAsync();
if (result == null) {
@@ -103,6 +110,18 @@ public class DownloadReceiver extends BroadcastReceiver {
}
}
+ private void handleUidRemoved(Context context, Intent intent) {
+ final ContentResolver resolver = context.getContentResolver();
+
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final int count = resolver.delete(
+ Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, Constants.UID + "=" + uid, null);
+
+ if (count > 0) {
+ Slog.d(TAG, "Deleted " + count + " downloads owned by UID " + uid);
+ }
+ }
+
/**
* Handle any broadcast related to a system notification.
*/
diff --git a/src/com/android/providers/downloads/DownloadService.java b/src/com/android/providers/downloads/DownloadService.java
index 7d746cca..58cf380c 100644
--- a/src/com/android/providers/downloads/DownloadService.java
+++ b/src/com/android/providers/downloads/DownloadService.java
@@ -23,6 +23,9 @@ import android.app.AlarmManager;
import android.app.DownloadManager;
import android.app.PendingIntent;
import android.app.Service;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -54,7 +57,10 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -78,7 +84,6 @@ public class DownloadService extends Service {
SystemFacade mSystemFacade;
private AlarmManager mAlarmManager;
- private StorageManager mStorageManager;
/** Observer to get notified when the content observer's data changes */
private DownloadManagerContentObserver mObserver;
@@ -86,6 +91,15 @@ public class DownloadService extends Service {
/** Class to handle Notification Manager updates */
private DownloadNotifier mNotifier;
+ /** Scheduling of the periodic cleanup job */
+ private JobInfo mCleanupJob;
+
+ private static final int CLEANUP_JOB_ID = 1;
+ private static final long CLEANUP_JOB_PERIOD = 1000 * 60 * 60 * 24; // one day
+ private static ComponentName sCleanupServiceName = new ComponentName(
+ DownloadIdleService.class.getPackage().getName(),
+ DownloadIdleService.class.getName());
+
/**
* The Service's view of the list of downloads, mapping download IDs to the corresponding info
* object. This is kept independently from the content provider, and the Service only initiates
@@ -105,7 +119,28 @@ public class DownloadService extends Service {
// threads as needed (up to maximum) and reclaims them when finished.
final ThreadPoolExecutor executor = new ThreadPoolExecutor(
maxConcurrent, maxConcurrent, 10, TimeUnit.SECONDS,
- new LinkedBlockingQueue<Runnable>());
+ new LinkedBlockingQueue<Runnable>()) {
+ @Override
+ protected void afterExecute(Runnable r, Throwable t) {
+ super.afterExecute(r, t);
+
+ if (t == null && r instanceof Future<?>) {
+ try {
+ ((Future<?>) r).get();
+ } catch (CancellationException ce) {
+ t = ce;
+ } catch (ExecutionException ee) {
+ t = ee.getCause();
+ } catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ if (t != null) {
+ Log.w(TAG, "Uncaught exception", t);
+ }
+ }
+ };
executor.allowCoreThreadTimeOut(true);
return executor;
}
@@ -157,7 +192,6 @@ public class DownloadService extends Service {
}
mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
- mStorageManager = new StorageManager(this);
mUpdateThread = new HandlerThread(TAG + "-UpdateThread");
mUpdateThread.start();
@@ -171,6 +205,28 @@ public class DownloadService extends Service {
mObserver = new DownloadManagerContentObserver();
getContentResolver().registerContentObserver(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
true, mObserver);
+
+ JobScheduler js = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ if (needToScheduleCleanup(js)) {
+ final JobInfo job = new JobInfo.Builder(CLEANUP_JOB_ID, sCleanupServiceName)
+ .setPeriodic(CLEANUP_JOB_PERIOD)
+ .setRequiresCharging(true)
+ .setRequiresDeviceIdle(true)
+ .build();
+ js.schedule(job);
+ }
+ }
+
+ private boolean needToScheduleCleanup(JobScheduler js) {
+ List<JobInfo> myJobs = js.getAllPendingJobs();
+ final int N = myJobs.size();
+ for (int i = 0; i < N; i++) {
+ if (myJobs.get(i).getId() == CLEANUP_JOB_ID) {
+ // It's already been (persistently) scheduled; no need to do it again
+ return false;
+ }
+ }
+ return true;
}
@Override
@@ -198,9 +254,11 @@ public class DownloadService extends Service {
/**
* Enqueue an {@link #updateLocked()} pass to occur in future.
*/
- private void enqueueUpdate() {
- mUpdateHandler.removeMessages(MSG_UPDATE);
- mUpdateHandler.obtainMessage(MSG_UPDATE, mLastStartId, -1).sendToTarget();
+ public void enqueueUpdate() {
+ if (mUpdateHandler != null) {
+ mUpdateHandler.removeMessages(MSG_UPDATE);
+ mUpdateHandler.obtainMessage(MSG_UPDATE, mLastStartId, -1).sendToTarget();
+ }
}
/**
@@ -376,8 +434,7 @@ public class DownloadService extends Service {
* download if appropriate.
*/
private DownloadInfo insertDownloadLocked(DownloadInfo.Reader reader, long now) {
- final DownloadInfo info = reader.newDownloadInfo(
- this, mSystemFacade, mStorageManager, mNotifier);
+ final DownloadInfo info = reader.newDownloadInfo(this, mSystemFacade, mNotifier);
mDownloads.put(info.mId, info);
if (Constants.LOGVV) {
diff --git a/src/com/android/providers/downloads/DownloadStorageProvider.java b/src/com/android/providers/downloads/DownloadStorageProvider.java
index ecef54e0..78b3c430 100644
--- a/src/com/android/providers/downloads/DownloadStorageProvider.java
+++ b/src/com/android/providers/downloads/DownloadStorageProvider.java
@@ -133,7 +133,7 @@ public class DownloadStorageProvider extends DocumentsProvider {
}
return Long.toString(mDm.addCompletedDownload(
- file.getName(), file.getName(), false, mimeType, file.getAbsolutePath(), 0L,
+ file.getName(), file.getName(), true, mimeType, file.getAbsolutePath(), 0L,
false, true));
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java
index 93f8d650..aa0190bf 100644
--- a/src/com/android/providers/downloads/DownloadThread.java
+++ b/src/com/android/providers/downloads/DownloadThread.java
@@ -22,6 +22,8 @@ import static android.provider.Downloads.Impl.STATUS_FILE_ERROR;
import static android.provider.Downloads.Impl.STATUS_HTTP_DATA_ERROR;
import static android.provider.Downloads.Impl.STATUS_SUCCESS;
import static android.provider.Downloads.Impl.STATUS_TOO_MANY_REDIRECTS;
+import static android.provider.Downloads.Impl.STATUS_UNHANDLED_HTTP_CODE;
+import static android.provider.Downloads.Impl.STATUS_UNKNOWN_ERROR;
import static android.provider.Downloads.Impl.STATUS_WAITING_FOR_NETWORK;
import static android.provider.Downloads.Impl.STATUS_WAITING_TO_RETRY;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
@@ -31,6 +33,7 @@ import static java.net.HttpURLConnection.HTTP_MOVED_PERM;
import static java.net.HttpURLConnection.HTTP_MOVED_TEMP;
import static java.net.HttpURLConnection.HTTP_OK;
import static java.net.HttpURLConnection.HTTP_PARTIAL;
+import static java.net.HttpURLConnection.HTTP_PRECON_FAILED;
import static java.net.HttpURLConnection.HTTP_SEE_OTHER;
import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
@@ -44,13 +47,15 @@ import android.net.INetworkPolicyListener;
import android.net.NetworkInfo;
import android.net.NetworkPolicyManager;
import android.net.TrafficStats;
-import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.Process;
import android.os.SystemClock;
import android.os.WorkSource;
import android.provider.Downloads;
-import android.text.TextUtils;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.util.Log;
import android.util.Pair;
@@ -60,132 +65,153 @@ import libcore.io.IoUtils;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
+import java.net.ProtocolException;
import java.net.URL;
import java.net.URLConnection;
/**
* Task which executes a given {@link DownloadInfo}: making network requests,
* persisting data to disk, and updating {@link DownloadProvider}.
+ * <p>
+ * To know if a download is successful, we need to know either the final content
+ * length to expect, or the transfer to be chunked. To resume an interrupted
+ * download, we need an ETag.
+ * <p>
+ * Failed network requests are retried several times before giving up. Local
+ * disk errors fail immediately and are not retried.
*/
public class DownloadThread implements Runnable {
// TODO: bind each download to a specific network interface to avoid state
// checking races once we have ConnectivityManager API
+ // TODO: add support for saving to content://
+
private static final int HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
private static final int HTTP_TEMP_REDIRECT = 307;
private static final int DEFAULT_TIMEOUT = (int) (20 * SECOND_IN_MILLIS);
private final Context mContext;
- private final DownloadInfo mInfo;
private final SystemFacade mSystemFacade;
- private final StorageManager mStorageManager;
private final DownloadNotifier mNotifier;
- private volatile boolean mPolicyDirty;
-
- public DownloadThread(Context context, SystemFacade systemFacade, DownloadInfo info,
- StorageManager storageManager, DownloadNotifier notifier) {
- mContext = context;
- mSystemFacade = systemFacade;
- mInfo = info;
- mStorageManager = storageManager;
- mNotifier = notifier;
- }
+ private final long mId;
/**
- * Returns the user agent provided by the initiating app, or use the default one
+ * Info object that should be treated as read-only. Any potentially mutated
+ * fields are tracked in {@link #mInfoDelta}. If a field exists in
+ * {@link #mInfoDelta}, it must not be read from {@link #mInfo}.
*/
- private String userAgent() {
- String userAgent = mInfo.mUserAgent;
- if (userAgent == null) {
- userAgent = Constants.DEFAULT_USER_AGENT;
- }
- return userAgent;
- }
+ private final DownloadInfo mInfo;
+ private final DownloadInfoDelta mInfoDelta;
+
+ private volatile boolean mPolicyDirty;
/**
- * State for the entire run() method.
+ * Local changes to {@link DownloadInfo}. These are kept local to avoid
+ * racing with the thread that updates based on change notifications.
*/
- static class State {
- public String mFilename;
+ private class DownloadInfoDelta {
+ public String mUri;
+ public String mFileName;
public String mMimeType;
- public int mRetryAfter = 0;
- public boolean mGotData = false;
- public String mRequestUri;
- public long mTotalBytes = -1;
- public long mCurrentBytes = 0;
- public String mHeaderETag;
- public boolean mContinuingDownload = false;
- public long mBytesNotified = 0;
- public long mTimeLastNotification = 0;
- public int mNetworkType = ConnectivityManager.TYPE_NONE;
-
- /** Historical bytes/second speed of this download. */
- public long mSpeed;
- /** Time when current sample started. */
- public long mSpeedSampleStart;
- /** Bytes transferred since current sample started. */
- public long mSpeedSampleBytes;
-
- public long mContentLength = -1;
- public String mContentDisposition;
- public String mContentLocation;
-
- public int mRedirectionCount;
- public URL mUrl;
-
- public State(DownloadInfo info) {
- mMimeType = Intent.normalizeMimeType(info.mMimeType);
- mRequestUri = info.mUri;
- mFilename = info.mFileName;
+ public int mStatus;
+ public int mNumFailed;
+ public int mRetryAfter;
+ public long mTotalBytes;
+ public long mCurrentBytes;
+ public String mETag;
+
+ public String mErrorMsg;
+
+ public DownloadInfoDelta(DownloadInfo info) {
+ mUri = info.mUri;
+ mFileName = info.mFileName;
+ mMimeType = info.mMimeType;
+ mStatus = info.mStatus;
+ mNumFailed = info.mNumFailed;
+ mRetryAfter = info.mRetryAfter;
mTotalBytes = info.mTotalBytes;
mCurrentBytes = info.mCurrentBytes;
+ mETag = info.mETag;
}
- public void resetBeforeExecute() {
- // Reset any state from previous execution
- mContentLength = -1;
- mContentDisposition = null;
- mContentLocation = null;
- mRedirectionCount = 0;
+ /**
+ * Push update of current delta values to provider.
+ */
+ public void writeToDatabase() {
+ final ContentValues values = new ContentValues();
+
+ values.put(Downloads.Impl.COLUMN_URI, mUri);
+ values.put(Downloads.Impl._DATA, mFileName);
+ values.put(Downloads.Impl.COLUMN_MIME_TYPE, mMimeType);
+ values.put(Downloads.Impl.COLUMN_STATUS, mStatus);
+ values.put(Downloads.Impl.COLUMN_FAILED_CONNECTIONS, mNumFailed);
+ values.put(Constants.RETRY_AFTER_X_REDIRECT_COUNT, mRetryAfter);
+ values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, mTotalBytes);
+ values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, mCurrentBytes);
+ values.put(Constants.ETAG, mETag);
+
+ values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, mSystemFacade.currentTimeMillis());
+ values.put(Downloads.Impl.COLUMN_ERROR_MSG, mErrorMsg);
+
+ mContext.getContentResolver().update(mInfo.getAllDownloadsUri(), values, null, null);
}
}
+ /**
+ * Flag indicating if we've made forward progress transferring file data
+ * from a remote server.
+ */
+ private boolean mMadeProgress = false;
+
+ /**
+ * Details from the last time we pushed a database update.
+ */
+ private long mLastUpdateBytes = 0;
+ private long mLastUpdateTime = 0;
+
+ private int mNetworkType = ConnectivityManager.TYPE_NONE;
+
+ /** Historical bytes/second speed of this download. */
+ private long mSpeed;
+ /** Time when current sample started. */
+ private long mSpeedSampleStart;
+ /** Bytes transferred since current sample started. */
+ private long mSpeedSampleBytes;
+
+ public DownloadThread(Context context, SystemFacade systemFacade, DownloadNotifier notifier,
+ DownloadInfo info) {
+ mContext = context;
+ mSystemFacade = systemFacade;
+ mNotifier = notifier;
+
+ mId = info.mId;
+ mInfo = info;
+ mInfoDelta = new DownloadInfoDelta(info);
+ }
+
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- try {
- runInternal();
- } finally {
- mNotifier.notifyDownloadSpeed(mInfo.mId, 0);
- }
- }
- private void runInternal() {
// Skip when download already marked as finished; this download was
// probably started again while racing with UpdateThread.
- if (DownloadInfo.queryDownloadStatus(mContext.getContentResolver(), mInfo.mId)
+ if (DownloadInfo.queryDownloadStatus(mContext.getContentResolver(), mId)
== Downloads.Impl.STATUS_SUCCESS) {
- Log.d(TAG, "Download " + mInfo.mId + " already finished; skipping");
+ logDebug("Already finished; skipping");
return;
}
- State state = new State(mInfo);
- PowerManager.WakeLock wakeLock = null;
- int finalStatus = Downloads.Impl.STATUS_UNKNOWN_ERROR;
- int numFailed = mInfo.mNumFailed;
- String errorMsg = null;
-
final NetworkPolicyManager netPolicy = NetworkPolicyManager.from(mContext);
+ PowerManager.WakeLock wakeLock = null;
final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
try {
@@ -196,13 +222,13 @@ public class DownloadThread implements Runnable {
// while performing download, register for rules updates
netPolicy.registerListener(mPolicyListener);
- Log.i(Constants.TAG, "Download " + mInfo.mId + " starting");
+ logDebug("Starting");
// Remember which network this download started on; used to
// determine if errors were due to network changes.
final NetworkInfo info = mSystemFacade.getActiveNetworkInfo(mInfo.mUid);
if (info != null) {
- state.mNetworkType = info.getType();
+ mNetworkType = info.getType();
}
// Network traffic on this thread should be counted against the
@@ -210,75 +236,79 @@ public class DownloadThread implements Runnable {
TrafficStats.setThreadStatsTag(TrafficStats.TAG_SYSTEM_DOWNLOAD);
TrafficStats.setThreadStatsUid(mInfo.mUid);
- try {
- // TODO: migrate URL sanity checking into client side of API
- state.mUrl = new URL(state.mRequestUri);
- } catch (MalformedURLException e) {
- throw new StopRequestException(STATUS_BAD_REQUEST, e);
- }
+ executeDownload();
+
+ mInfoDelta.mStatus = STATUS_SUCCESS;
+ TrafficStats.incrementOperationCount(1);
- executeDownload(state);
-
- finalizeDestinationFile(state);
- finalStatus = Downloads.Impl.STATUS_SUCCESS;
- } catch (StopRequestException error) {
- // remove the cause before printing, in case it contains PII
- errorMsg = error.getMessage();
- String msg = "Aborting request for download " + mInfo.mId + ": " + errorMsg;
- Log.w(Constants.TAG, msg);
- if (Constants.LOGV) {
- Log.w(Constants.TAG, msg, error);
+ // If we just finished a chunked file, record total size
+ if (mInfoDelta.mTotalBytes == -1) {
+ mInfoDelta.mTotalBytes = mInfoDelta.mCurrentBytes;
}
- finalStatus = error.getFinalStatus();
+
+ } catch (StopRequestException e) {
+ mInfoDelta.mStatus = e.getFinalStatus();
+ mInfoDelta.mErrorMsg = e.getMessage();
+
+ logWarning("Stop requested with status "
+ + Downloads.Impl.statusToString(mInfoDelta.mStatus) + ": "
+ + mInfoDelta.mErrorMsg);
// Nobody below our level should request retries, since we handle
// failure counts at this level.
- if (finalStatus == STATUS_WAITING_TO_RETRY) {
+ if (mInfoDelta.mStatus == STATUS_WAITING_TO_RETRY) {
throw new IllegalStateException("Execution should always throw final error codes");
}
// Some errors should be retryable, unless we fail too many times.
- if (isStatusRetryable(finalStatus)) {
- if (state.mGotData) {
- numFailed = 1;
+ if (isStatusRetryable(mInfoDelta.mStatus)) {
+ if (mMadeProgress) {
+ mInfoDelta.mNumFailed = 1;
} else {
- numFailed += 1;
+ mInfoDelta.mNumFailed += 1;
}
- if (numFailed < Constants.MAX_RETRIES) {
+ if (mInfoDelta.mNumFailed < Constants.MAX_RETRIES) {
final NetworkInfo info = mSystemFacade.getActiveNetworkInfo(mInfo.mUid);
- if (info != null && info.getType() == state.mNetworkType
- && info.isConnected()) {
+ if (info != null && info.getType() == mNetworkType && info.isConnected()) {
// Underlying network is still intact, use normal backoff
- finalStatus = STATUS_WAITING_TO_RETRY;
+ mInfoDelta.mStatus = STATUS_WAITING_TO_RETRY;
} else {
// Network changed, retry on any next available
- finalStatus = STATUS_WAITING_FOR_NETWORK;
+ mInfoDelta.mStatus = STATUS_WAITING_FOR_NETWORK;
+ }
+
+ if ((mInfoDelta.mETag == null && mMadeProgress)
+ || DownloadDrmHelper.isDrmConvertNeeded(mInfoDelta.mMimeType)) {
+ // However, if we wrote data and have no ETag to verify
+ // contents against later, we can't actually resume.
+ mInfoDelta.mStatus = STATUS_CANNOT_RESUME;
}
}
}
- // fall through to finally block
- } catch (Throwable ex) {
- errorMsg = ex.getMessage();
- String msg = "Exception for id " + mInfo.mId + ": " + errorMsg;
- Log.w(Constants.TAG, msg, ex);
- finalStatus = Downloads.Impl.STATUS_UNKNOWN_ERROR;
- // falls through to the code that reports an error
+ } catch (Throwable t) {
+ mInfoDelta.mStatus = STATUS_UNKNOWN_ERROR;
+ mInfoDelta.mErrorMsg = t.toString();
+
+ logError("Failed: " + mInfoDelta.mErrorMsg, t);
+
} finally {
- if (finalStatus == STATUS_SUCCESS) {
- TrafficStats.incrementOperationCount(1);
+ logDebug("Finished with status " + Downloads.Impl.statusToString(mInfoDelta.mStatus));
+
+ mNotifier.notifyDownloadSpeed(mId, 0);
+
+ finalizeDestination();
+
+ mInfoDelta.writeToDatabase();
+
+ if (Downloads.Impl.isStatusCompleted(mInfoDelta.mStatus)) {
+ mInfo.sendIntentIfRequested();
}
TrafficStats.clearThreadStatsTag();
TrafficStats.clearThreadStatsUid();
- cleanupDestination(state, finalStatus);
- notifyDownloadCompleted(state, finalStatus, errorMsg, numFailed);
-
- Log.i(Constants.TAG, "Download " + mInfo.mId + " finished with status "
- + Downloads.Impl.statusToString(finalStatus));
-
netPolicy.unregisterListener(mPolicyListener);
if (wakeLock != null) {
@@ -286,54 +316,54 @@ public class DownloadThread implements Runnable {
wakeLock = null;
}
}
- mStorageManager.incrementNumDownloadsSoFar();
}
/**
* Fully execute a single download request. Setup and send the request,
* handle the response, and transfer the data to the destination file.
*/
- private void executeDownload(State state) throws StopRequestException {
- state.resetBeforeExecute();
- setupDestinationFile(state);
-
- // skip when already finished; remove after fixing race in 5217390
- if (state.mCurrentBytes == state.mTotalBytes) {
- Log.i(Constants.TAG, "Skipping initiating request for download " +
- mInfo.mId + "; already completed");
- return;
+ private void executeDownload() throws StopRequestException {
+ final boolean resuming = mInfoDelta.mCurrentBytes != 0;
+
+ URL url;
+ try {
+ // TODO: migrate URL sanity checking into client side of API
+ url = new URL(mInfoDelta.mUri);
+ } catch (MalformedURLException e) {
+ throw new StopRequestException(STATUS_BAD_REQUEST, e);
}
- while (state.mRedirectionCount++ < Constants.MAX_REDIRECTS) {
+ int redirectionCount = 0;
+ while (redirectionCount++ < Constants.MAX_REDIRECTS) {
// Open connection and follow any redirects until we have a useful
// response with body.
HttpURLConnection conn = null;
try {
checkConnectivity();
- conn = (HttpURLConnection) state.mUrl.openConnection();
+ conn = (HttpURLConnection) url.openConnection();
conn.setInstanceFollowRedirects(false);
conn.setConnectTimeout(DEFAULT_TIMEOUT);
conn.setReadTimeout(DEFAULT_TIMEOUT);
- addRequestHeaders(state, conn);
+ addRequestHeaders(conn, resuming);
final int responseCode = conn.getResponseCode();
switch (responseCode) {
case HTTP_OK:
- if (state.mContinuingDownload) {
+ if (resuming) {
throw new StopRequestException(
STATUS_CANNOT_RESUME, "Expected partial, but received OK");
}
- processResponseHeaders(state, conn);
- transferData(state, conn);
+ parseOkHeaders(conn);
+ transferData(conn);
return;
case HTTP_PARTIAL:
- if (!state.mContinuingDownload) {
+ if (!resuming) {
throw new StopRequestException(
STATUS_CANNOT_RESUME, "Expected OK, but received partial");
}
- transferData(state, conn);
+ transferData(conn);
return;
case HTTP_MOVED_PERM:
@@ -341,19 +371,23 @@ public class DownloadThread implements Runnable {
case HTTP_SEE_OTHER:
case HTTP_TEMP_REDIRECT:
final String location = conn.getHeaderField("Location");
- state.mUrl = new URL(state.mUrl, location);
+ url = new URL(url, location);
if (responseCode == HTTP_MOVED_PERM) {
// Push updated URL back to database
- state.mRequestUri = state.mUrl.toString();
+ mInfoDelta.mUri = url.toString();
}
continue;
+ case HTTP_PRECON_FAILED:
+ throw new StopRequestException(
+ STATUS_CANNOT_RESUME, "Precondition failed");
+
case HTTP_REQUESTED_RANGE_NOT_SATISFIABLE:
throw new StopRequestException(
STATUS_CANNOT_RESUME, "Requested range not satisfiable");
case HTTP_UNAVAILABLE:
- parseRetryAfterHeaders(state, conn);
+ parseUnavailableHeaders(conn);
throw new StopRequestException(
HTTP_UNAVAILABLE, conn.getResponseMessage());
@@ -365,9 +399,15 @@ public class DownloadThread implements Runnable {
StopRequestException.throwUnhandledHttpError(
responseCode, conn.getResponseMessage());
}
+
} catch (IOException e) {
- // Trouble with low-level sockets
- throw new StopRequestException(STATUS_HTTP_DATA_ERROR, e);
+ if (e instanceof ProtocolException
+ && e.getMessage().startsWith("Unexpected status line")) {
+ throw new StopRequestException(STATUS_UNHANDLED_HTTP_CODE, e);
+ } else {
+ // Trouble with low-level sockets
+ throw new StopRequestException(STATUS_HTTP_DATA_ERROR, e);
+ }
} finally {
if (conn != null) conn.disconnect();
@@ -380,11 +420,23 @@ public class DownloadThread implements Runnable {
/**
* Transfer data from the given connection to the destination file.
*/
- private void transferData(State state, HttpURLConnection conn) throws StopRequestException {
+ private void transferData(HttpURLConnection conn) throws StopRequestException {
+
+ // To detect when we're really finished, we either need a length or
+ // chunked encoding.
+ final boolean hasLength = mInfoDelta.mTotalBytes != -1;
+ final String transferEncoding = conn.getHeaderField("Transfer-Encoding");
+ final boolean isChunked = "chunked".equalsIgnoreCase(transferEncoding);
+ if (!hasLength && !isChunked) {
+ throw new StopRequestException(
+ STATUS_CANNOT_RESUME, "can't know size of download, giving up");
+ }
+
DrmManagerClient drmClient = null;
+ ParcelFileDescriptor outPfd = null;
+ FileDescriptor outFd = null;
InputStream in = null;
OutputStream out = null;
- FileDescriptor outFd = null;
try {
try {
in = conn.getInputStream();
@@ -393,23 +445,49 @@ public class DownloadThread implements Runnable {
}
try {
- if (DownloadDrmHelper.isDrmConvertNeeded(state.mMimeType)) {
+ outPfd = mContext.getContentResolver()
+ .openFileDescriptor(mInfo.getAllDownloadsUri(), "rw");
+ outFd = outPfd.getFileDescriptor();
+
+ if (DownloadDrmHelper.isDrmConvertNeeded(mInfoDelta.mMimeType)) {
drmClient = new DrmManagerClient(mContext);
- final RandomAccessFile file = new RandomAccessFile(
- new File(state.mFilename), "rw");
- out = new DrmOutputStream(drmClient, file, state.mMimeType);
- outFd = file.getFD();
+ out = new DrmOutputStream(drmClient, outPfd, mInfoDelta.mMimeType);
} else {
- out = new FileOutputStream(state.mFilename, true);
- outFd = ((FileOutputStream) out).getFD();
+ out = new ParcelFileDescriptor.AutoCloseOutputStream(outPfd);
+ }
+
+ // Pre-flight disk space requirements, when known
+ if (mInfoDelta.mTotalBytes > 0) {
+ final long curSize = Os.fstat(outFd).st_size;
+ final long newBytes = mInfoDelta.mTotalBytes - curSize;
+
+ StorageUtils.ensureAvailableSpace(mContext, outFd, newBytes);
+
+ try {
+ // We found enough space, so claim it for ourselves
+ Os.posix_fallocate(outFd, 0, mInfoDelta.mTotalBytes);
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.ENOSYS || e.errno == OsConstants.ENOTSUP) {
+ Log.w(TAG, "fallocate() not supported; falling back to ftruncate()");
+ Os.ftruncate(outFd, mInfoDelta.mTotalBytes);
+ } else {
+ throw e;
+ }
+ }
}
+
+ // Move into place to begin writing
+ Os.lseek(outFd, mInfoDelta.mCurrentBytes, OsConstants.SEEK_SET);
+
+ } catch (ErrnoException e) {
+ throw new StopRequestException(STATUS_FILE_ERROR, e);
} catch (IOException e) {
throw new StopRequestException(STATUS_FILE_ERROR, e);
}
// Start streaming data, periodically watch for pause/cancel
// commands and checking disk space as needed.
- transferData(state, in, out);
+ transferData(in, out, outFd);
try {
if (out instanceof DrmOutputStream) {
@@ -437,83 +515,138 @@ public class DownloadThread implements Runnable {
}
/**
- * Check if current connectivity is valid for this request.
- */
- private void checkConnectivity() throws StopRequestException {
- // checking connectivity will apply current policy
- mPolicyDirty = false;
-
- final NetworkState networkUsable = mInfo.checkCanUseNetwork();
- if (networkUsable != NetworkState.OK) {
- int status = Downloads.Impl.STATUS_WAITING_FOR_NETWORK;
- if (networkUsable == NetworkState.UNUSABLE_DUE_TO_SIZE) {
- status = Downloads.Impl.STATUS_QUEUED_FOR_WIFI;
- mInfo.notifyPauseDueToSize(true);
- } else if (networkUsable == NetworkState.RECOMMENDED_UNUSABLE_DUE_TO_SIZE) {
- status = Downloads.Impl.STATUS_QUEUED_FOR_WIFI;
- mInfo.notifyPauseDueToSize(false);
- }
- throw new StopRequestException(status, networkUsable.name());
- }
- }
-
- /**
* Transfer as much data as possible from the HTTP response to the
* destination file.
*/
- private void transferData(State state, InputStream in, OutputStream out)
+ private void transferData(InputStream in, OutputStream out, FileDescriptor outFd)
throws StopRequestException {
- final byte data[] = new byte[Constants.BUFFER_SIZE];
- for (;;) {
- int bytesRead = readFromResponse(state, data, in);
- if (bytesRead == -1) { // success, end of stream already reached
- handleEndOfStream(state);
- return;
+ final byte buffer[] = new byte[Constants.BUFFER_SIZE];
+ while (true) {
+ checkPausedOrCanceled();
+
+ int len = -1;
+ try {
+ len = in.read(buffer);
+ } catch (IOException e) {
+ throw new StopRequestException(
+ STATUS_HTTP_DATA_ERROR, "Failed reading response: " + e, e);
+ }
+
+ if (len == -1) {
+ break;
}
- state.mGotData = true;
- writeDataToDestination(state, data, bytesRead, out);
- state.mCurrentBytes += bytesRead;
- reportProgress(state);
+ try {
+ // When streaming, ensure space before each write
+ if (mInfoDelta.mTotalBytes == -1) {
+ final long curSize = Os.fstat(outFd).st_size;
+ final long newBytes = (mInfoDelta.mCurrentBytes + len) - curSize;
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "downloaded " + state.mCurrentBytes + " for "
- + mInfo.mUri);
+ StorageUtils.ensureAvailableSpace(mContext, outFd, newBytes);
+ }
+
+ out.write(buffer, 0, len);
+
+ mMadeProgress = true;
+ mInfoDelta.mCurrentBytes += len;
+
+ updateProgress(outFd);
+
+ } catch (ErrnoException e) {
+ throw new StopRequestException(STATUS_FILE_ERROR, e);
+ } catch (IOException e) {
+ throw new StopRequestException(STATUS_FILE_ERROR, e);
}
+ }
- checkPausedOrCanceled(state);
+ // Finished without error; verify length if known
+ if (mInfoDelta.mTotalBytes != -1 && mInfoDelta.mCurrentBytes != mInfoDelta.mTotalBytes) {
+ throw new StopRequestException(STATUS_HTTP_DATA_ERROR, "Content length mismatch");
}
}
/**
- * Called after a successful completion to take any necessary action on the downloaded file.
+ * Called just before the thread finishes, regardless of status, to take any
+ * necessary action on the downloaded file.
*/
- private void finalizeDestinationFile(State state) {
- if (state.mFilename != null) {
- // make sure the file is readable
- FileUtils.setPermissions(state.mFilename, 0644, -1, -1);
+ private void finalizeDestination() {
+ if (Downloads.Impl.isStatusError(mInfoDelta.mStatus)) {
+ // When error, free up any disk space
+ try {
+ final ParcelFileDescriptor target = mContext.getContentResolver()
+ .openFileDescriptor(mInfo.getAllDownloadsUri(), "rw");
+ try {
+ Os.ftruncate(target.getFileDescriptor(), 0);
+ } catch (ErrnoException ignored) {
+ } finally {
+ IoUtils.closeQuietly(target);
+ }
+ } catch (FileNotFoundException ignored) {
+ }
+
+ // Delete if local file
+ if (mInfoDelta.mFileName != null) {
+ new File(mInfoDelta.mFileName).delete();
+ mInfoDelta.mFileName = null;
+ }
+
+ } else if (Downloads.Impl.isStatusSuccess(mInfoDelta.mStatus)) {
+ // When success, open access if local file
+ if (mInfoDelta.mFileName != null) {
+ try {
+ // TODO: remove this once PackageInstaller works with content://
+ Os.chmod(mInfoDelta.mFileName, 0644);
+ } catch (ErrnoException ignored) {
+ }
+
+ if (mInfo.mDestination != Downloads.Impl.DESTINATION_FILE_URI) {
+ try {
+ // Move into final resting place, if needed
+ final File before = new File(mInfoDelta.mFileName);
+ final File beforeDir = Helpers.getRunningDestinationDirectory(
+ mContext, mInfo.mDestination);
+ final File afterDir = Helpers.getSuccessDestinationDirectory(
+ mContext, mInfo.mDestination);
+ if (!beforeDir.equals(afterDir)
+ && before.getParentFile().equals(beforeDir)) {
+ final File after = new File(afterDir, before.getName());
+ if (before.renameTo(after)) {
+ mInfoDelta.mFileName = after.getAbsolutePath();
+ }
+ }
+ } catch (IOException ignored) {
+ }
+ }
+ }
}
}
/**
- * Called just before the thread finishes, regardless of status, to take any necessary action on
- * the downloaded file.
+ * Check if current connectivity is valid for this request.
*/
- private void cleanupDestination(State state, int finalStatus) {
- if (state.mFilename != null && Downloads.Impl.isStatusError(finalStatus)) {
- if (Constants.LOGVV) {
- Log.d(TAG, "cleanupDestination() deleting " + state.mFilename);
+ private void checkConnectivity() throws StopRequestException {
+ // checking connectivity will apply current policy
+ mPolicyDirty = false;
+
+ final NetworkState networkUsable = mInfo.checkCanUseNetwork(mInfoDelta.mTotalBytes);
+ if (networkUsable != NetworkState.OK) {
+ int status = Downloads.Impl.STATUS_WAITING_FOR_NETWORK;
+ if (networkUsable == NetworkState.UNUSABLE_DUE_TO_SIZE) {
+ status = Downloads.Impl.STATUS_QUEUED_FOR_WIFI;
+ mInfo.notifyPauseDueToSize(true);
+ } else if (networkUsable == NetworkState.RECOMMENDED_UNUSABLE_DUE_TO_SIZE) {
+ status = Downloads.Impl.STATUS_QUEUED_FOR_WIFI;
+ mInfo.notifyPauseDueToSize(false);
}
- new File(state.mFilename).delete();
- state.mFilename = null;
+ throw new StopRequestException(status, networkUsable.name());
}
}
/**
- * Check if the download has been paused or canceled, stopping the request appropriately if it
- * has been.
+ * Check if the download has been paused or canceled, stopping the request
+ * appropriately if it has been.
*/
- private void checkPausedOrCanceled(State state) throws StopRequestException {
+ private void checkPausedOrCanceled() throws StopRequestException {
synchronized (mInfo) {
if (mInfo.mControl == Downloads.Impl.CONTROL_PAUSED) {
throw new StopRequestException(
@@ -533,340 +666,133 @@ public class DownloadThread implements Runnable {
/**
* Report download progress through the database if necessary.
*/
- private void reportProgress(State state) {
+ private void updateProgress(FileDescriptor outFd) throws IOException {
final long now = SystemClock.elapsedRealtime();
+ final long currentBytes = mInfoDelta.mCurrentBytes;
- final long sampleDelta = now - state.mSpeedSampleStart;
+ final long sampleDelta = now - mSpeedSampleStart;
if (sampleDelta > 500) {
- final long sampleSpeed = ((state.mCurrentBytes - state.mSpeedSampleBytes) * 1000)
+ final long sampleSpeed = ((currentBytes - mSpeedSampleBytes) * 1000)
/ sampleDelta;
- if (state.mSpeed == 0) {
- state.mSpeed = sampleSpeed;
+ if (mSpeed == 0) {
+ mSpeed = sampleSpeed;
} else {
- state.mSpeed = ((state.mSpeed * 3) + sampleSpeed) / 4;
+ mSpeed = ((mSpeed * 3) + sampleSpeed) / 4;
}
// Only notify once we have a full sample window
- if (state.mSpeedSampleStart != 0) {
- mNotifier.notifyDownloadSpeed(mInfo.mId, state.mSpeed);
+ if (mSpeedSampleStart != 0) {
+ mNotifier.notifyDownloadSpeed(mId, mSpeed);
}
- state.mSpeedSampleStart = now;
- state.mSpeedSampleBytes = state.mCurrentBytes;
+ mSpeedSampleStart = now;
+ mSpeedSampleBytes = currentBytes;
}
- if (state.mCurrentBytes - state.mBytesNotified > Constants.MIN_PROGRESS_STEP &&
- now - state.mTimeLastNotification > Constants.MIN_PROGRESS_TIME) {
- ContentValues values = new ContentValues();
- values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, state.mCurrentBytes);
- mContext.getContentResolver().update(mInfo.getAllDownloadsUri(), values, null, null);
- state.mBytesNotified = state.mCurrentBytes;
- state.mTimeLastNotification = now;
- }
- }
-
- /**
- * Write a data buffer to the destination file.
- * @param data buffer containing the data to write
- * @param bytesRead how many bytes to write from the buffer
- */
- private void writeDataToDestination(State state, byte[] data, int bytesRead, OutputStream out)
- throws StopRequestException {
- mStorageManager.verifySpaceBeforeWritingToFile(
- mInfo.mDestination, state.mFilename, bytesRead);
+ final long bytesDelta = currentBytes - mLastUpdateBytes;
+ final long timeDelta = now - mLastUpdateTime;
+ if (bytesDelta > Constants.MIN_PROGRESS_STEP && timeDelta > Constants.MIN_PROGRESS_TIME) {
+ // fsync() to ensure that current progress has been flushed to disk,
+ // so we can always resume based on latest database information.
+ outFd.sync();
- boolean forceVerified = false;
- while (true) {
- try {
- out.write(data, 0, bytesRead);
- return;
- } catch (IOException ex) {
- // TODO: better differentiate between DRM and disk failures
- if (!forceVerified) {
- // couldn't write to file. are we out of space? check.
- mStorageManager.verifySpace(mInfo.mDestination, state.mFilename, bytesRead);
- forceVerified = true;
- } else {
- throw new StopRequestException(Downloads.Impl.STATUS_FILE_ERROR,
- "Failed to write data: " + ex);
- }
- }
- }
- }
+ mInfoDelta.writeToDatabase();
- /**
- * Called when we've reached the end of the HTTP response stream, to update the database and
- * check for consistency.
- */
- private void handleEndOfStream(State state) throws StopRequestException {
- ContentValues values = new ContentValues();
- values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, state.mCurrentBytes);
- if (state.mContentLength == -1) {
- values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, state.mCurrentBytes);
- }
- mContext.getContentResolver().update(mInfo.getAllDownloadsUri(), values, null, null);
-
- final boolean lengthMismatched = (state.mContentLength != -1)
- && (state.mCurrentBytes != state.mContentLength);
- if (lengthMismatched) {
- if (cannotResume(state)) {
- throw new StopRequestException(STATUS_CANNOT_RESUME,
- "mismatched content length; unable to resume");
- } else {
- throw new StopRequestException(STATUS_HTTP_DATA_ERROR,
- "closed socket before end of file");
- }
+ mLastUpdateBytes = currentBytes;
+ mLastUpdateTime = now;
}
}
- private boolean cannotResume(State state) {
- return (state.mCurrentBytes > 0 && !mInfo.mNoIntegrity && state.mHeaderETag == null)
- || DownloadDrmHelper.isDrmConvertNeeded(state.mMimeType);
- }
-
/**
- * Read some data from the HTTP response stream, handling I/O errors.
- * @param data buffer to use to read data
- * @param entityStream stream for reading the HTTP response entity
- * @return the number of bytes actually read or -1 if the end of the stream has been reached
+ * Process response headers from first server response. This derives its
+ * filename, size, and ETag.
*/
- private int readFromResponse(State state, byte[] data, InputStream entityStream)
- throws StopRequestException {
- try {
- return entityStream.read(data);
- } catch (IOException ex) {
- // TODO: handle stream errors the same as other retries
- if ("unexpected end of stream".equals(ex.getMessage())) {
- return -1;
- }
+ private void parseOkHeaders(HttpURLConnection conn) throws StopRequestException {
+ if (mInfoDelta.mFileName == null) {
+ final String contentDisposition = conn.getHeaderField("Content-Disposition");
+ final String contentLocation = conn.getHeaderField("Content-Location");
- ContentValues values = new ContentValues();
- values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, state.mCurrentBytes);
- mContext.getContentResolver().update(mInfo.getAllDownloadsUri(), values, null, null);
- if (cannotResume(state)) {
- throw new StopRequestException(STATUS_CANNOT_RESUME,
- "Failed reading response: " + ex + "; unable to resume", ex);
- } else {
- throw new StopRequestException(STATUS_HTTP_DATA_ERROR,
- "Failed reading response: " + ex, ex);
+ try {
+ mInfoDelta.mFileName = Helpers.generateSaveFile(mContext, mInfoDelta.mUri,
+ mInfo.mHint, contentDisposition, contentLocation, mInfoDelta.mMimeType,
+ mInfo.mDestination);
+ } catch (IOException e) {
+ throw new StopRequestException(
+ Downloads.Impl.STATUS_FILE_ERROR, "Failed to generate filename: " + e);
}
}
- }
-
- /**
- * Prepare target file based on given network response. Derives filename and
- * target size as needed.
- */
- private void processResponseHeaders(State state, HttpURLConnection conn)
- throws StopRequestException {
- // TODO: fallocate the entire file if header gave us specific length
-
- readResponseHeaders(state, conn);
-
- state.mFilename = Helpers.generateSaveFile(
- mContext,
- mInfo.mUri,
- mInfo.mHint,
- state.mContentDisposition,
- state.mContentLocation,
- state.mMimeType,
- mInfo.mDestination,
- state.mContentLength,
- mStorageManager);
-
- updateDatabaseFromHeaders(state);
- // check connectivity again now that we know the total size
- checkConnectivity();
- }
-
- /**
- * Update necessary database fields based on values of HTTP response headers that have been
- * read.
- */
- private void updateDatabaseFromHeaders(State state) {
- ContentValues values = new ContentValues();
- values.put(Downloads.Impl._DATA, state.mFilename);
- if (state.mHeaderETag != null) {
- values.put(Constants.ETAG, state.mHeaderETag);
- }
- if (state.mMimeType != null) {
- values.put(Downloads.Impl.COLUMN_MIME_TYPE, state.mMimeType);
- }
- values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, mInfo.mTotalBytes);
- mContext.getContentResolver().update(mInfo.getAllDownloadsUri(), values, null, null);
- }
-
- /**
- * Read headers from the HTTP response and store them into local state.
- */
- private void readResponseHeaders(State state, HttpURLConnection conn)
- throws StopRequestException {
- state.mContentDisposition = conn.getHeaderField("Content-Disposition");
- state.mContentLocation = conn.getHeaderField("Content-Location");
- if (state.mMimeType == null) {
- state.mMimeType = Intent.normalizeMimeType(conn.getContentType());
+ if (mInfoDelta.mMimeType == null) {
+ mInfoDelta.mMimeType = Intent.normalizeMimeType(conn.getContentType());
}
- state.mHeaderETag = conn.getHeaderField("ETag");
-
final String transferEncoding = conn.getHeaderField("Transfer-Encoding");
if (transferEncoding == null) {
- state.mContentLength = getHeaderFieldLong(conn, "Content-Length", -1);
+ mInfoDelta.mTotalBytes = getHeaderFieldLong(conn, "Content-Length", -1);
} else {
- Log.i(TAG, "Ignoring Content-Length since Transfer-Encoding is also defined");
- state.mContentLength = -1;
+ mInfoDelta.mTotalBytes = -1;
}
- state.mTotalBytes = state.mContentLength;
- mInfo.mTotalBytes = state.mContentLength;
+ mInfoDelta.mETag = conn.getHeaderField("ETag");
- final boolean noSizeInfo = state.mContentLength == -1
- && (transferEncoding == null || !transferEncoding.equalsIgnoreCase("chunked"));
- if (!mInfo.mNoIntegrity && noSizeInfo) {
- throw new StopRequestException(STATUS_CANNOT_RESUME,
- "can't know size of download, giving up");
- }
+ mInfoDelta.writeToDatabase();
+
+ // Check connectivity again now that we know the total size
+ checkConnectivity();
}
- private void parseRetryAfterHeaders(State state, HttpURLConnection conn) {
- state.mRetryAfter = conn.getHeaderFieldInt("Retry-After", -1);
- if (state.mRetryAfter < 0) {
- state.mRetryAfter = 0;
+ private void parseUnavailableHeaders(HttpURLConnection conn) {
+ long retryAfter = conn.getHeaderFieldInt("Retry-After", -1);
+ if (retryAfter < 0) {
+ retryAfter = 0;
} else {
- if (state.mRetryAfter < Constants.MIN_RETRY_AFTER) {
- state.mRetryAfter = Constants.MIN_RETRY_AFTER;
- } else if (state.mRetryAfter > Constants.MAX_RETRY_AFTER) {
- state.mRetryAfter = Constants.MAX_RETRY_AFTER;
+ if (retryAfter < Constants.MIN_RETRY_AFTER) {
+ retryAfter = Constants.MIN_RETRY_AFTER;
+ } else if (retryAfter > Constants.MAX_RETRY_AFTER) {
+ retryAfter = Constants.MAX_RETRY_AFTER;
}
- state.mRetryAfter += Helpers.sRandom.nextInt(Constants.MIN_RETRY_AFTER + 1);
- state.mRetryAfter *= 1000;
+ retryAfter += Helpers.sRandom.nextInt(Constants.MIN_RETRY_AFTER + 1);
}
- }
- /**
- * Prepare the destination file to receive data. If the file already exists, we'll set up
- * appropriately for resumption.
- */
- private void setupDestinationFile(State state) throws StopRequestException {
- if (!TextUtils.isEmpty(state.mFilename)) { // only true if we've already run a thread for this download
- if (Constants.LOGV) {
- Log.i(Constants.TAG, "have run thread before for id: " + mInfo.mId +
- ", and state.mFilename: " + state.mFilename);
- }
- if (!Helpers.isFilenameValid(state.mFilename,
- mStorageManager.getDownloadDataDirectory())) {
- // this should never happen
- throw new StopRequestException(Downloads.Impl.STATUS_FILE_ERROR,
- "found invalid internal destination filename");
- }
- // We're resuming a download that got interrupted
- File f = new File(state.mFilename);
- if (f.exists()) {
- if (Constants.LOGV) {
- Log.i(Constants.TAG, "resuming download for id: " + mInfo.mId +
- ", and state.mFilename: " + state.mFilename);
- }
- long fileLength = f.length();
- if (fileLength == 0) {
- // The download hadn't actually started, we can restart from scratch
- if (Constants.LOGVV) {
- Log.d(TAG, "setupDestinationFile() found fileLength=0, deleting "
- + state.mFilename);
- }
- f.delete();
- state.mFilename = null;
- if (Constants.LOGV) {
- Log.i(Constants.TAG, "resuming download for id: " + mInfo.mId +
- ", BUT starting from scratch again: ");
- }
- } else if (mInfo.mETag == null && !mInfo.mNoIntegrity) {
- // This should've been caught upon failure
- if (Constants.LOGVV) {
- Log.d(TAG, "setupDestinationFile() unable to resume download, deleting "
- + state.mFilename);
- }
- f.delete();
- throw new StopRequestException(Downloads.Impl.STATUS_CANNOT_RESUME,
- "Trying to resume a download that can't be resumed");
- } else {
- // All right, we'll be able to resume this download
- if (Constants.LOGV) {
- Log.i(Constants.TAG, "resuming download for id: " + mInfo.mId +
- ", and starting with file of length: " + fileLength);
- }
- state.mCurrentBytes = (int) fileLength;
- if (mInfo.mTotalBytes != -1) {
- state.mContentLength = mInfo.mTotalBytes;
- }
- state.mHeaderETag = mInfo.mETag;
- state.mContinuingDownload = true;
- if (Constants.LOGV) {
- Log.i(Constants.TAG, "resuming download for id: " + mInfo.mId +
- ", state.mCurrentBytes: " + state.mCurrentBytes +
- ", and setting mContinuingDownload to true: ");
- }
- }
- }
- }
+ mInfoDelta.mRetryAfter = (int) (retryAfter * SECOND_IN_MILLIS);
}
/**
* Add custom headers for this download to the HTTP request.
*/
- private void addRequestHeaders(State state, HttpURLConnection conn) {
+ private void addRequestHeaders(HttpURLConnection conn, boolean resuming) {
for (Pair<String, String> header : mInfo.getHeaders()) {
conn.addRequestProperty(header.first, header.second);
}
// Only splice in user agent when not already defined
if (conn.getRequestProperty("User-Agent") == null) {
- conn.addRequestProperty("User-Agent", userAgent());
+ conn.addRequestProperty("User-Agent", mInfo.getUserAgent());
}
// Defeat transparent gzip compression, since it doesn't allow us to
// easily resume partial downloads.
conn.setRequestProperty("Accept-Encoding", "identity");
- if (state.mContinuingDownload) {
- if (state.mHeaderETag != null) {
- conn.addRequestProperty("If-Match", state.mHeaderETag);
+ if (resuming) {
+ if (mInfoDelta.mETag != null) {
+ conn.addRequestProperty("If-Match", mInfoDelta.mETag);
}
- conn.addRequestProperty("Range", "bytes=" + state.mCurrentBytes + "-");
+ conn.addRequestProperty("Range", "bytes=" + mInfoDelta.mCurrentBytes + "-");
}
}
- /**
- * Stores information about the completed download, and notifies the initiating application.
- */
- private void notifyDownloadCompleted(
- State state, int finalStatus, String errorMsg, int numFailed) {
- notifyThroughDatabase(state, finalStatus, errorMsg, numFailed);
- if (Downloads.Impl.isStatusCompleted(finalStatus)) {
- mInfo.sendIntentIfRequested();
- }
+ private void logDebug(String msg) {
+ Log.d(TAG, "[" + mId + "] " + msg);
}
- private void notifyThroughDatabase(
- State state, int finalStatus, String errorMsg, int numFailed) {
- ContentValues values = new ContentValues();
- values.put(Downloads.Impl.COLUMN_STATUS, finalStatus);
- values.put(Downloads.Impl._DATA, state.mFilename);
- values.put(Downloads.Impl.COLUMN_MIME_TYPE, state.mMimeType);
- values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, mSystemFacade.currentTimeMillis());
- values.put(Downloads.Impl.COLUMN_FAILED_CONNECTIONS, numFailed);
- values.put(Constants.RETRY_AFTER_X_REDIRECT_COUNT, state.mRetryAfter);
-
- if (!TextUtils.equals(mInfo.mUri, state.mRequestUri)) {
- values.put(Downloads.Impl.COLUMN_URI, state.mRequestUri);
- }
+ private void logWarning(String msg) {
+ Log.w(TAG, "[" + mId + "] " + msg);
+ }
- // save the error message. could be useful to developers.
- if (!TextUtils.isEmpty(errorMsg)) {
- values.put(Downloads.Impl.COLUMN_ERROR_MSG, errorMsg);
- }
- mContext.getContentResolver().update(mInfo.getAllDownloadsUri(), values, null, null);
+ private void logError(String msg, Throwable t) {
+ Log.e(TAG, "[" + mId + "] " + msg, t);
}
private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
@@ -891,7 +817,7 @@ public class DownloadThread implements Runnable {
}
};
- public static long getHeaderFieldLong(URLConnection conn, String field, long defaultValue) {
+ private static long getHeaderFieldLong(URLConnection conn, String field, long defaultValue) {
try {
return Long.parseLong(conn.getHeaderField(field));
} catch (NumberFormatException e) {
diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java
index 3562dac7..7ca50bb1 100644
--- a/src/com/android/providers/downloads/Helpers.java
+++ b/src/com/android/providers/downloads/Helpers.java
@@ -21,6 +21,7 @@ import static com.android.providers.downloads.Constants.TAG;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
+import android.os.FileUtils;
import android.os.SystemClock;
import android.provider.Downloads;
import android.util.Log;
@@ -68,98 +69,79 @@ public class Helpers {
/**
* Creates a filename (where the file should be saved) from info about a download.
+ * This file will be touched to reserve it.
*/
- static String generateSaveFile(
- Context context,
- String url,
- String hint,
- String contentDisposition,
- String contentLocation,
- String mimeType,
- int destination,
- long contentLength,
- StorageManager storageManager) throws StopRequestException {
- if (contentLength < 0) {
- contentLength = 0;
- }
- String path;
- File base = null;
+ static String generateSaveFile(Context context, String url, String hint,
+ String contentDisposition, String contentLocation, String mimeType, int destination)
+ throws IOException {
+
+ final File parent;
+ final File[] parentTest;
+ String name = null;
+
if (destination == Downloads.Impl.DESTINATION_FILE_URI) {
- path = Uri.parse(hint).getPath();
+ final File file = new File(Uri.parse(hint).getPath());
+ parent = file.getParentFile().getAbsoluteFile();
+ parentTest = new File[] { parent };
+ name = file.getName();
} else {
- base = storageManager.locateDestinationDirectory(mimeType, destination,
- contentLength);
- path = chooseFilename(url, hint, contentDisposition, contentLocation,
- destination);
+ parent = getRunningDestinationDirectory(context, destination);
+ parentTest = new File[] {
+ parent,
+ getSuccessDestinationDirectory(context, destination)
+ };
+ name = chooseFilename(url, hint, contentDisposition, contentLocation);
+ }
+
+ // Ensure target directories are ready
+ for (File test : parentTest) {
+ if (!(test.isDirectory() || test.mkdirs())) {
+ throw new IOException("Failed to create parent for " + test);
+ }
}
- storageManager.verifySpace(destination, path, contentLength);
+
if (DownloadDrmHelper.isDrmConvertNeeded(mimeType)) {
- path = DownloadDrmHelper.modifyDrmFwLockFileExtension(path);
+ name = DownloadDrmHelper.modifyDrmFwLockFileExtension(name);
}
- path = getFullPath(path, mimeType, destination, base);
- return path;
- }
- static String getFullPath(String filename, String mimeType, int destination, File base)
- throws StopRequestException {
- String extension = null;
- int dotIndex = filename.lastIndexOf('.');
- boolean missingExtension = dotIndex < 0 || dotIndex < filename.lastIndexOf('/');
+ final String prefix;
+ final String suffix;
+ final int dotIndex = name.lastIndexOf('.');
+ final boolean missingExtension = dotIndex < 0;
if (destination == Downloads.Impl.DESTINATION_FILE_URI) {
// Destination is explicitly set - do not change the extension
if (missingExtension) {
- extension = "";
+ prefix = name;
+ suffix = "";
} else {
- extension = filename.substring(dotIndex);
- filename = filename.substring(0, dotIndex);
+ prefix = name.substring(0, dotIndex);
+ suffix = name.substring(dotIndex);
}
} else {
// Split filename between base and extension
// Add an extension if filename does not have one
if (missingExtension) {
- extension = chooseExtensionFromMimeType(mimeType, true);
+ prefix = name;
+ suffix = chooseExtensionFromMimeType(mimeType, true);
} else {
- extension = chooseExtensionFromFilename(mimeType, destination, filename, dotIndex);
- filename = filename.substring(0, dotIndex);
+ prefix = name.substring(0, dotIndex);
+ suffix = chooseExtensionFromFilename(mimeType, destination, name, dotIndex);
}
}
- boolean recoveryDir = Constants.RECOVERY_DIRECTORY.equalsIgnoreCase(filename + extension);
-
- if (base != null) {
- filename = base.getPath() + File.separator + filename;
- }
-
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "target file: " + filename + extension);
- }
-
synchronized (sUniqueLock) {
- final String path = chooseUniqueFilenameLocked(
- destination, filename, extension, recoveryDir);
+ name = generateAvailableFilenameLocked(parentTest, prefix, suffix);
// Claim this filename inside lock to prevent other threads from
// clobbering us. We're not paranoid enough to use O_EXCL.
- try {
- File file = new File(path);
- File parent = file.getParentFile();
-
- // Make sure the parent directories exists before generates new file
- if (parent != null && !parent.exists()) {
- parent.mkdirs();
- }
-
- file.createNewFile();
- } catch (IOException e) {
- throw new StopRequestException(Downloads.Impl.STATUS_FILE_ERROR,
- "Failed to create target file " + path, e);
- }
- return path;
+ final File file = new File(parent, name);
+ file.createNewFile();
+ return file.getAbsolutePath();
}
}
private static String chooseFilename(String url, String hint, String contentDisposition,
- String contentLocation, int destination) {
+ String contentLocation) {
String filename = null;
// First, try to use the hint from the application, if there's one
@@ -305,18 +287,25 @@ public class Helpers {
return extension;
}
- private static String chooseUniqueFilenameLocked(int destination, String filename,
- String extension, boolean recoveryDir) throws StopRequestException {
- String fullFilename = filename + extension;
- if (!new File(fullFilename).exists()
- && (!recoveryDir ||
- (destination != Downloads.Impl.DESTINATION_CACHE_PARTITION &&
- destination != Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION &&
- destination != Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE &&
- destination != Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING))) {
- return fullFilename;
- }
- filename = filename + Constants.FILENAME_SEQUENCE_SEPARATOR;
+ private static boolean isFilenameAvailableLocked(File[] parents, String name) {
+ if (Constants.RECOVERY_DIRECTORY.equalsIgnoreCase(name)) return false;
+
+ for (File parent : parents) {
+ if (new File(parent, name).exists()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static String generateAvailableFilenameLocked(
+ File[] parents, String prefix, String suffix) throws IOException {
+ String name = prefix + suffix;
+ if (isFilenameAvailableLocked(parents, name)) {
+ return name;
+ }
+
/*
* This number is used to generate partially randomized filenames to avoid
* collisions.
@@ -334,39 +323,37 @@ public class Helpers {
int sequence = 1;
for (int magnitude = 1; magnitude < 1000000000; magnitude *= 10) {
for (int iteration = 0; iteration < 9; ++iteration) {
- fullFilename = filename + sequence + extension;
- if (!new File(fullFilename).exists()) {
- return fullFilename;
- }
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "file with sequence number " + sequence + " exists");
+ name = prefix + Constants.FILENAME_SEQUENCE_SEPARATOR + sequence + suffix;
+ if (isFilenameAvailableLocked(parents, name)) {
+ return name;
}
sequence += sRandom.nextInt(magnitude) + 1;
}
}
- throw new StopRequestException(Downloads.Impl.STATUS_FILE_ERROR,
- "failed to generate an unused filename on internal download storage");
+
+ throw new IOException("Failed to generate an available filename");
}
/**
- * Checks whether the filename looks legitimate
+ * Checks whether the filename looks legitimate for security purposes. This
+ * prevents us from opening files that aren't actually downloads.
*/
- static boolean isFilenameValid(String filename, File downloadsDataDir) {
- final String[] whitelist;
+ static boolean isFilenameValid(Context context, File file) {
+ final File[] whitelist;
try {
- filename = new File(filename).getCanonicalPath();
- whitelist = new String[] {
- downloadsDataDir.getCanonicalPath(),
- Environment.getDownloadCacheDirectory().getCanonicalPath(),
- Environment.getExternalStorageDirectory().getCanonicalPath(),
+ whitelist = new File[] {
+ context.getFilesDir().getCanonicalFile(),
+ context.getCacheDir().getCanonicalFile(),
+ Environment.getDownloadCacheDirectory().getCanonicalFile(),
+ Environment.getExternalStorageDirectory().getCanonicalFile(),
};
} catch (IOException e) {
Log.w(TAG, "Failed to resolve canonical path: " + e);
return false;
}
- for (String test : whitelist) {
- if (filename.startsWith(test)) {
+ for (File testDir : whitelist) {
+ if (FileUtils.contains(testDir, file)) {
return true;
}
}
@@ -374,6 +361,49 @@ public class Helpers {
return false;
}
+ public static File getRunningDestinationDirectory(Context context, int destination)
+ throws IOException {
+ return getDestinationDirectory(context, destination, true);
+ }
+
+ public static File getSuccessDestinationDirectory(Context context, int destination)
+ throws IOException {
+ return getDestinationDirectory(context, destination, false);
+ }
+
+ private static File getDestinationDirectory(Context context, int destination, boolean running)
+ throws IOException {
+ switch (destination) {
+ case Downloads.Impl.DESTINATION_CACHE_PARTITION:
+ case Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE:
+ case Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING:
+ if (running) {
+ return context.getFilesDir();
+ } else {
+ return context.getCacheDir();
+ }
+
+ case Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION:
+ if (running) {
+ return new File(Environment.getDownloadCacheDirectory(),
+ Constants.DIRECTORY_CACHE_RUNNING);
+ } else {
+ return Environment.getDownloadCacheDirectory();
+ }
+
+ case Downloads.Impl.DESTINATION_EXTERNAL:
+ final File target = new File(
+ Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DOWNLOADS);
+ if (!target.isDirectory() && target.mkdirs()) {
+ throw new IOException("unable to create external downloads directory");
+ }
+ return target;
+
+ default:
+ throw new IllegalStateException("unexpected destination: " + destination);
+ }
+ }
+
/**
* Checks whether this looks like a legitimate selection parameter
*/
diff --git a/src/com/android/providers/downloads/StopRequestException.java b/src/com/android/providers/downloads/StopRequestException.java
index a2b642d8..07bd6284 100644
--- a/src/com/android/providers/downloads/StopRequestException.java
+++ b/src/com/android/providers/downloads/StopRequestException.java
@@ -34,13 +34,13 @@ class StopRequestException extends Exception {
}
public StopRequestException(int finalStatus, Throwable t) {
- super(t);
- mFinalStatus = finalStatus;
+ this(finalStatus, t.getMessage());
+ initCause(t);
}
public StopRequestException(int finalStatus, String message, Throwable t) {
- super(message, t);
- mFinalStatus = finalStatus;
+ this(finalStatus, message);
+ initCause(t);
}
public int getFinalStatus() {
diff --git a/src/com/android/providers/downloads/StorageManager.java b/src/com/android/providers/downloads/StorageManager.java
deleted file mode 100644
index deb412e7..00000000
--- a/src/com/android/providers/downloads/StorageManager.java
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.providers.downloads;
-
-import static com.android.providers.downloads.Constants.LOGV;
-import static com.android.providers.downloads.Constants.TAG;
-
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteException;
-import android.net.Uri;
-import android.os.Environment;
-import android.os.StatFs;
-import android.provider.Downloads;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.R;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.StructStat;
-
-/**
- * Manages the storage space consumed by Downloads Data dir. When space falls below
- * a threshold limit (set in resource xml files), starts cleanup of the Downloads data dir
- * to free up space.
- */
-class StorageManager {
- /** the max amount of space allowed to be taken up by the downloads data dir */
- private static final long sMaxdownloadDataDirSize =
- Resources.getSystem().getInteger(R.integer.config_downloadDataDirSize) * 1024 * 1024;
-
- /** threshold (in bytes) beyond which the low space warning kicks in and attempt is made to
- * purge some downloaded files to make space
- */
- private static final long sDownloadDataDirLowSpaceThreshold =
- Resources.getSystem().getInteger(
- R.integer.config_downloadDataDirLowSpaceThreshold)
- * sMaxdownloadDataDirSize / 100;
-
- /** see {@link Environment#getExternalStorageDirectory()} */
- private final File mExternalStorageDir;
-
- /** see {@link Environment#getDownloadCacheDirectory()} */
- private final File mSystemCacheDir;
-
- /** The downloaded files are saved to this dir. it is the value returned by
- * {@link Context#getCacheDir()}.
- */
- private final File mDownloadDataDir;
-
- /** how often do we need to perform checks on space to make sure space is available */
- private static final int FREQUENCY_OF_CHECKS_ON_SPACE_AVAILABILITY = 1024 * 1024; // 1MB
- private int mBytesDownloadedSinceLastCheckOnSpace = 0;
-
- /** misc members */
- private final Context mContext;
-
- public StorageManager(Context context) {
- mContext = context;
- mDownloadDataDir = getDownloadDataDirectory(context);
- mExternalStorageDir = Environment.getExternalStorageDirectory();
- mSystemCacheDir = Environment.getDownloadCacheDirectory();
- startThreadToCleanupDatabaseAndPurgeFileSystem();
- }
-
- /** How often should database and filesystem be cleaned up to remove spurious files
- * from the file system and
- * The value is specified in terms of num of downloads since last time the cleanup was done.
- */
- private static final int FREQUENCY_OF_DATABASE_N_FILESYSTEM_CLEANUP = 250;
- private int mNumDownloadsSoFar = 0;
-
- synchronized void incrementNumDownloadsSoFar() {
- if (++mNumDownloadsSoFar % FREQUENCY_OF_DATABASE_N_FILESYSTEM_CLEANUP == 0) {
- startThreadToCleanupDatabaseAndPurgeFileSystem();
- }
- }
- /* start a thread to cleanup the following
- * remove spurious files from the file system
- * remove excess entries from the database
- */
- private Thread mCleanupThread = null;
- private synchronized void startThreadToCleanupDatabaseAndPurgeFileSystem() {
- if (mCleanupThread != null && mCleanupThread.isAlive()) {
- return;
- }
- mCleanupThread = new Thread() {
- @Override public void run() {
- removeSpuriousFiles();
- trimDatabase();
- }
- };
- mCleanupThread.start();
- }
-
- void verifySpaceBeforeWritingToFile(int destination, String path, long length)
- throws StopRequestException {
- // do this check only once for every 1MB of downloaded data
- if (incrementBytesDownloadedSinceLastCheckOnSpace(length) <
- FREQUENCY_OF_CHECKS_ON_SPACE_AVAILABILITY) {
- return;
- }
- verifySpace(destination, path, length);
- }
-
- void verifySpace(int destination, String path, long length) throws StopRequestException {
- resetBytesDownloadedSinceLastCheckOnSpace();
- File dir = null;
- if (Constants.LOGV) {
- Log.i(Constants.TAG, "in verifySpace, destination: " + destination +
- ", path: " + path + ", length: " + length);
- }
- if (path == null) {
- throw new IllegalArgumentException("path can't be null");
- }
- switch (destination) {
- case Downloads.Impl.DESTINATION_CACHE_PARTITION:
- case Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING:
- case Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE:
- dir = mDownloadDataDir;
- break;
- case Downloads.Impl.DESTINATION_EXTERNAL:
- dir = mExternalStorageDir;
- break;
- case Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION:
- dir = mSystemCacheDir;
- break;
- case Downloads.Impl.DESTINATION_FILE_URI:
- if (path.startsWith(mExternalStorageDir.getPath())) {
- dir = mExternalStorageDir;
- } else if (path.startsWith(mDownloadDataDir.getPath())) {
- dir = mDownloadDataDir;
- } else if (path.startsWith(mSystemCacheDir.getPath())) {
- dir = mSystemCacheDir;
- }
- break;
- }
- if (dir == null) {
- throw new IllegalStateException("invalid combination of destination: " + destination +
- ", path: " + path);
- }
- findSpace(dir, length, destination);
- }
-
- /**
- * finds space in the given filesystem (input param: root) to accommodate # of bytes
- * specified by the input param(targetBytes).
- * returns true if found. false otherwise.
- */
- private synchronized void findSpace(File root, long targetBytes, int destination)
- throws StopRequestException {
- if (targetBytes == 0) {
- return;
- }
- if (destination == Downloads.Impl.DESTINATION_FILE_URI ||
- destination == Downloads.Impl.DESTINATION_EXTERNAL) {
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- throw new StopRequestException(Downloads.Impl.STATUS_DEVICE_NOT_FOUND_ERROR,
- "external media not mounted");
- }
- }
- // is there enough space in the file system of the given param 'root'.
- long bytesAvailable = getAvailableBytesInFileSystemAtGivenRoot(root);
- if (bytesAvailable < sDownloadDataDirLowSpaceThreshold) {
- /* filesystem's available space is below threshold for low space warning.
- * threshold typically is 10% of download data dir space quota.
- * try to cleanup and see if the low space situation goes away.
- */
- discardPurgeableFiles(destination, sDownloadDataDirLowSpaceThreshold);
- removeSpuriousFiles();
- bytesAvailable = getAvailableBytesInFileSystemAtGivenRoot(root);
- if (bytesAvailable < sDownloadDataDirLowSpaceThreshold) {
- /*
- * available space is still below the threshold limit.
- *
- * If this is system cache dir, print a warning.
- * otherwise, don't allow downloading until more space
- * is available because downloadmanager shouldn't end up taking those last
- * few MB of space left on the filesystem.
- */
- if (root.equals(mSystemCacheDir)) {
- Log.w(Constants.TAG, "System cache dir ('/cache') is running low on space." +
- "space available (in bytes): " + bytesAvailable);
- } else {
- throw new StopRequestException(Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR,
- "space in the filesystem rooted at: " + root +
- " is below 10% availability. stopping this download.");
- }
- }
- }
- if (root.equals(mDownloadDataDir)) {
- // this download is going into downloads data dir. check space in that specific dir.
- bytesAvailable = getAvailableBytesInDownloadsDataDir(mDownloadDataDir);
- if (bytesAvailable < sDownloadDataDirLowSpaceThreshold) {
- // print a warning
- Log.w(Constants.TAG, "Downloads data dir: " + root +
- " is running low on space. space available (in bytes): " + bytesAvailable);
- }
- if (bytesAvailable < targetBytes) {
- // Insufficient space; make space.
- discardPurgeableFiles(destination, sDownloadDataDirLowSpaceThreshold);
- removeSpuriousFiles();
- bytesAvailable = getAvailableBytesInDownloadsDataDir(mDownloadDataDir);
- }
- }
- if (bytesAvailable < targetBytes) {
- throw new StopRequestException(Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR,
- "not enough free space in the filesystem rooted at: " + root +
- " and unable to free any more");
- }
- }
-
- /**
- * returns the number of bytes available in the downloads data dir
- * TODO this implementation is too slow. optimize it.
- */
- private long getAvailableBytesInDownloadsDataDir(File root) {
- File[] files = root.listFiles();
- long space = sMaxdownloadDataDirSize;
- if (files == null) {
- return space;
- }
- int size = files.length;
- for (int i = 0; i < size; i++) {
- space -= files[i].length();
- }
- if (Constants.LOGV) {
- Log.i(Constants.TAG, "available space (in bytes) in downloads data dir: " + space);
- }
- return space;
- }
-
- private long getAvailableBytesInFileSystemAtGivenRoot(File root) {
- StatFs stat = new StatFs(root.getPath());
- // put a bit of margin (in case creating the file grows the system by a few blocks)
- long availableBlocks = (long) stat.getAvailableBlocks() - 4;
- long size = stat.getBlockSize() * availableBlocks;
- if (Constants.LOGV) {
- Log.i(Constants.TAG, "available space (in bytes) in filesystem rooted at: " +
- root.getPath() + " is: " + size);
- }
- return size;
- }
-
- File locateDestinationDirectory(String mimeType, int destination, long contentLength)
- throws StopRequestException {
- switch (destination) {
- case Downloads.Impl.DESTINATION_CACHE_PARTITION:
- case Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE:
- case Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING:
- return mDownloadDataDir;
- case Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION:
- return mSystemCacheDir;
- case Downloads.Impl.DESTINATION_EXTERNAL:
- File base = new File(mExternalStorageDir.getPath() + Constants.DEFAULT_DL_SUBDIR);
- if (!base.isDirectory() && !base.mkdir()) {
- // Can't create download directory, e.g. because a file called "download"
- // already exists at the root level, or the SD card filesystem is read-only.
- throw new StopRequestException(Downloads.Impl.STATUS_FILE_ERROR,
- "unable to create external downloads directory " + base.getPath());
- }
- return base;
- default:
- throw new IllegalStateException("unexpected value for destination: " + destination);
- }
- }
-
- File getDownloadDataDirectory() {
- return mDownloadDataDir;
- }
-
- public static File getDownloadDataDirectory(Context context) {
- return context.getCacheDir();
- }
-
- /**
- * Deletes purgeable files from the cache partition. This also deletes
- * the matching database entries. Files are deleted in LRU order until
- * the total byte size is greater than targetBytes
- */
- private long discardPurgeableFiles(int destination, long targetBytes) {
- if (true || Constants.LOGV) {
- Log.i(Constants.TAG, "discardPurgeableFiles: destination = " + destination +
- ", targetBytes = " + targetBytes);
- }
- String destStr = (destination == Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION) ?
- String.valueOf(destination) :
- String.valueOf(Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE);
- String[] bindArgs = new String[]{destStr};
- Cursor cursor = mContext.getContentResolver().query(
- Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
- null,
- "( " +
- Downloads.Impl.COLUMN_STATUS + " = '" + Downloads.Impl.STATUS_SUCCESS + "' AND " +
- Downloads.Impl.COLUMN_DESTINATION + " = ? )",
- bindArgs,
- Downloads.Impl.COLUMN_LAST_MODIFICATION);
- if (cursor == null) {
- return 0;
- }
- long totalFreed = 0;
- try {
- final int dataIndex = cursor.getColumnIndex(Downloads.Impl._DATA);
- while (cursor.moveToNext() && totalFreed < targetBytes) {
- final String data = cursor.getString(dataIndex);
- if (TextUtils.isEmpty(data)) continue;
-
- File file = new File(data);
- if (Constants.LOGV) {
- Log.d(Constants.TAG, "purging " + file.getAbsolutePath() + " for "
- + file.length() + " bytes");
- }
- totalFreed += file.length();
- file.delete();
- long id = cursor.getLong(cursor.getColumnIndex(Downloads.Impl._ID));
- mContext.getContentResolver().delete(
- ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id),
- null, null);
- }
- } finally {
- cursor.close();
- }
- if (true || Constants.LOGV) {
- Log.i(Constants.TAG, "Purged files, freed " + totalFreed + " for " +
- targetBytes + " requested");
- }
- return totalFreed;
- }
-
- /**
- * Removes files in the systemcache and downloads data dir without corresponding entries in
- * the downloads database.
- * This can occur if a delete is done on the database but the file is not removed from the
- * filesystem (due to sudden death of the process, for example).
- * This is not a very common occurrence. So, do this only once in a while.
- */
- private void removeSpuriousFiles() {
- if (Constants.LOGV) {
- Log.i(Constants.TAG, "in removeSpuriousFiles");
- }
- // get a list of all files in system cache dir and downloads data dir
- List<File> files = new ArrayList<File>();
- File[] listOfFiles = mSystemCacheDir.listFiles();
- if (listOfFiles != null) {
- files.addAll(Arrays.asList(listOfFiles));
- }
- listOfFiles = mDownloadDataDir.listFiles();
- if (listOfFiles != null) {
- files.addAll(Arrays.asList(listOfFiles));
- }
- if (files.size() == 0) {
- return;
- }
- Cursor cursor = mContext.getContentResolver().query(
- Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
- new String[] { Downloads.Impl._DATA }, null, null, null);
- try {
- if (cursor != null) {
- while (cursor.moveToNext()) {
- String filename = cursor.getString(0);
- if (!TextUtils.isEmpty(filename)) {
- if (LOGV) {
- Log.i(Constants.TAG, "in removeSpuriousFiles, preserving file " +
- filename);
- }
- files.remove(new File(filename));
- }
- }
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
-
- // delete files owned by us, but that don't appear in our database
- final int myUid = android.os.Process.myUid();
- for (File file : files) {
- final String path = file.getAbsolutePath();
- try {
- final StructStat stat = Libcore.os.stat(path);
- if (stat.st_uid == myUid) {
- if (Constants.LOGVV) {
- Log.d(TAG, "deleting spurious file " + path);
- }
- file.delete();
- }
- } catch (ErrnoException e) {
- Log.w(TAG, "stat(" + path + ") result: " + e);
- }
- }
- }
-
- /**
- * Drops old rows from the database to prevent it from growing too large
- * TODO logic in this method needs to be optimized. maintain the number of downloads
- * in memory - so that this method can limit the amount of data read.
- */
- private void trimDatabase() {
- if (Constants.LOGV) {
- Log.i(Constants.TAG, "in trimDatabase");
- }
- Cursor cursor = null;
- try {
- cursor = mContext.getContentResolver().query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
- new String[] { Downloads.Impl._ID },
- Downloads.Impl.COLUMN_STATUS + " >= '200'", null,
- Downloads.Impl.COLUMN_LAST_MODIFICATION);
- if (cursor == null) {
- // This isn't good - if we can't do basic queries in our database,
- // nothing's gonna work
- Log.e(Constants.TAG, "null cursor in trimDatabase");
- return;
- }
- if (cursor.moveToFirst()) {
- int numDelete = cursor.getCount() - Constants.MAX_DOWNLOADS;
- int columnId = cursor.getColumnIndexOrThrow(Downloads.Impl._ID);
- while (numDelete > 0) {
- Uri downloadUri = ContentUris.withAppendedId(
- Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, cursor.getLong(columnId));
- mContext.getContentResolver().delete(downloadUri, null, null);
- if (!cursor.moveToNext()) {
- break;
- }
- numDelete--;
- }
- }
- } catch (SQLiteException e) {
- // trimming the database raised an exception. alright, ignore the exception
- // and return silently. trimming database is not exactly a critical operation
- // and there is no need to propagate the exception.
- Log.w(Constants.TAG, "trimDatabase failed with exception: " + e.getMessage());
- return;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- private synchronized int incrementBytesDownloadedSinceLastCheckOnSpace(long val) {
- mBytesDownloadedSinceLastCheckOnSpace += val;
- return mBytesDownloadedSinceLastCheckOnSpace;
- }
-
- private synchronized void resetBytesDownloadedSinceLastCheckOnSpace() {
- mBytesDownloadedSinceLastCheckOnSpace = 0;
- }
-}
diff --git a/src/com/android/providers/downloads/StorageUtils.java b/src/com/android/providers/downloads/StorageUtils.java
new file mode 100644
index 00000000..1817c758
--- /dev/null
+++ b/src/com/android/providers/downloads/StorageUtils.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.providers.downloads;
+
+import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.provider.Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR;
+import static android.text.format.DateUtils.DAY_IN_MILLIS;
+import static com.android.providers.downloads.Constants.TAG;
+
+import android.app.DownloadManager;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.os.Environment;
+import android.provider.Downloads;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
+import android.system.StructStatVfs;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Sets;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Utility methods for managing storage space related to
+ * {@link DownloadManager}.
+ */
+public class StorageUtils {
+
+ /**
+ * Minimum age for a file to be considered for deletion.
+ */
+ static final long MIN_DELETE_AGE = DAY_IN_MILLIS;
+
+ /**
+ * Reserved disk space to avoid filling disk.
+ */
+ static final long RESERVED_BYTES = 32 * MB_IN_BYTES;
+
+ @VisibleForTesting
+ static boolean sForceFullEviction = false;
+
+ /**
+ * Ensure that requested free space exists on the partition backing the
+ * given {@link FileDescriptor}. If not enough space is available, it tries
+ * freeing up space as follows:
+ * <ul>
+ * <li>If backed by the data partition (including emulated external
+ * storage), then ask {@link PackageManager} to free space from cache
+ * directories.
+ * <li>If backed by the cache partition, then try deleting older downloads
+ * to free space.
+ * </ul>
+ */
+ public static void ensureAvailableSpace(Context context, FileDescriptor fd, long bytes)
+ throws IOException, StopRequestException {
+
+ long availBytes = getAvailableBytes(fd);
+ if (availBytes >= bytes) {
+ // Underlying partition has enough space; go ahead
+ return;
+ }
+
+ // Not enough space, let's try freeing some up. Start by tracking down
+ // the backing partition.
+ final long dev;
+ try {
+ dev = Os.fstat(fd).st_dev;
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+
+ final long dataDev = getDeviceId(Environment.getDataDirectory());
+ final long cacheDev = getDeviceId(Environment.getDownloadCacheDirectory());
+ final long externalDev = getDeviceId(Environment.getExternalStorageDirectory());
+
+ if (dev == dataDev || (dev == externalDev && Environment.isExternalStorageEmulated())) {
+ // File lives on internal storage; ask PackageManager to try freeing
+ // up space from cache directories.
+ final PackageManager pm = context.getPackageManager();
+ final ObserverLatch observer = new ObserverLatch();
+ pm.freeStorageAndNotify(sForceFullEviction ? Long.MAX_VALUE : bytes, observer);
+
+ try {
+ if (!observer.latch.await(30, TimeUnit.SECONDS)) {
+ throw new IOException("Timeout while freeing disk space");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+
+ } else if (dev == cacheDev) {
+ // Try removing old files on cache partition
+ freeCacheStorage(bytes);
+ }
+
+ // Did we free enough space?
+ availBytes = getAvailableBytes(fd);
+ if (availBytes < bytes) {
+ throw new StopRequestException(STATUS_INSUFFICIENT_SPACE_ERROR,
+ "Not enough free space; " + bytes + " requested, " + availBytes + " available");
+ }
+ }
+
+ /**
+ * Free requested space on cache partition, deleting oldest files first.
+ * We're only focused on freeing up disk space, and rely on the next orphan
+ * pass to clean up database entries.
+ */
+ private static void freeCacheStorage(long bytes) {
+ // Only consider finished downloads
+ final List<ConcreteFile> files = listFilesRecursive(
+ Environment.getDownloadCacheDirectory(), Constants.DIRECTORY_CACHE_RUNNING,
+ android.os.Process.myUid());
+
+ Slog.d(TAG, "Found " + files.size() + " downloads on cache");
+
+ Collections.sort(files, new Comparator<ConcreteFile>() {
+ @Override
+ public int compare(ConcreteFile lhs, ConcreteFile rhs) {
+ return (int) (lhs.file.lastModified() - rhs.file.lastModified());
+ }
+ });
+
+ final long now = System.currentTimeMillis();
+ for (ConcreteFile file : files) {
+ if (bytes <= 0) break;
+
+ if (now - file.file.lastModified() < MIN_DELETE_AGE) {
+ Slog.d(TAG, "Skipping recently modified " + file.file);
+ } else {
+ final long len = file.file.length();
+ Slog.d(TAG, "Deleting " + file.file + " to reclaim " + len);
+ bytes -= len;
+ file.file.delete();
+ }
+ }
+ }
+
+ /**
+ * Return number of available bytes on the filesystem backing the given
+ * {@link FileDescriptor}, minus any {@link #RESERVED_BYTES} buffer.
+ */
+ private static long getAvailableBytes(FileDescriptor fd) throws IOException {
+ try {
+ final StructStatVfs stat = Os.fstatvfs(fd);
+ return (stat.f_bavail * stat.f_bsize) - RESERVED_BYTES;
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ }
+
+ private static long getDeviceId(File file) {
+ try {
+ return Os.stat(file.getAbsolutePath()).st_dev;
+ } catch (ErrnoException e) {
+ // Safe since dev_t is uint
+ return -1;
+ }
+ }
+
+ /**
+ * Return list of all normal files under the given directory, traversing
+ * directories recursively.
+ *
+ * @param exclude ignore dirs with this name, or {@code null} to ignore.
+ * @param uid only return files owned by this UID, or {@code -1} to ignore.
+ */
+ static List<ConcreteFile> listFilesRecursive(File startDir, String exclude, int uid) {
+ final ArrayList<ConcreteFile> files = Lists.newArrayList();
+ final LinkedList<File> dirs = new LinkedList<File>();
+ dirs.add(startDir);
+ while (!dirs.isEmpty()) {
+ final File dir = dirs.removeFirst();
+ if (Objects.equals(dir.getName(), exclude)) continue;
+
+ final File[] children = dir.listFiles();
+ if (children == null) continue;
+
+ for (File child : children) {
+ if (child.isDirectory()) {
+ dirs.add(child);
+ } else if (child.isFile()) {
+ try {
+ final ConcreteFile file = new ConcreteFile(child);
+ if (uid == -1 || file.stat.st_uid == uid) {
+ files.add(file);
+ }
+ } catch (ErrnoException ignored) {
+ }
+ }
+ }
+ }
+ return files;
+ }
+
+ /**
+ * Concrete file on disk that has a backing device and inode. Faster than
+ * {@code realpath()} when looking for identical files.
+ */
+ static class ConcreteFile {
+ public final File file;
+ public final StructStat stat;
+
+ public ConcreteFile(File file) throws ErrnoException {
+ this.file = file;
+ this.stat = Os.lstat(file.getAbsolutePath());
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ result = 31 * result + (int) (stat.st_dev ^ (stat.st_dev >>> 32));
+ result = 31 * result + (int) (stat.st_ino ^ (stat.st_ino >>> 32));
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ConcreteFile) {
+ final ConcreteFile f = (ConcreteFile) o;
+ return (f.stat.st_dev == stat.st_dev) && (f.stat.st_ino == stat.st_ino);
+ }
+ return false;
+ }
+ }
+
+ static class ObserverLatch extends IPackageDataObserver.Stub {
+ public final CountDownLatch latch = new CountDownLatch(1);
+
+ @Override
+ public void onRemoveCompleted(String packageName, boolean succeeded) {
+ latch.countDown();
+ }
+ }
+}
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index d520123f..ec73ca2e 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -19,6 +19,8 @@
package="com.android.providers.downloads.tests"
android:sharedUserId="android.media">
+ <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED" />
+
<application>
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java b/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java
index 3b937389..28c5dc7d 100644
--- a/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java
+++ b/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java
@@ -74,15 +74,18 @@ public abstract class AbstractDownloadProviderFunctionalTest extends
static class MockContentResolverWithNotify extends MockContentResolver {
public boolean mNotifyWasCalled = false;
+ public MockContentResolverWithNotify(Context context) {
+ super(context);
+ }
+
public synchronized void resetNotified() {
mNotifyWasCalled = false;
}
@Override
- public synchronized void notifyChange(Uri uri, ContentObserver observer,
- boolean syncToNetwork) {
+ public synchronized void notifyChange(
+ Uri uri, ContentObserver observer, boolean syncToNetwork) {
mNotifyWasCalled = true;
- notifyAll();
}
}
@@ -94,20 +97,17 @@ public abstract class AbstractDownloadProviderFunctionalTest extends
static class TestContext extends RenamingDelegatingContext {
private static final String FILENAME_PREFIX = "test.";
- private ContentResolver mResolver;
+ private final ContentResolver mResolver;
private final NotificationManager mNotifManager;
boolean mHasServiceBeenStarted = false;
public TestContext(Context realContext) {
super(realContext, FILENAME_PREFIX);
+ mResolver = new MockContentResolverWithNotify(this);
mNotifManager = mock(NotificationManager.class);
}
- public void setResolver(ContentResolver resolver) {
- mResolver = resolver;
- }
-
/**
* Direct DownloadService to our test instance of DownloadProvider.
*/
@@ -156,12 +156,20 @@ public abstract class AbstractDownloadProviderFunctionalTest extends
System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
final Context realContext = getContext();
+
mTestContext = new TestContext(realContext);
- setupProviderAndResolver();
- mTestContext.setResolver(mResolver);
+ mResolver = (MockContentResolverWithNotify) mTestContext.getContentResolver();
+
+ final DownloadProvider provider = new DownloadProvider();
+ provider.mSystemFacade = mSystemFacade;
+ provider.attachInfo(mTestContext, null);
+
+ mResolver.addProvider(PROVIDER_AUTHORITY, provider);
+
setContext(mTestContext);
setupService();
getService().mSystemFacade = mSystemFacade;
+
mSystemFacade.setUp();
assertTrue(isDatabaseEmpty()); // ensure we're not messing with real data
mServer = new MockWebServer();
@@ -186,14 +194,6 @@ public abstract class AbstractDownloadProviderFunctionalTest extends
}
}
- void setupProviderAndResolver() {
- DownloadProvider provider = new DownloadProvider();
- provider.mSystemFacade = mSystemFacade;
- provider.attachInfo(mTestContext, null);
- mResolver = new MockContentResolverWithNotify();
- mResolver.addProvider(PROVIDER_AUTHORITY, provider);
- }
-
/**
* Remove any downloaded files and delete any lingering downloads.
*/
diff --git a/tests/src/com/android/providers/downloads/AbstractPublicApiTest.java b/tests/src/com/android/providers/downloads/AbstractPublicApiTest.java
index 348dbd1b..2846c7af 100644
--- a/tests/src/com/android/providers/downloads/AbstractPublicApiTest.java
+++ b/tests/src/com/android/providers/downloads/AbstractPublicApiTest.java
@@ -28,6 +28,9 @@ import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.util.Log;
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
@@ -91,19 +94,23 @@ public abstract class AbstractPublicApiTest extends AbstractDownloadProviderFunc
}
}
- String getContents() throws Exception {
+ byte[] getRawContents() throws Exception {
ParcelFileDescriptor downloadedFile = mManager.openDownloadedFile(mId);
assertTrue("Invalid file descriptor: " + downloadedFile,
downloadedFile.getFileDescriptor().valid());
- final InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(
+ final InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
downloadedFile);
try {
- return readStream(stream);
+ return Streams.readFully(is);
} finally {
- stream.close();
+ IoUtils.closeQuietly(is);
}
}
+ String getContents() throws Exception {
+ return new String(getRawContents());
+ }
+
void runUntilStatus(int status) throws TimeoutException {
final long startMillis = mSystemFacade.currentTimeMillis();
startService(null);
diff --git a/tests/src/com/android/providers/downloads/FakeSystemFacade.java b/tests/src/com/android/providers/downloads/FakeSystemFacade.java
index d54c1224..5a15d399 100644
--- a/tests/src/com/android/providers/downloads/FakeSystemFacade.java
+++ b/tests/src/com/android/providers/downloads/FakeSystemFacade.java
@@ -64,12 +64,12 @@ public class FakeSystemFacade implements SystemFacade {
@Override
public Long getMaxBytesOverMobile() {
- return mMaxBytesOverMobile ;
+ return mMaxBytesOverMobile;
}
@Override
public Long getRecommendedMaxBytesOverMobile() {
- return mRecommendedMaxBytesOverMobile ;
+ return mRecommendedMaxBytesOverMobile;
}
@Override
diff --git a/tests/src/com/android/providers/downloads/HelpersTest.java b/tests/src/com/android/providers/downloads/HelpersTest.java
index 50f4c44c..121b7cda 100644
--- a/tests/src/com/android/providers/downloads/HelpersTest.java
+++ b/tests/src/com/android/providers/downloads/HelpersTest.java
@@ -16,29 +16,73 @@
package com.android.providers.downloads;
+import android.net.Uri;
import android.provider.Downloads;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
/**
* This test exercises methods in the {@Helpers} utility class.
*/
-@LargeTest
+@SmallTest
public class HelpersTest extends AndroidTestCase {
- public HelpersTest() {
+ @Override
+ protected void tearDown() throws Exception {
+ IoUtils.deleteContents(getContext().getFilesDir());
+ IoUtils.deleteContents(getContext().getCacheDir());
+
+ super.tearDown();
+ }
+
+ public void testGenerateSaveFile() throws Exception {
+ final File expected = new File(getContext().getFilesDir(), "file.mp4");
+ final String actual = Helpers.generateSaveFile(getContext(),
+ "http://example.com/file.txt", null, null, null,
+ "video/mp4", Downloads.Impl.DESTINATION_CACHE_PARTITION);
+ assertEquals(expected.getAbsolutePath(), actual);
+ }
+
+ public void testGenerateSaveFileDupes() throws Exception {
+ final File expected1 = new File(getContext().getFilesDir(), "file.txt");
+ final String actual1 = Helpers.generateSaveFile(getContext(), "http://example.com/file.txt",
+ null, null, null, null, Downloads.Impl.DESTINATION_CACHE_PARTITION);
+
+ final File expected2 = new File(getContext().getFilesDir(), "file-1.txt");
+ final String actual2 = Helpers.generateSaveFile(getContext(), "http://example.com/file.txt",
+ null, null, null, null, Downloads.Impl.DESTINATION_CACHE_PARTITION);
+
+ assertEquals(expected1.getAbsolutePath(), actual1);
+ assertEquals(expected2.getAbsolutePath(), actual2);
}
- public void testGetFullPath() throws Exception {
- String hint = "file:///com.android.providers.downloads/test";
+ public void testGenerateSaveFileNoExtension() throws Exception {
+ final File expected = new File(getContext().getFilesDir(), "file.mp4");
+ final String actual = Helpers.generateSaveFile(getContext(),
+ "http://example.com/file", null, null, null,
+ "video/mp4", Downloads.Impl.DESTINATION_CACHE_PARTITION);
+ assertEquals(expected.getAbsolutePath(), actual);
+ }
+
+ public void testGenerateSaveFileHint() throws Exception {
+ final File expected = new File(getContext().getFilesDir(), "meow");
+ final String hint = Uri.fromFile(expected).toString();
- // Test that we never change requested filename.
- String fileName = Helpers.getFullPath(
- hint,
- "video/mp4", // MIME type corresponding to file extension .mp4
- Downloads.Impl.DESTINATION_FILE_URI,
- null);
- assertEquals(hint, fileName);
+ // Test that we never change requested filename.
+ final String actual = Helpers.generateSaveFile(getContext(), "url", hint,
+ "dispo", "locat", "video/mp4", Downloads.Impl.DESTINATION_FILE_URI);
+ assertEquals(expected.getAbsolutePath(), actual);
}
+ public void testGenerateSaveFileDisposition() throws Exception {
+ final File expected = new File(getContext().getFilesDir(), "real.mp4");
+ final String actual = Helpers.generateSaveFile(getContext(),
+ "http://example.com/file.txt", null, "attachment; filename=\"subdir/real.pdf\"",
+ null, "video/mp4", Downloads.Impl.DESTINATION_CACHE_PARTITION);
+ assertEquals(expected.getAbsolutePath(), actual);
+ }
}
diff --git a/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java b/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java
index bde95815..d7b389c5 100644
--- a/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java
+++ b/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java
@@ -53,6 +53,8 @@ import com.google.mockwebserver.MockResponse;
import com.google.mockwebserver.RecordedRequest;
import com.google.mockwebserver.SocketPolicy;
+import libcore.io.IoUtils;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -83,9 +85,7 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
mTestDirectory = new File(Environment.getExternalStorageDirectory() + File.separator
+ "download_manager_functional_test");
if (mTestDirectory.exists()) {
- for (File file : mTestDirectory.listFiles()) {
- file.delete();
- }
+ IoUtils.deleteContents(mTestDirectory);
} else {
mTestDirectory.mkdir();
}
@@ -94,9 +94,7 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
@Override
protected void tearDown() throws Exception {
if (mTestDirectory != null && mTestDirectory.exists()) {
- for (File file : mTestDirectory.listFiles()) {
- file.delete();
- }
+ IoUtils.deleteContents(mTestDirectory);
mTestDirectory.delete();
}
super.tearDown();
@@ -223,7 +221,7 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
boolean isFirstResponse = (start == 0);
int status = isFirstResponse ? HTTP_OK : HTTP_PARTIAL;
MockResponse response = buildResponse(status, FILE_CONTENT.substring(start, end))
- .setHeader("Content-length", totalLength)
+ .setHeader("Content-length", isFirstResponse ? totalLength : (end - start))
.setHeader("Etag", ETAG);
if (!isFirstResponse) {
response.setHeader(
@@ -475,7 +473,7 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
// 2. Try resuming A, but fail ETag check
mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
download.runUntilStatus(STATUS_FAILED);
- assertEquals(HTTP_PRECON_FAILED, download.getReason());
+ assertEquals(DownloadManager.ERROR_CANNOT_RESUME, download.getReason());
req = takeRequest();
assertEquals("bytes=2-", getHeaderValue(req, "Range"));
assertEquals(A, getHeaderValue(req, "If-Match"));
diff --git a/tests/src/com/android/providers/downloads/StorageTest.java b/tests/src/com/android/providers/downloads/StorageTest.java
new file mode 100644
index 00000000..8ba3cbce
--- /dev/null
+++ b/tests/src/com/android/providers/downloads/StorageTest.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.providers.downloads;
+
+import static android.app.DownloadManager.COLUMN_REASON;
+import static android.app.DownloadManager.ERROR_INSUFFICIENT_SPACE;
+import static android.app.DownloadManager.STATUS_FAILED;
+import static android.app.DownloadManager.STATUS_SUCCESSFUL;
+import static android.provider.Downloads.Impl.DESTINATION_CACHE_PARTITION;
+import static android.provider.Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION;
+
+import android.app.DownloadManager;
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.os.StatFs;
+import android.provider.Downloads.Impl;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStatVfs;
+import android.test.MoreAsserts;
+import android.util.Log;
+
+import com.android.providers.downloads.StorageUtils.ObserverLatch;
+import com.google.mockwebserver.MockResponse;
+import com.google.mockwebserver.SocketPolicy;
+
+import libcore.io.ForwardingOs;
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+public class StorageTest extends AbstractPublicApiTest {
+ private static final String TAG = "StorageTest";
+
+ private static final int DOWNLOAD_SIZE = 512 * 1024;
+ private static final byte[] DOWNLOAD_BODY;
+
+ static {
+ DOWNLOAD_BODY = new byte[DOWNLOAD_SIZE];
+ for (int i = 0; i < DOWNLOAD_SIZE; i++) {
+ DOWNLOAD_BODY[i] = (byte) (i % 32);
+ }
+ }
+
+ private libcore.io.Os mOriginal;
+ private long mStealBytes;
+
+ public StorageTest() {
+ super(new FakeSystemFacade());
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ StorageUtils.sForceFullEviction = true;
+ mStealBytes = 0;
+
+ mOriginal = libcore.io.Libcore.os;
+ libcore.io.Libcore.os = new ForwardingOs(mOriginal) {
+ @Override
+ public StructStatVfs statvfs(String path) throws ErrnoException {
+ return stealBytes(os.statvfs(path));
+ }
+
+ @Override
+ public StructStatVfs fstatvfs(FileDescriptor fd) throws ErrnoException {
+ return stealBytes(os.fstatvfs(fd));
+ }
+
+ private StructStatVfs stealBytes(StructStatVfs s) {
+ final long stealBlocks = (mStealBytes + (s.f_bsize - 1)) / s.f_bsize;
+ final long f_bavail = s.f_bavail - stealBlocks;
+ return new StructStatVfs(s.f_bsize, s.f_frsize, s.f_blocks, s.f_bfree, f_bavail,
+ s.f_files, s.f_ffree, s.f_favail, s.f_fsid, s.f_flag, s.f_namemax);
+ }
+ };
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ StorageUtils.sForceFullEviction = false;
+ mStealBytes = 0;
+
+ if (mOriginal != null) {
+ libcore.io.Libcore.os = mOriginal;
+ }
+ }
+
+ private enum CacheStatus { CLEAN, DIRTY }
+ private enum BodyType { COMPLETE, CHUNKED }
+
+ public void testDataDirtyComplete() throws Exception {
+ prepareAndRunDownload(DESTINATION_CACHE_PARTITION,
+ CacheStatus.DIRTY, BodyType.COMPLETE,
+ STATUS_SUCCESSFUL, -1);
+ }
+
+ public void testDataDirtyChunked() throws Exception {
+ prepareAndRunDownload(DESTINATION_CACHE_PARTITION,
+ CacheStatus.DIRTY, BodyType.CHUNKED,
+ STATUS_SUCCESSFUL, -1);
+ }
+
+ public void testDataCleanComplete() throws Exception {
+ prepareAndRunDownload(DESTINATION_CACHE_PARTITION,
+ CacheStatus.CLEAN, BodyType.COMPLETE,
+ STATUS_FAILED, ERROR_INSUFFICIENT_SPACE);
+ }
+
+ public void testDataCleanChunked() throws Exception {
+ prepareAndRunDownload(DESTINATION_CACHE_PARTITION,
+ CacheStatus.CLEAN, BodyType.CHUNKED,
+ STATUS_FAILED, ERROR_INSUFFICIENT_SPACE);
+ }
+
+ public void testCacheDirtyComplete() throws Exception {
+ prepareAndRunDownload(DESTINATION_SYSTEMCACHE_PARTITION,
+ CacheStatus.DIRTY, BodyType.COMPLETE,
+ STATUS_SUCCESSFUL, -1);
+ }
+
+ public void testCacheDirtyChunked() throws Exception {
+ prepareAndRunDownload(DESTINATION_SYSTEMCACHE_PARTITION,
+ CacheStatus.DIRTY, BodyType.CHUNKED,
+ STATUS_SUCCESSFUL, -1);
+ }
+
+ public void testCacheCleanComplete() throws Exception {
+ prepareAndRunDownload(DESTINATION_SYSTEMCACHE_PARTITION,
+ CacheStatus.CLEAN, BodyType.COMPLETE,
+ STATUS_FAILED, ERROR_INSUFFICIENT_SPACE);
+ }
+
+ public void testCacheCleanChunked() throws Exception {
+ prepareAndRunDownload(DESTINATION_SYSTEMCACHE_PARTITION,
+ CacheStatus.CLEAN, BodyType.CHUNKED,
+ STATUS_FAILED, ERROR_INSUFFICIENT_SPACE);
+ }
+
+ private void prepareAndRunDownload(
+ int dest, CacheStatus cache, BodyType body, int expectedStatus, int expectedReason)
+ throws Exception {
+
+ // Ensure that we've purged everything possible for destination
+ final File dirtyDir;
+ if (dest == DESTINATION_CACHE_PARTITION) {
+ final PackageManager pm = getContext().getPackageManager();
+ final ObserverLatch observer = new ObserverLatch();
+ pm.freeStorageAndNotify(Long.MAX_VALUE, observer);
+
+ try {
+ if (!observer.latch.await(30, TimeUnit.SECONDS)) {
+ throw new IOException("Timeout while freeing disk space");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+
+ dirtyDir = getContext().getCacheDir();
+
+ } else if (dest == DESTINATION_SYSTEMCACHE_PARTITION) {
+ IoUtils.deleteContents(Environment.getDownloadCacheDirectory());
+ dirtyDir = Environment.getDownloadCacheDirectory();
+
+ } else {
+ throw new IllegalArgumentException("Unknown destination");
+ }
+
+ // Allocate a cache file, if requested, making it large enough and old
+ // enough to clear.
+ final File dirtyFile;
+ if (cache == CacheStatus.DIRTY) {
+ dirtyFile = new File(dirtyDir, "cache_file.bin");
+ assertTrue(dirtyFile.createNewFile());
+ final FileOutputStream os = new FileOutputStream(dirtyFile);
+ final int dirtySize = (DOWNLOAD_SIZE * 3) / 2;
+ Os.posix_fallocate(os.getFD(), 0, dirtySize);
+ IoUtils.closeQuietly(os);
+
+ dirtyFile.setLastModified(
+ System.currentTimeMillis() - (StorageUtils.MIN_DELETE_AGE * 2));
+ } else {
+ dirtyFile = null;
+ }
+
+ // At this point, hide all other disk space to make the download fail;
+ // if we have a dirty cache file it can be cleared to let us proceed.
+ final long targetFree = StorageUtils.RESERVED_BYTES + (DOWNLOAD_SIZE / 2);
+
+ final StatFs stat = new StatFs(dirtyDir.getAbsolutePath());
+ Log.d(TAG, "Available bytes (before steal): " + stat.getAvailableBytes());
+ mStealBytes = stat.getAvailableBytes() - targetFree;
+
+ stat.restat(dirtyDir.getAbsolutePath());
+ Log.d(TAG, "Available bytes (after steal): " + stat.getAvailableBytes());
+
+ final MockResponse resp = new MockResponse().setResponseCode(200)
+ .setHeader("Content-type", "text/plain")
+ .setSocketPolicy(SocketPolicy.DISCONNECT_AT_END);
+ if (body == BodyType.CHUNKED) {
+ resp.setChunkedBody(DOWNLOAD_BODY, 1021);
+ } else {
+ resp.setBody(DOWNLOAD_BODY);
+ }
+ enqueueResponse(resp);
+
+ final DownloadManager.Request req = getRequest();
+ if (dest == Impl.DESTINATION_SYSTEMCACHE_PARTITION) {
+ req.setDestinationToSystemCache();
+ }
+ final Download download = enqueueRequest(req);
+ download.runUntilStatus(expectedStatus);
+
+ if (expectedStatus == STATUS_SUCCESSFUL) {
+ MoreAsserts.assertEquals(DOWNLOAD_BODY, download.getRawContents());
+ }
+
+ if (expectedReason != -1) {
+ assertEquals(expectedReason, download.getLongField(COLUMN_REASON));
+ }
+
+ if (dirtyFile != null) {
+ assertFalse(dirtyFile.exists());
+ }
+ }
+}
diff --git a/tests/src/com/android/providers/downloads/ThreadingTest.java b/tests/src/com/android/providers/downloads/ThreadingTest.java
index 920f703b..1e501444 100644
--- a/tests/src/com/android/providers/downloads/ThreadingTest.java
+++ b/tests/src/com/android/providers/downloads/ThreadingTest.java
@@ -27,6 +27,7 @@ import com.google.android.collect.Sets;
import com.google.mockwebserver.MockResponse;
import com.google.mockwebserver.SocketPolicy;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -60,9 +61,10 @@ public class ThreadingTest extends AbstractPublicApiTest {
public void testFilenameRace() throws Exception {
final List<Pair<Download, String>> downloads = Lists.newArrayList();
+ final HashSet<String> expectedBodies = Sets.newHashSet();
// Request dozen files at once with same name
- for (int i = 0; i < 12; i++) {
+ for (int i = 0; i < 32; i++) {
final String body = "DOWNLOAD " + i + " CONTENTS";
enqueueResponse(new MockResponse().setResponseCode(HTTP_OK).setBody(body)
.setHeader("Content-type", "text/plain")
@@ -70,6 +72,7 @@ public class ThreadingTest extends AbstractPublicApiTest {
final Download d = enqueueRequest(getRequest());
downloads.add(Pair.create(d, body));
+ expectedBodies.add(body);
}
// Kick off downloads in parallel
@@ -82,6 +85,7 @@ public class ThreadingTest extends AbstractPublicApiTest {
// Ensure that contents are clean and filenames unique
final Set<String> seenFiles = Sets.newHashSet();
+ final HashSet<String> actualBodies = Sets.newHashSet();
for (Pair<Download, String> d : downloads) {
final String file = d.first.getStringField(DownloadManager.COLUMN_LOCAL_FILENAME);
@@ -91,7 +95,10 @@ public class ThreadingTest extends AbstractPublicApiTest {
final String expected = d.second;
final String actual = d.first.getContents();
- assertEquals(expected, actual);
+
+ actualBodies.add(actual);
}
+
+ assertEquals(expectedBodies, actualBodies);
}
}
diff --git a/ui/res/anim/footer_appear.xml b/ui/res/anim/footer_appear.xml
deleted file mode 100644
index aacfd035..00000000
--- a/ui/res/anim/footer_appear.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-** Copyright 2010, Google Inc.
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <translate
- android:interpolator="@android:anim/decelerate_interpolator"
- android:fromYDelta="+12%p"
- android:toYDelta="0"
- android:duration="300" />
-</set>
diff --git a/ui/res/anim/footer_disappear.xml b/ui/res/anim/footer_disappear.xml
deleted file mode 100644
index d87be6ab..00000000
--- a/ui/res/anim/footer_disappear.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-** Copyright 2010, Google Inc.
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <translate
- android:interpolator="@android:anim/decelerate_interpolator"
- android:fromYDelta="0"
- android:toYDelta="+12%p"
- android:duration="300" />
-</set>
diff --git a/ui/res/drawable-hdpi/ic_download_misc_file_type.png b/ui/res/drawable-hdpi/ic_download_misc_file_type.png
deleted file mode 100644
index dab3b6e1..00000000
--- a/ui/res/drawable-hdpi/ic_download_misc_file_type.png
+++ /dev/null
Binary files differ
diff --git a/ui/res/drawable-hdpi/ic_launcher_drm_file.png b/ui/res/drawable-hdpi/ic_launcher_drm_file.png
deleted file mode 100644
index 9df1c556..00000000
--- a/ui/res/drawable-hdpi/ic_launcher_drm_file.png
+++ /dev/null
Binary files differ
diff --git a/ui/res/drawable-hdpi/ic_menu_desk_clock.png b/ui/res/drawable-hdpi/ic_menu_desk_clock.png
deleted file mode 100644
index 4101434e..00000000
--- a/ui/res/drawable-hdpi/ic_menu_desk_clock.png
+++ /dev/null
Binary files differ
diff --git a/ui/res/drawable-mdpi/ic_download_misc_file_type.png b/ui/res/drawable-mdpi/ic_download_misc_file_type.png
deleted file mode 100644
index ceed70cf..00000000
--- a/ui/res/drawable-mdpi/ic_download_misc_file_type.png
+++ /dev/null
Binary files differ
diff --git a/ui/res/drawable-mdpi/ic_launcher_drm_file.png b/ui/res/drawable-mdpi/ic_launcher_drm_file.png
deleted file mode 100644
index 57378b23..00000000
--- a/ui/res/drawable-mdpi/ic_launcher_drm_file.png
+++ /dev/null
Binary files differ
diff --git a/ui/res/layout/download_list.xml b/ui/res/layout/download_list.xml
deleted file mode 100644
index a0ff5ff2..00000000
--- a/ui/res/layout/download_list.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:divider="?android:attr/dividerHorizontal"
- android:showDividers="middle"
- android:dividerPadding="16dip">
-
- <!-- The main area showing the list of downloads -->
- <FrameLayout android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1">
-
- <ExpandableListView android:id="@+id/date_ordered_list"
- android:paddingStart="16dip"
- android:paddingEnd="16dip"
- android:paddingBottom="16dip"
- android:clipToPadding="false"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scrollbarStyle="outsideOverlay" />
- <ListView android:id="@+id/size_ordered_list"
- android:paddingStart="16dip"
- android:paddingEnd="16dip"
- android:paddingBottom="16dip"
- android:clipToPadding="false"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scrollbarStyle="outsideOverlay" />
- <TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/empty"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:text="@string/no_downloads"
- android:gravity="center"
- android:textStyle="bold"/>
- </FrameLayout>
-
- <!-- The selection menu that pops up from the bottom of the screen -->
- <LinearLayout android:id="@+id/sort_menu"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- style="?android:attr/buttonBarStyle">
-
- <Button android:id="@+id/sort_button"
- style="?android:attr/buttonBarButtonStyle"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="match_parent"/>
- </LinearLayout>
-</LinearLayout>
diff --git a/ui/res/layout/download_list_item.xml b/ui/res/layout/download_list_item.xml
deleted file mode 100644
index 2435ba7f..00000000
--- a/ui/res/layout/download_list_item.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<com.android.providers.downloads.ui.DownloadItem
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="8dip"
- android:paddingBottom="8dip"
- android:columnCount="4"
- android:descendantFocusability="blocksDescendants">
-
- <!-- Clicks are handled directly by DownloadItem -->
- <CheckBox
- android:id="@+id/download_checkbox"
- android:layout_rowSpan="3"
- android:layout_gravity="center_vertical"
- android:clickable="false" />
-
- <ImageView
- android:id="@+id/download_icon"
- android:layout_width="@android:dimen/app_icon_size"
- android:layout_height="@android:dimen/app_icon_size"
- android:layout_rowSpan="3"
- android:layout_marginEnd="8dip"
- android:layout_gravity="center_vertical"
- android:scaleType="centerInside"
- android:contentDescription="@null" />
-
- <TextView
- android:id="@+id/download_title"
- android:layout_width="0dip"
- android:layout_columnSpan="2"
- android:layout_gravity="fill_horizontal"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textStyle="bold"
- android:textAppearance="?android:attr/textAppearance"
- android:textAlignment="viewStart" />
-
- <TextView
- android:id="@+id/domain"
- android:layout_width="0dip"
- android:layout_columnSpan="2"
- android:layout_gravity="fill_horizontal"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAlignment="viewStart" />
-
- <TextView
- android:id="@+id/size_text"
- android:layout_width="0dip"
- android:layout_gravity="fill_horizontal"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAlignment="viewStart" />
-
- <TextView
- android:id="@+id/status_text"
- android:layout_marginStart="8dip"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAlignment="viewStart" />
-
-</com.android.providers.downloads.ui.DownloadItem>
diff --git a/ui/res/layout/list_group_header.xml b/ui/res/layout/list_group_header.xml
deleted file mode 100644
index 466cd6c6..00000000
--- a/ui/res/layout/list_group_header.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:paddingStart="?android:attr/expandableListPreferredItemPaddingLeft"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:gravity="center_vertical" />
diff --git a/ui/res/menu/download_menu.xml b/ui/res/menu/download_menu.xml
deleted file mode 100644
index a33dd52b..00000000
--- a/ui/res/menu/download_menu.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/share_download"
- android:icon="@android:drawable/ic_menu_share"
- android:title="@string/download_share_dialog"
- android:showAsAction="always" />
-
- <item android:id="@+id/delete_download"
- android:icon="@android:drawable/ic_menu_delete"
- android:title="@string/delete_download"
- android:showAsAction="always" />
-</menu>
diff --git a/ui/res/mipmap-hdpi/ic_launcher_download.png b/ui/res/mipmap-hdpi/ic_launcher_download.png
index 2450cfbb..f958bbd3 100644
--- a/ui/res/mipmap-hdpi/ic_launcher_download.png
+++ b/ui/res/mipmap-hdpi/ic_launcher_download.png
Binary files differ
diff --git a/ui/res/mipmap-mdpi/ic_launcher_download.png b/ui/res/mipmap-mdpi/ic_launcher_download.png
index 7b56ada3..f2e93766 100644
--- a/ui/res/mipmap-mdpi/ic_launcher_download.png
+++ b/ui/res/mipmap-mdpi/ic_launcher_download.png
Binary files differ
diff --git a/ui/res/mipmap-xhdpi/ic_launcher_download.png b/ui/res/mipmap-xhdpi/ic_launcher_download.png
index 775004f2..4dc53363 100644
--- a/ui/res/mipmap-xhdpi/ic_launcher_download.png
+++ b/ui/res/mipmap-xhdpi/ic_launcher_download.png
Binary files differ
diff --git a/ui/res/mipmap-xxhdpi/ic_launcher_download.png b/ui/res/mipmap-xxhdpi/ic_launcher_download.png
index ed8c7827..87162909 100644
--- a/ui/res/mipmap-xxhdpi/ic_launcher_download.png
+++ b/ui/res/mipmap-xxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/ui/res/mipmap-xxxhdpi/ic_launcher_download.png b/ui/res/mipmap-xxxhdpi/ic_launcher_download.png
index 2dbe0f2d..f5be2199 100644
--- a/ui/res/mipmap-xxxhdpi/ic_launcher_download.png
+++ b/ui/res/mipmap-xxxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/ui/res/values-ms/strings.xml b/ui/res/values-az-rAZ/strings.xml
index e1e9f666..5ee50dfe 100644
--- a/ui/res/values-ms/strings.xml
+++ b/ui/res/values-az-rAZ/strings.xml
@@ -16,35 +16,35 @@
<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="3070921713463294774">"Muat turun"</string>
- <string name="download_title_sorted_by_date" msgid="5898014492155434221">"Muat turun - Diisih mengikut tarikh"</string>
- <string name="download_title_sorted_by_size" msgid="1417193166677094813">"Muat turun - Diisih mengikut saiz"</string>
- <string name="no_downloads" msgid="1029667411186146836">"Tiada muat turun."</string>
- <string name="missing_title" msgid="830115697868833773">"&lt;Tidak diketahui&gt;"</string>
- <string name="button_sort_by_size" msgid="7331549713691146251">"Isih mengikut saiz"</string>
- <string name="button_sort_by_date" msgid="8800842892684101528">"Isih mengikut tarikh"</string>
- <string name="download_queued" msgid="104973307780629904">"Baris gilir"</string>
- <string name="download_running" msgid="4656462962155580641">"Sdg dijlnkn"</string>
- <string name="download_success" msgid="7006048006543495236">"Selesai"</string>
- <string name="download_error" msgid="8081329546008568251">"Tidak berjaya"</string>
- <string name="dialog_title_not_available" msgid="5746317632356158515">"Tidak dapat memuat turun"</string>
- <string name="dialog_failed_body" msgid="587545111677064427">"Adakah anda mahu mencuba semula muat turun fail kemudian atau memadamnya dari baris gilir?"</string>
- <string name="dialog_title_queued_body" msgid="6760681913815015219">"Fail dalam giliran"</string>
- <string name="dialog_queued_body" msgid="708552801635572720">"Fail ini digilirkan untuk muat turun pada masa akan datang jadi ia belum lagi tersedia."</string>
- <string name="dialog_file_missing_body" msgid="3223012612774276284">"Tidak dapat mencari fail yang dimuat turun."</string>
- <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"Tidak dapat menyelesaikan muat turun. Ruang pada storan luaran tidak mencukupi."</string>
- <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"Tidak dapat menyelesaikan muat turun. Ruang pada storan muat turun dalaman tidak mencukupi."</string>
- <string name="dialog_cannot_resume" msgid="8664509751358983543">"Muat turun terganggu dan tidak dapat disambung semula."</string>
- <string name="dialog_file_already_exists" msgid="8308563940663449590">"Tidak dapat memuat turun. Fail destinasi sudah pun wujud."</string>
- <string name="dialog_media_not_found" msgid="4468088418758018765">"Tidak dapat memuat turun. Media luaran tidak tersedia."</string>
- <string name="download_no_application_title" msgid="7024782176657362251">"Tidak dapat membuka fail"</string>
- <string name="remove_download" msgid="6372920256257247857">"Alih keluar"</string>
- <string name="delete_download" msgid="76629022653866471">"Padam"</string>
- <string name="keep_queued_download" msgid="5144882786014818569">"Simpan"</string>
- <string name="cancel_running_download" msgid="5232704030969221112">"Batal"</string>
- <string name="retry_download" msgid="7617100787922717912">"Cuba semula"</string>
- <string name="deselect_all" msgid="6348198946254776764">"Nyahpilih semua"</string>
- <string name="select_all" msgid="634074918366265804">"Pilih semua"</string>
- <string name="selected_count" msgid="2101564570019753277">"Pilihan <xliff:g id="NUMBER">%1$d</xliff:g> dari <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
- <string name="download_share_dialog" msgid="3355867339806448955">"Kongsi melalui"</string>
+ <string name="app_label" msgid="3070921713463294774">"Endirmələr"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"Endirilənlər - Tarixə görə sıralanıb"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"Endirilənlər - Ölçüsünə görə sıralanıb"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"Endirmə yoxdur."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;Bilinməyən&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"Ölçüsünə görə sırala"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"Tarixə görə sırala"</string>
+ <string name="download_queued" msgid="104973307780629904">"Növbəyə salınıb"</string>
+ <string name="download_running" msgid="4656462962155580641">"Davam edir"</string>
+ <string name="download_success" msgid="7006048006543495236">"Tamamlandı"</string>
+ <string name="download_error" msgid="8081329546008568251">"Nəticəsiz"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"Endirilmədi"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"Faylı yenidən endirmək istəyirsiniz yoxsa sıradan silmək istəyirsiniz?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"Növbədəki fayl"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"Bu fayl gələcək endirmə üçün növbəyə salındı, buna görə hələ mövcud deyil."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"Endirilmiş fayl tapılmır."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"Endirmə tamamlanmadı. Xarici yaddaşda kifayət qədər yer yoxdur"</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"Endirmə tamamlanmadı. Daxili endirmə yaddaşında kifayət qədər yer yoxdur."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"Endirmə kəsildi və bərpa edilə bilməz."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"Endirilmir. Hədəf fayl artıq mövcuddur."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"Endirilmədi. Xarici media mövcud deyil."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"Fayl açılmır"</string>
+ <string name="remove_download" msgid="6372920256257247857">"Yığışdır"</string>
+ <string name="delete_download" msgid="76629022653866471">"Sil"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"Saxla"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"Ləğv et"</string>
+ <string name="retry_download" msgid="7617100787922717912">"Yeniden yoxla"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"Hamısını qaldır"</string>
+ <string name="select_all" msgid="634074918366265804">"Hamısını seç"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="TOTAL">%2$d</xliff:g> içindən seçilmiş <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"Vasitəsilə paylaş"</string>
</resources>
diff --git a/ui/res/values-be/strings.xml b/ui/res/values-be/strings.xml
deleted file mode 100644
index 6d0ca937..00000000
--- a/ui/res/values-be/strings.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="3070921713463294774">"Спампоўкі"</string>
- <string name="download_title_sorted_by_date" msgid="5898014492155434221">"Запампаванае - Сартаванне паводле даты"</string>
- <string name="download_title_sorted_by_size" msgid="1417193166677094813">"Запампаванае - Сартаванне паводле памеру"</string>
- <string name="no_downloads" msgid="1029667411186146836">"Няма спамповак."</string>
- <string name="missing_title" msgid="830115697868833773">"Невядомы"</string>
- <string name="button_sort_by_size" msgid="7331549713691146251">"Сартаваць паводле памеру"</string>
- <string name="button_sort_by_date" msgid="8800842892684101528">"Сартаваць паводле даты"</string>
- <string name="download_queued" msgid="104973307780629904">"У чарзе"</string>
- <string name="download_running" msgid="4656462962155580641">"Выконваецца"</string>
- <string name="download_success" msgid="7006048006543495236">"Гатова"</string>
- <string name="download_error" msgid="8081329546008568251">"Няўдала"</string>
- <string name="dialog_title_not_available" msgid="5746317632356158515">"Не атрымалася спампаваць"</string>
- <string name="dialog_failed_body" msgid="587545111677064427">"Жадаеце паўтарыць спампоўванне файла пазней або выдаліць яго з чаргі?"</string>
- <string name="dialog_title_queued_body" msgid="6760681913815015219">"Файл у чарзе"</string>
- <string name="dialog_queued_body" msgid="708552801635572720">"Гэты файл знаходзіцца ў чарзе на спампоўку і пакуль недаступны."</string>
- <string name="dialog_file_missing_body" msgid="3223012612774276284">"Немагчыма знайсці спампаваны файл."</string>
- <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"Немагчыма завершыць спампоўку. Не хапае месца на знешнім назапашвальнiку."</string>
- <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"Немагчыма скончыць спампоўку. Не хапае месца ва ўнутраным сховішчы."</string>
- <string name="dialog_cannot_resume" msgid="8664509751358983543">"Спампоўка перапынена і не можа быць адноўлена."</string>
- <string name="dialog_file_already_exists" msgid="8308563940663449590">"Немагчыма спампаваць. Мэтавы файл ужо існуе."</string>
- <string name="dialog_media_not_found" msgid="4468088418758018765">"Немагчыма спампаваць. Не падключаны знешнi назапашвальнiк."</string>
- <string name="download_no_application_title" msgid="7024782176657362251">"Немагчыма адкрыць файл"</string>
- <string name="remove_download" msgid="6372920256257247857">"Выдаліць"</string>
- <string name="delete_download" msgid="76629022653866471">"Выдаліць"</string>
- <string name="keep_queued_download" msgid="5144882786014818569">"Пакінуць"</string>
- <string name="cancel_running_download" msgid="5232704030969221112">"Адмена"</string>
- <string name="retry_download" msgid="7617100787922717912">"Паўтарыць"</string>
- <string name="deselect_all" msgid="6348198946254776764">"Адмяніць выбар усяго"</string>
- <string name="select_all" msgid="634074918366265804">"Выбраць усё"</string>
- <string name="selected_count" msgid="2101564570019753277">"Выбрана <xliff:g id="NUMBER">%1$d</xliff:g> з <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
- <string name="download_share_dialog" msgid="3355867339806448955">"Апублікаваць у"</string>
-</resources>
diff --git a/ui/res/values-bn-rBD/strings.xml b/ui/res/values-bn-rBD/strings.xml
new file mode 100644
index 00000000..5aca3712
--- /dev/null
+++ b/ui/res/values-bn-rBD/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"ডাউনলোডগুলি"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"ডাউনলোডগুলি - তারিখ অনুসারে সাজানো"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"ডাউনলোডগুলি - আকার অনুসারে সাজানো"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"কোনো ডাউনলোড নেই।"</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;অজানা&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"আকার অনুসারে সাজান"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"তারিখ অনুসারে বাছাই করুন"</string>
+ <string name="download_queued" msgid="104973307780629904">"সারিবদ্ধ"</string>
+ <string name="download_running" msgid="4656462962155580641">"প্রগতিতে রয়েছে"</string>
+ <string name="download_success" msgid="7006048006543495236">"সম্পূর্ণ"</string>
+ <string name="download_error" msgid="8081329546008568251">"অসফল"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"ডাউনলোড করা যায়নি"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"আপনি পরে ফাইলটি ডাউনলোড করতে পুনরায় চেষ্টা করবেন অথবা সারি থেকে এটি মুছে ফেলতে চান?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"ফাইল সারিতে রয়েছে"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"এই ফাইলটি ভবিষ্যতের ডাউনলোডের জন্য সারিবদ্ধ করা আছে তাই এখনো উপলব্ধ নয়।"</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"ডাউনলোড করা ফাইল খুঁজে পাওয়া যাবে না।"</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"ডাউনলোড শেষ করা যাবে না। বহিরাগত সঞ্চয়স্থানে পর্যাপ্ত জায়গা নেই।"</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"ডাউনলোড শেষ করা যাবে না। অভ্যন্তরীণ ডাউনলোড সঞ্চয়স্থানে পর্যাপ্ত জায়গা নেই।"</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"ডাউনলোড বাধাপ্রাপ্ত হয়েছে এবং পুনঃসূচনা করা যাবে না।"</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"ডাউনলোড করতে পারবেন না। গন্তব্য ফাইলটি ইতিমধ্যেই বিদ্যমান।"</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"ডাউনলোড করতে পারবেন না। বহিরাগত মিডিয়া উপলব্ধ নয়।"</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"ফাইল খোলা যাবে না"</string>
+ <string name="remove_download" msgid="6372920256257247857">"সরান"</string>
+ <string name="delete_download" msgid="76629022653866471">"মুছুন"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"রাখুন"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"বাতিল করুন"</string>
+ <string name="retry_download" msgid="7617100787922717912">"পুনরায় চেষ্টা করুন"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"সবগুলিকে নির্বাচনমুক্ত করুন"</string>
+ <string name="select_all" msgid="634074918366265804">"সবগুলি নির্বাচন করুন"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="TOTAL">%2$d</xliff:g>টির মধ্যে <xliff:g id="NUMBER">%1$d</xliff:g>টি নির্বাচিত"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"এর মাধ্যমে ভাগ করুন"</string>
+</resources>
diff --git a/ui/res/values-et/strings.xml b/ui/res/values-eu-rES/strings.xml
index e2602e5d..b852bb0c 100644
--- a/ui/res/values-et/strings.xml
+++ b/ui/res/values-eu-rES/strings.xml
@@ -16,35 +16,35 @@
<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="3070921713463294774">"Allalaadimised"</string>
- <string name="download_title_sorted_by_date" msgid="5898014492155434221">"Allalaadimised - sorditud kuupäeva järgi"</string>
- <string name="download_title_sorted_by_size" msgid="1417193166677094813">"Allalaadimised - sorditud suuruse järgi"</string>
- <string name="no_downloads" msgid="1029667411186146836">"Allalaadimisi pole."</string>
- <string name="missing_title" msgid="830115697868833773">"&lt;Tundmatu&gt;"</string>
- <string name="button_sort_by_size" msgid="7331549713691146251">"Sordi suuruse järgi"</string>
- <string name="button_sort_by_date" msgid="8800842892684101528">"Sordi kuupäeva järgi"</string>
- <string name="download_queued" msgid="104973307780629904">"Järjekorras"</string>
- <string name="download_running" msgid="4656462962155580641">"Edenemine"</string>
- <string name="download_success" msgid="7006048006543495236">"Lõpetatud"</string>
- <string name="download_error" msgid="8081329546008568251">"Ebaõnnestus"</string>
- <string name="dialog_title_not_available" msgid="5746317632356158515">"Ei saanud alla laadida."</string>
- <string name="dialog_failed_body" msgid="587545111677064427">"Kas soovite proovida faili hiljem uuesti alla laadida või kustutada selle järjekorrast?"</string>
- <string name="dialog_title_queued_body" msgid="6760681913815015219">"Järjekorras olev fail"</string>
- <string name="dialog_queued_body" msgid="708552801635572720">"Fail on allalaadimise järjekorras ega ole seetõttu veel saadaval."</string>
- <string name="dialog_file_missing_body" msgid="3223012612774276284">"Ei leia allalaaditud faili."</string>
- <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"Allalaadimist ei saa lõpetada. Välismäluseadmes ei ole piisavalt ruumi."</string>
- <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"Allalaadimist ei saa lõpule viia. Sisest allalaadimisruumi ei ole piisavalt."</string>
- <string name="dialog_cannot_resume" msgid="8664509751358983543">"Allalaadimine katkes ja seda ei saa jätkata."</string>
- <string name="dialog_file_already_exists" msgid="8308563940663449590">"Ei saa alla laadida. Sihtfail on juba olemas."</string>
- <string name="dialog_media_not_found" msgid="4468088418758018765">"Ei saa alla laadida. Väline andmekandja ei ole saadaval."</string>
- <string name="download_no_application_title" msgid="7024782176657362251">"Faili ei saa avada"</string>
- <string name="remove_download" msgid="6372920256257247857">"Eemalda"</string>
- <string name="delete_download" msgid="76629022653866471">"Kustuta"</string>
- <string name="keep_queued_download" msgid="5144882786014818569">"Jäta alles"</string>
- <string name="cancel_running_download" msgid="5232704030969221112">"Tühista"</string>
- <string name="retry_download" msgid="7617100787922717912">"Proovi uuesti"</string>
- <string name="deselect_all" msgid="6348198946254776764">"Tühista kõik valikud"</string>
- <string name="select_all" msgid="634074918366265804">"Vali kõik"</string>
- <string name="selected_count" msgid="2101564570019753277">"Valitud <xliff:g id="NUMBER">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
- <string name="download_share_dialog" msgid="3355867339806448955">"Jaga rakendusest"</string>
+ <string name="app_label" msgid="3070921713463294774">"Deskargak"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"Deskargak, dataren arabera ordenatuta"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"Deskargak, tamainaren arabera ordenatuta"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"Ez dago deskargarik."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;Ezezaguna&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"Ordenatu tamainaren arabera"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"Ordenatu dataren arabera"</string>
+ <string name="download_queued" msgid="104973307780629904">"Ilaran ezarri da"</string>
+ <string name="download_running" msgid="4656462962155580641">"Abian"</string>
+ <string name="download_success" msgid="7006048006543495236">"Osatuta"</string>
+ <string name="download_error" msgid="8081329546008568251">"Ezin izan da deskargatu"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"Ezin izan da deskargatu"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"Fitxategia geroago deskargatzen saiatu nahi duzu edo ilaratik ezabatu nahi duzu?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"Fitxategia ilaran dago"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"Fitxategia ilaran ezarri da geroago deskargatzeko eta, beraz, ez dago oraindik erabilgarri."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"Ezin da deskargatutako fitxategia aurkitu."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"Ezin da deskarga amaitu. Ez dago deskargetarako behar adina kanpoko memoria."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"Ezin da deskarga amaitu. Ez dago deskargetarako behar adina barneko memoria."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"Deskarga eten egin da eta ezin zaio berrekin."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"Ezin da deskargatu. Helburuko fitxategia bazegoen lehendik ere."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"Ezin da deskargatu. Kanpoko multimedia-elementua ez dago erabilgarri."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"Ezin da fitxategia ireki"</string>
+ <string name="remove_download" msgid="6372920256257247857">"Kendu"</string>
+ <string name="delete_download" msgid="76629022653866471">"Ezabatu"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"Utzi bere horretan"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"Utzi"</string>
+ <string name="retry_download" msgid="7617100787922717912">"Saiatu berriro"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"Desautatu guztiak"</string>
+ <string name="select_all" msgid="634074918366265804">"Hautatu guztiak"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="NUMBER">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g> hautatuta"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"Partekatu honekin:"</string>
</resources>
diff --git a/ui/res/values-gl-rES/strings.xml b/ui/res/values-gl-rES/strings.xml
new file mode 100644
index 00000000..c3d6c800
--- /dev/null
+++ b/ui/res/values-gl-rES/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"Descargas"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"Descargas: ordenadas por data"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"Descargas: ordenadas por tamaño"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"Non hai descargas."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;Descoñecido&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"Ordenar por tamaño"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"Ordenar por data"</string>
+ <string name="download_queued" msgid="104973307780629904">"Na cola"</string>
+ <string name="download_running" msgid="4656462962155580641">"En curso"</string>
+ <string name="download_success" msgid="7006048006543495236">"Completada"</string>
+ <string name="download_error" msgid="8081329546008568251">"Incorrecta"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"Non se puido descargar"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"Queres tentar descargar o ficheiro máis tarde ou queres eliminalo da cola?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"Ficheiro en cola"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"Este ficheiro está na cola para descargar máis adiante, polo que aínda non está dispoñible."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"Non se puido atopar o ficheiro descargado."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"Non se pode rematar a descarga. Non hai espazo suficiente no almacenamento externo."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"Non se pode rematar a descarga. Non hai espazo suficiente no almacenamento de descargas interno."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"Interrompeuse a descarga e non se pode retomar."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"Non se pode descargar. O ficheiro de destino xa existe."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"Non se pode realizar a descarga. O soporte externo non está dispoñible."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"Non se pode abrir o ficheiro"</string>
+ <string name="remove_download" msgid="6372920256257247857">"Eliminar"</string>
+ <string name="delete_download" msgid="76629022653866471">"Eliminar"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"Manter"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"Cancelar"</string>
+ <string name="retry_download" msgid="7617100787922717912">"Tentar de novo"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"Desmarcar todo"</string>
+ <string name="select_all" msgid="634074918366265804">"Seleccionar todas"</string>
+ <string name="selected_count" msgid="2101564570019753277">"Seleccionáronse <xliff:g id="NUMBER">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"Compartir a través de"</string>
+</resources>
diff --git a/ui/res/values-hi/strings.xml b/ui/res/values-hi/strings.xml
index 4761bd34..d33f40c4 100644
--- a/ui/res/values-hi/strings.xml
+++ b/ui/res/values-hi/strings.xml
@@ -28,12 +28,12 @@
<string name="download_success" msgid="7006048006543495236">"पूर्ण"</string>
<string name="download_error" msgid="8081329546008568251">"विफल"</string>
<string name="dialog_title_not_available" msgid="5746317632356158515">"डाउनलोड नहीं किया जा सका"</string>
- <string name="dialog_failed_body" msgid="587545111677064427">"क्‍या आप बाद में फ़ाइल डाउनलोड करने का पुनः प्रयास करना चाहते हैं या उसे कतार से हटाना चाहते हैं?"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"क्‍या आप बाद में फ़ाइल डाउनलोड करने का फिर से प्रयास करना चाहते हैं या उसे कतार से हटाना चाहते हैं?"</string>
<string name="dialog_title_queued_body" msgid="6760681913815015219">"फ़ाइल कतार में"</string>
<string name="dialog_queued_body" msgid="708552801635572720">"यह फ़ाइल भविष्य के डाउनलोड के लिए कतारबद्ध है इसलिए अभी उपलब्ध नहीं है."</string>
<string name="dialog_file_missing_body" msgid="3223012612774276284">"डाउनलोड की गई फ़ाइल नहीं मिल रही."</string>
- <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"डाउनलोड पूर्ण नहीं हो सकता. बाह्य संग्रहण पर पर्याप्‍त स्थान नहीं है."</string>
- <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"डाउनलोड पूर्ण नहीं हो सकता. आंतरिक डाउनलोड संग्रहण में पर्याप्‍त स्थान नहीं है."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"डाउनलोड पूर्ण नहीं हो सकता. बाह्य मेमोरी पर पर्याप्‍त स्थान नहीं है."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"डाउनलोड पूर्ण नहीं हो सकता. आंतरिक डाउनलोड मेमोरी में पर्याप्‍त स्थान नहीं है."</string>
<string name="dialog_cannot_resume" msgid="8664509751358983543">"डाउनलोड बाधित हो गया था और इसे फिर से शुरू नहीं किया जा सकता."</string>
<string name="dialog_file_already_exists" msgid="8308563940663449590">"डाउनलोड नहीं कर सकता. गंतव्‍य फ़ाइल पहले से मौजूद है."</string>
<string name="dialog_media_not_found" msgid="4468088418758018765">"डाउनलोड नहीं किया जा सकता. बाह्य मीडिया उपलब्‍ध नहीं है."</string>
@@ -41,9 +41,9 @@
<string name="remove_download" msgid="6372920256257247857">"निकालें"</string>
<string name="delete_download" msgid="76629022653866471">"हटाएं"</string>
<string name="keep_queued_download" msgid="5144882786014818569">"रखें"</string>
- <string name="cancel_running_download" msgid="5232704030969221112">"रद्द करें"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"रहने दें"</string>
<string name="retry_download" msgid="7617100787922717912">"पुन: प्रयास करें"</string>
- <string name="deselect_all" msgid="6348198946254776764">"सभी का चयन रद्द करें"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"कुछ भी ना चुनें"</string>
<string name="select_all" msgid="634074918366265804">"सभी चुनें"</string>
<string name="selected_count" msgid="2101564570019753277">"<xliff:g id="TOTAL">%2$d</xliff:g> में से <xliff:g id="NUMBER">%1$d</xliff:g> चयनित"</string>
<string name="download_share_dialog" msgid="3355867339806448955">"इसके द्वारा साझा करें"</string>
diff --git a/ui/res/values-is-rIS/strings.xml b/ui/res/values-is-rIS/strings.xml
new file mode 100644
index 00000000..2db65251
--- /dev/null
+++ b/ui/res/values-is-rIS/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"Niðurhal"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"Niðurhal – Raðað eftir dagsetningu"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"Niðurhal – Raðað eftir stærð"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"Ekkert niðurhal."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;Óþekkt&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"Raða eftir stærð"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"Raða eftir dagsetningu"</string>
+ <string name="download_queued" msgid="104973307780629904">"Í biðröð"</string>
+ <string name="download_running" msgid="4656462962155580641">"Í gangi"</string>
+ <string name="download_success" msgid="7006048006543495236">"Lokið"</string>
+ <string name="download_error" msgid="8081329546008568251">"Mistókst"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"Ekki var hægt að sækja"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"Hvort viltu reyna að sækja skrána aftur síðar eða eyða henni úr biðröðinni?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"Skrá í biðröð"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"Þessi skrá er í biðröð til niðurhals síðar og er því ekki tiltæk enn."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"Ekki er hægt að sækja skrána."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"Ekki er hægt að ljúka niðurhalinu. Ekki er nægt pláss í ytri geymslu."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"Ekki er hægt að ljúka niðurhalinu. Ekki er nægt pláss í innbyggðu niðurhalsgeymslunni."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"Niðurhalið var truflað og ekki er hægt að hefja það að nýju."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"Ekki er hægt að sækja. Viðtökuskráin er þegar til staðar."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"Ekki er hægt að sækja. Ytri geymslumiðill er ekki tilbúinn."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"Ekki er hægt að opna skrána"</string>
+ <string name="remove_download" msgid="6372920256257247857">"Fjarlægja"</string>
+ <string name="delete_download" msgid="76629022653866471">"Eyða"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"Halda"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"Hætta við"</string>
+ <string name="retry_download" msgid="7617100787922717912">"Reyna aftur"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"Velja ekkert"</string>
+ <string name="select_all" msgid="634074918366265804">"Velja allt"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="NUMBER">%1$d</xliff:g> skrár valdar af <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"Deila í gegnum"</string>
+</resources>
diff --git a/ui/res/values-kk-rKZ/strings.xml b/ui/res/values-kk-rKZ/strings.xml
new file mode 100644
index 00000000..5987713f
--- /dev/null
+++ b/ui/res/values-kk-rKZ/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"Жүктеулер"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"Жүктеулер - Мерзім бойынша сұрыпталған"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"Жүктеулер - Өлшем бойынша сұрыпталған"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"Жүктеулер жоқ."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;Белгісіз&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"Өлшемі бойынша сұрыптау"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"Мерзімі бойынша сұрыптау"</string>
+ <string name="download_queued" msgid="104973307780629904">"Кезекте"</string>
+ <string name="download_running" msgid="4656462962155580641">"Жүктеуде"</string>
+ <string name="download_success" msgid="7006048006543495236">"Аяқталды"</string>
+ <string name="download_error" msgid="8081329546008568251">"Сәтсіз"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"Жүктеу мүмкін болмады."</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"Бұл файлды кейінірек қайта жүктеп көруді қалайсыз ба әлде кезектен жойылсын ба?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"Файл кезекте."</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"Бұл файл келесі жолы жүктеу үшін кезекке қойылған, сондықтан қазір қол жетімсіз."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"Жүктелген файлдарды таба алмады."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"Жүктеуді аяқтау мүмкін емес. Сыртқы жүктеу жадында жеткілікті орын жоқ."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"Жүктеуді аяқтау мүмкін емес. Ішкі жүктеу жадында жеткілікті орын жоқ."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"Жүктеу тоқтатылды және оны жалғастыру мүмкін емес."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"Жүктеу мүмкін емес. Мақсатты файл бұрыннан бар."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"Жүктеу мүмкін емес. Сыртқы медиа қол жетімсіз."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"Файлды аша алмады"</string>
+ <string name="remove_download" msgid="6372920256257247857">"Алып тастау"</string>
+ <string name="delete_download" msgid="76629022653866471">"Жою"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"Қалсын"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"Өшіру"</string>
+ <string name="retry_download" msgid="7617100787922717912">"Қайта әрекеттену"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"Барлығының таңдауын алыңыз"</string>
+ <string name="select_all" msgid="634074918366265804">"Барлығын таңдау"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="NUMBER">%1$d</xliff:g> таңдалды, барлығы <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"Бөлісу қолданбасы"</string>
+</resources>
diff --git a/ui/res/values-km-rKH/strings.xml b/ui/res/values-km-rKH/strings.xml
index 5bcc6851..cc5f49b6 100644
--- a/ui/res/values-km-rKH/strings.xml
+++ b/ui/res/values-km-rKH/strings.xml
@@ -41,7 +41,7 @@
<string name="remove_download" msgid="6372920256257247857">"លុប​ចេញ"</string>
<string name="delete_download" msgid="76629022653866471">"លុប"</string>
<string name="keep_queued_download" msgid="5144882786014818569">"បន្ត"</string>
- <string name="cancel_running_download" msgid="5232704030969221112">"បោះ​បង់"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"បោះ​បង់​"</string>
<string name="retry_download" msgid="7617100787922717912">"សាកល្បង​ម្ដងទៀត"</string>
<string name="deselect_all" msgid="6348198946254776764">"មិន​ជ្រើស​ទាំងអស់"</string>
<string name="select_all" msgid="634074918366265804">"ជ្រើស​ទាំងអស់"</string>
diff --git a/ui/res/values-kn-rIN/strings.xml b/ui/res/values-kn-rIN/strings.xml
new file mode 100644
index 00000000..62fa8a66
--- /dev/null
+++ b/ui/res/values-kn-rIN/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"ಡೌನ್‌ಲೋಡ್‌ಗಳು"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"ಡೌನ್‌ಲೋಡ್‌ಗಳು - ದಿನಾಂಕದ ಪ್ರಕಾರ ವಿಂಗಡಿಸಲಾಗಿದೆ"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"ಡೌನ್‌ಲೊಡ್‌ಗಳು - ಗಾತ್ರದ ಪ್ರಕಾರ ವಿಂಗಡಿಸಲಾಗಿದೆ"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"ಯಾವುದೇ ಡೌನ್‌ಲೋಡ್‌ಗಳಿಲ್ಲ."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;ಅಜ್ಞಾತ&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"ಗಾತ್ರದಂತೆ ವಿಂಗಡಿಸಿ"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"ದಿನಾಂಕದ ಪ್ರಕಾರವಾಗಿ ವಿಂಗಡಿಸಿ"</string>
+ <string name="download_queued" msgid="104973307780629904">"ಸರದಿಯಲ್ಲಿರಿಸಲಾಗಿದೆ"</string>
+ <string name="download_running" msgid="4656462962155580641">"ಪ್ರಗತಿಯಲ್ಲಿದೆ"</string>
+ <string name="download_success" msgid="7006048006543495236">"ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
+ <string name="download_error" msgid="8081329546008568251">"ವಿಫಲಗೊಂಡಿದೆ"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"ಡೌನ್‌ಲೋಡ್‌ ಮಾಡಲು ಸಾಧ್ಯವಾಗಿಲ್ಲ"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"ನೀವು ನಂತರದಲ್ಲಿ ಫೈಲ್‌ಗಳನ್ನು ಡೌನ್‌ಲೋಡ್ ಮಾಡಲು ಮರುಪ್ರಯತ್ನಿಸಲು ಬಯಸುವಿರಾ ಅಥವಾ ಅದನ್ನು ಸರದಿಯಿಂದ ಅಳಿಸಲು ಬಯಸುವಿರಾ?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"ಫೈಲ್‌ ಸರದಿಯಲ್ಲಿದೆ"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"ಭವಿಷ್ಯದ ಡೌನ್‌ಲೋಡ್‌ಗಾಗಿ ಈ ಫೈಲ್‌‌ ಅನ್ನು ಸರದಿಯಲ್ಲಿರಿಸಲಾಗಿದೆ ಹಾಗಾಗಿ ಇನ್ನೂ ಲಭ್ಯವಿಲ್ಲ."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"ಡೌನ್‌ಲೋಡ್‌ ಮಾಡಿದ ಫೈಲ್‌‌ ಹುಡುಕಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"ಡೌನ್‌ಲೋಡ್‌ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಲಾಗಲಿಲ್ಲ. ಬಾಹ್ಯ ಡೌನ್‌ಲೋಡ್‌ ಸಂಗ್ರಹಣೆಯಲ್ಲಿ ಸಾಕಷ್ಟು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"ಡೌನ್‌ಲೋಡ್‌ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಲಾಗಲಿಲ್ಲ. ಆಂತರಿಕ ಡೌನ್‌ಲೋಡ್‌ ಸಂಗ್ರಹಣೆಯಲ್ಲಿ ಸಾಕಷ್ಟು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"ಡೌನ್‌ಲೋಡ್‌ ಅಡಚಣೆಗೊಳಗಾಗಿದೆ ಮತ್ತು ಪುನರಾರಂಭಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"ಡೌನ್‌ಲೋಡ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಉದ್ದೇಶಿತ ಫೈಲ್‌ ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"ಡೌನ್‌ಲೋಡ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಬಾಹ್ಯ ಮಾಧ್ಯಮವು ಲಭ್ಯವಿಲ್ಲ."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"ಫೈಲ್ ತೆರೆಯಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
+ <string name="remove_download" msgid="6372920256257247857">"ತೆಗೆದುಹಾಕಿ"</string>
+ <string name="delete_download" msgid="76629022653866471">"ಅಳಿಸು"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"ಇರಿಸಿ"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"ರದ್ದುಮಾಡು"</string>
+ <string name="retry_download" msgid="7617100787922717912">"ಮರುಪ್ರಯತ್ನಿಸಿ"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"ಎಲ್ಲಾ ಆಯ್ಕೆಯನ್ನು ರದ್ದುಮಾಡಿ"</string>
+ <string name="select_all" msgid="634074918366265804">"ಎಲ್ಲವನ್ನೂ ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="TOTAL">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="NUMBER">%1$d</xliff:g> ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"ಈ ಮೂಲಕ ಹಂಚಿಕೊಳ್ಳಿ"</string>
+</resources>
diff --git a/ui/res/values-ky-rKG/strings.xml b/ui/res/values-ky-rKG/strings.xml
new file mode 100644
index 00000000..ccfdf0ca
--- /dev/null
+++ b/ui/res/values-ky-rKG/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"Жүктөөлөр"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"Жүктөөлөр - датасы боюнча ылганган"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"Жүктөөлөр - өлчөмү боюнча ылганган"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"Жүктөөлөр жок."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;Белгисиз&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"Өлчөмү боюнча ылгоо"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"Датасы боюнча ылгоо"</string>
+ <string name="download_queued" msgid="104973307780629904">"Кезекте"</string>
+ <string name="download_running" msgid="4656462962155580641">"Жүктөлүүдө"</string>
+ <string name="download_success" msgid="7006048006543495236">"Жүктөө аяктады"</string>
+ <string name="download_error" msgid="8081329546008568251">"Ийгиликсиз"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"Жүктөө мүмкүн болбоду"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"Сиз файлды кийинчерээк жүктөп көрөсүзбү же аны кезектен чыгарып саласызбы?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"Файл кезекте"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"Бул файл кийин жүктөлсүн деп кезекке тургузулган, азырынча ал жеткиликтүү эмес."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"Жүктөлгөн файл табылбай жатат."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"Жүктөөнү аягына чыгаруу мүмкүн эмес. Тышкы сактагычта орун жетишсиз."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"Жүктөөнү аягына чыгаруу мүмкүн эмес. Ички сактагычта орун жетишсиз."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"Жүктөө үзгүлтүккө учурады жана аягына чыгарылбайт."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"Жүктөө мүмкүн эмес. Мындай файл мурунтан бар."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"Жүктөөнү аягына чыгаруу мүмкүн эмес. Тышкы медиа жеткиликтүү эмес."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"Файл ачылбады"</string>
+ <string name="remove_download" msgid="6372920256257247857">"Алып салуу"</string>
+ <string name="delete_download" msgid="76629022653866471">"Жок кылуу"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"Калтыруу"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"Айнуу"</string>
+ <string name="retry_download" msgid="7617100787922717912">"Кайра аракеттенүү"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"Баарын бошотуу"</string>
+ <string name="select_all" msgid="634074918366265804">"Бардыгын тандоо"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="TOTAL">%2$d</xliff:g> ичинен <xliff:g id="NUMBER">%1$d</xliff:g> тандалды"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"Бул аркылуу бөлүшүү:"</string>
+</resources>
diff --git a/ui/res/values-mk-rMK/strings.xml b/ui/res/values-mk-rMK/strings.xml
new file mode 100644
index 00000000..15951642
--- /dev/null
+++ b/ui/res/values-mk-rMK/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"Преземања"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"Преземања - Подредени по датум"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"Преземања - Подредени по големина"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"Нема преземања."</string>
+ <string name="missing_title" msgid="830115697868833773">"Непознато"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"Подреди по големина"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"Подреди по датум"</string>
+ <string name="download_queued" msgid="104973307780629904">"Чека на ред"</string>
+ <string name="download_running" msgid="4656462962155580641">"Во тек е"</string>
+ <string name="download_success" msgid="7006048006543495236">"Целосно"</string>
+ <string name="download_error" msgid="8081329546008568251">"Неуспешно"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"Не можеше да се преземе"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"Сакате повторно да се обиде со преземање на датотеката подоцна или да се избрише од редот?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"Датотеката е во ред на чекање"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"Оваа датотека е ставена во ред начекање да се преземе во иднина и сè уште не е достапна."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"Не може да се пронајде преземената датотека."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"Преземањето не може да се заврши. Нема доволно простор на надворешната меморија."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"Преземањето не може да се заврши. Нема доволно простор на внатрешна меморија за преземање."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"Преземањето се прекина и не може да продолжи."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"Не може да се преземе. Одредишната датотека веќе постои."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"Не може да се преземе. Надворешниот медиум не е достапен."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"Датотеката не се отвора"</string>
+ <string name="remove_download" msgid="6372920256257247857">"Отстрани"</string>
+ <string name="delete_download" msgid="76629022653866471">"Избриши"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"Задржи"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"Откажи"</string>
+ <string name="retry_download" msgid="7617100787922717912">"Обиди се повторно"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"Отштиклирај ги сите"</string>
+ <string name="select_all" msgid="634074918366265804">"Избери ги сите"</string>
+ <string name="selected_count" msgid="2101564570019753277">"Избрани <xliff:g id="NUMBER">%1$d</xliff:g> од <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"Сподели преку"</string>
+</resources>
diff --git a/ui/res/values-ml-rIN/strings.xml b/ui/res/values-ml-rIN/strings.xml
new file mode 100644
index 00000000..29f9a70e
--- /dev/null
+++ b/ui/res/values-ml-rIN/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"ഡൗൺലോഡുകൾ"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"ഡൗൺലോഡുകൾ - തീയതി പ്രകാരം അടുക്കുക"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"ഡൗൺലോഡുകൾ - വലുപ്പം പ്രകാരം അടുക്കുക"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"ഡൗൺലോഡുകളൊന്നുമില്ല."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;അജ്ഞാതം&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"വലുപ്പമനുസരിച്ച് അടുക്കുക"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"തീയതി അനുസരിച്ച് അടുക്കുക"</string>
+ <string name="download_queued" msgid="104973307780629904">"ക്യൂവിലാണ്"</string>
+ <string name="download_running" msgid="4656462962155580641">"പുരോഗമിക്കുന്നു"</string>
+ <string name="download_success" msgid="7006048006543495236">"പൂർത്തിയായി"</string>
+ <string name="download_error" msgid="8081329546008568251">"പരാജയപ്പെട്ടു"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"ഡൗൺലോഡുചെയ്യാനായില്ല"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"ഫയൽ ഡൗൺലോഡുചെയ്യാൻ വീണ്ടും ശ്രമിക്കുകയോ ക്യൂവിൽ നിന്നും അത് ഇല്ലാതാക്കുകയോ ചെയ്യണോ?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"ഫയൽ ക്യൂവിലാണ്"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"ഭാവിയിൽ ഡൗൺലോഡുചെയ്യാനായി ഫയൽ ക്യൂവിലായതിനാൽ ഇതുവരെയും ലഭ്യമല്ല."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"ഡൗൺലോഡുചെയ്‌ത ഫയൽ കണ്ടെത്താനായില്ല."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"ഡൗൺലോഡ് പൂർത്തിയാക്കാനാകില്ല. ബാഹ്യസംഭരണത്തിൽ ആവശ്യമായ ഇടമില്ല."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"ഡൗൺലോഡ് പൂർത്തിയാക്കാനായില്ല. ആന്തരിക ഡൗൺലോഡ് സംഭരണത്തിൽ ആവശ്യമായ ഇടമില്ല."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"ഡൗൺലോഡ് തടസ്സപ്പെട്ടതിനാൽ പുനരാരംഭിക്കാനാകില്ല."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"ഡൗൺലോഡുചെയ്യാനാകില്ല. ലക്ഷ്യസ്ഥാന ഫയൽ ഇതിനകം നിലവിലുണ്ട്."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"ഡൗൺലോഡുചെയ്യാനാകില്ല. ബാഹ്യ മീഡിയ ലഭ്യമല്ല."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"ഫയൽ തുറക്കാനായില്ല"</string>
+ <string name="remove_download" msgid="6372920256257247857">"നീക്കംചെയ്യുക"</string>
+ <string name="delete_download" msgid="76629022653866471">"ഇല്ലാതാക്കുക"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"സൂക്ഷിക്കുക"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"റദ്ദാക്കുക"</string>
+ <string name="retry_download" msgid="7617100787922717912">"വീണ്ടും ശ്രമിക്കുക"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"തിരഞ്ഞെടുത്തത് എല്ലാം മാറ്റുക"</string>
+ <string name="select_all" msgid="634074918366265804">"എല്ലാം തിരഞ്ഞെടുക്കുക"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="NUMBER">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g> എണ്ണം തിരഞ്ഞെടുത്തു"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"ഇതുവഴി പങ്കിടുക"</string>
+</resources>
diff --git a/ui/res/values-mr-rIN/strings.xml b/ui/res/values-mr-rIN/strings.xml
new file mode 100644
index 00000000..4340c570
--- /dev/null
+++ b/ui/res/values-mr-rIN/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"डाउनलोड"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"डाउनलोड - तारखेनुसार क्रमवारी लावलेले"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"डाउनलोड - आकारानुसार क्रमवारी लावलेले"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"कोणतेही डाउनलोड नाहीत."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;अज्ञात&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"आकारानुसार क्रमवारी लावा"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"तारखेनुसार क्रमवारी लावा"</string>
+ <string name="download_queued" msgid="104973307780629904">"रांगेत लावलेला"</string>
+ <string name="download_running" msgid="4656462962155580641">"प्रगतीपथावर"</string>
+ <string name="download_success" msgid="7006048006543495236">"पूर्ण"</string>
+ <string name="download_error" msgid="8081329546008568251">"अयशस्वी"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"डाउनलोड करू शकलो नाही"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"आपण फाइल डाउनलोड करण्‍याचा नंतर पुन्हा प्रयत्न करू इच्‍छिता कि तिला रांगेमधून हटवू इच्छिता?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"रांगेतील फाइल"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"ही फाइल भविष्‍यात डाउनलोड करण्‍यासाठी रांगेत लावली आहे म्‍हणून ती अद्याप उपलब्‍ध नाही."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"डाउनलोड केलेली फाइल शोधू शकत नाही."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"डाउनलोड समाप्त करू शकत नाही. बाह्य संचयनावर पुरेसे स्‍थान नाही."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"डाउनलोड समाप्त करू शकत नाही. अंतर्गत डाउनलोड संचयनावर पुरेसे स्‍थान नाही."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"डाउनलोडमध्‍ये व्यत्यय आला आणि पुन्हा सुरु केले जाऊ शकत नाही."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"डाउनलोड करू शकत नाही. गंतव्य फाइल आधीपासून अस्तित्वात आहे."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"डाउनलोड करू शकत नाही. बाह्य मीडिया उपलब्ध नाही."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"फाइल उघडू शकत नाही"</string>
+ <string name="remove_download" msgid="6372920256257247857">"काढा"</string>
+ <string name="delete_download" msgid="76629022653866471">"हटवा"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"ठेवा"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"रद्द करा"</string>
+ <string name="retry_download" msgid="7617100787922717912">"पुन्हा प्रयत्न करा"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"सर्व निवड रद्द करा"</string>
+ <string name="select_all" msgid="634074918366265804">"सर्व निवडा"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="TOTAL">%2$d</xliff:g> पैकी <xliff:g id="NUMBER">%1$d</xliff:g> निवडले"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"द्वारे सामायिक करा"</string>
+</resources>
diff --git a/ui/res/values-my-rMM/strings.xml b/ui/res/values-my-rMM/strings.xml
new file mode 100644
index 00000000..f2483e8e
--- /dev/null
+++ b/ui/res/values-my-rMM/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"ဒေါင်းလုပ်များ"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"ဒေါင်းလုပ်များ -နေ့စွဲအလိုက် စီထားသည်"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"ဒေါင်းလုပ်များ -အရွယ်အစားအလိုက် စီထားသည်"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"ဒေါင်းလုပ်မရှိပါ"</string>
+ <string name="missing_title" msgid="830115697868833773">"အကြောင်းအရာ မသိရှိ"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"အရွယ်အစားအလိုက် စီရန်"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"နေ့စွဲအလိုက် စီရန်"</string>
+ <string name="download_queued" msgid="104973307780629904">"တန်းစီထားပြီး"</string>
+ <string name="download_running" msgid="4656462962155580641">"ပြုလုပ်နေဆဲ"</string>
+ <string name="download_success" msgid="7006048006543495236">"ပြီးဆုံးပါပြီ"</string>
+ <string name="download_error" msgid="8081329546008568251">"မအောင်မြင်ပါ"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"ဒေါင်းလုပ်ပြုလုပ်မရပါ"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"ခဏကြာလျှင် ဒေါင်းလုပ်ပြန်ကြိုးစားမည်လား သို့မဟုတ် တန်းစီးထားခြင်းမှ ဖျက်မည်လား?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"ဖိုင်ကိုတန်းစီထားသည်"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"နောင်တွင် ဒေါင်းလုပ်ပြုလုပ်ရန် ဖိုင်ကိုတန်းစီထားသောကြောင့် မရနိုင်သေးပါ"</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"ဒေါင်းလုပ်ပြုလုပ်ထားသောဖိုင်အား ရှာမရပါ"</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"ဒေါင်းလုပ် မပြီးဆုံးနိုင်ပါ၊ ပြင်ပ သိုလှောင်ရာနေရာတွင် လုံလောက်သော နေရာလွတ် မရှိပါ။"</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"ဒေါင်းလုပ် မပြီးဆုံးနိုင်ပါ၊ စက်တွင်းဒေါင်းလုပ်သိုလှောင်မှုတွင် လုံလောက်သောနေရာလပ်မရှိပါ"</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"ဒေါင်းလုပ်မှာ နှောက်ယှက်ခံရသောကြောင့် ​ပြန်မစနိုင်ပါ"</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"ဒေါင်းလုပ်ပြုလုပ်မရပါ၊ ဦးတည်ရာဖိုင် ရှိနှင့်ပြီးဖြစ်သည်။"</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"ဒေါင်းလုပ် မပြုလုပ်နိုင်ပါ၊ ပြင်ပ မီဒီယာ မရှိပါ။"</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"ဖိုင်အား ဖွင့်မရပါ"</string>
+ <string name="remove_download" msgid="6372920256257247857">"ဖယ်ရှားရန်"</string>
+ <string name="delete_download" msgid="76629022653866471">"ဖျက်ပစ်ရန်"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"သိမ်းထားပါ"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"ထားတော့"</string>
+ <string name="retry_download" msgid="7617100787922717912">"ပြန်ကြိုးစားပါ"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"ဘာကိုမှ မရွေးပါ"</string>
+ <string name="select_all" msgid="634074918366265804">"အားလုံးရွေးချယ်ရန်"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="NUMBER">%1$d</xliff:g> ထဲမှ <xliff:g id="TOTAL">%2$d</xliff:g> ရွေးချယ်ပြီး"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"မှတစ်ဆင့် မျှဝေပါ"</string>
+</resources>
diff --git a/ui/res/values-ne-rNP/strings.xml b/ui/res/values-ne-rNP/strings.xml
new file mode 100644
index 00000000..2a7389b2
--- /dev/null
+++ b/ui/res/values-ne-rNP/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"डाउनलोडहरू"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"डाउनलोडहरू - मिति अनुसार क्रमबद्ध गरिएका"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"डाउनलोडहरू - आकार अनुसार क्रमबद्ध गरिएका"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"कुनै डाउनलोडहरू छैनन्।"</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;अज्ञात&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"आकार अनुसार क्रमबद्ध गर्नुहोस्"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"मिति अनुसार क्रमबद्ध गर्नुहोस्"</string>
+ <string name="download_queued" msgid="104973307780629904">"लाममा राखियो"</string>
+ <string name="download_running" msgid="4656462962155580641">"प्रगतिमा"</string>
+ <string name="download_success" msgid="7006048006543495236">"पुरा गर्नुहोस्"</string>
+ <string name="download_error" msgid="8081329546008568251">"असफल"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"डाउनलोड गर्न सकेन"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"तपाईँ पछि फेरि फाइल डाउनलोड गर्ने प्रयास गर्न चाहनुहुन्छ कि लामबाट हटाउन चाहनुहुन्छ?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"फाइल लाममा छ"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"फाइल भविष्यमा डाउनलोड गर्नका लागि लाममा राखिएको छ, यसैले अझै उपलब्ध छैन।"</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"डाउनलोड गरिएको फाइल फेला पार्न सकेन।"</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"डाउनलोड समाप्त पार्न सकेन। बाह्य भण्डारणमा पर्याप्त ठाउँ छैन।"</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"डाउनलोड समाप्त पार्न सकेन। आन्तरिक डाउनलोड भण्डारणमा पर्याप्त ठाउँ छैन।"</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"डाउनलोड अवरूद्ध भयो र यो पुनः सुरु गर्न सकिन्न।"</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"डाउनलोड गर्न सकेन। लक्षित फाइल पहिले नै छ।"</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"डाउनलोड गर्न सकेन। बाह्य मिडिया उपलब्ध छैन।"</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"फाइल खोल्न सकिँदैन"</string>
+ <string name="remove_download" msgid="6372920256257247857">"हटाउनुहोस्"</string>
+ <string name="delete_download" msgid="76629022653866471">"मेटाउनुहोस्"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"राख्नुहोस्"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"रद्द गर्नुहोस्"</string>
+ <string name="retry_download" msgid="7617100787922717912">"पुनःप्रयास गर्नुहोस्"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"सबै अचयन गर्नुहोस्"</string>
+ <string name="select_all" msgid="634074918366265804">"सबै चयन गर्नुहोस्"</string>
+ <string name="selected_count" msgid="2101564570019753277">"छानिएको <xliff:g id="TOTAL">%2$d</xliff:g> को <xliff:g id="NUMBER">%1$d</xliff:g> बाट"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"द्वारा साझेदारी गर्नुहोस्"</string>
+</resources>
diff --git a/ui/res/values-si-rLK/strings.xml b/ui/res/values-si-rLK/strings.xml
new file mode 100644
index 00000000..11873878
--- /dev/null
+++ b/ui/res/values-si-rLK/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"බාගැනීම්"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"බාගැනීම් - දිනය අනුව පෙළගස්වන ලද"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"බාගැනීම් - ප්‍රමාණය අනුව පෙළගස්වන ලද"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"බාගැනීම් නොමැත."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;නොදනී&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"ප්‍රමාණය අනුව අනුපිළිවෙලට සකසන්න"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"දිනය අනුව අනුපිළිවෙලට සකසන්න"</string>
+ <string name="download_queued" msgid="104973307780629904">"පෙළ ගැස්විණි"</string>
+ <string name="download_running" msgid="4656462962155580641">"ක්‍රියාවේ පවතී"</string>
+ <string name="download_success" msgid="7006048006543495236">"සම්පුර්ණයි"</string>
+ <string name="download_error" msgid="8081329546008568251">"අසාර්ථකයි"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"බාගත නොහැකි විය"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"ඔබට ගොනු පසුව බාගැනීමට උත්සාහ කිරීමට අවශ්‍යද නැතිනම් එය පෝලිමෙන් මැකීමට අවශ්‍යද?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"ගොනුව පේළියෙහි තිබේ"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"අනාගත බාගැනීම් සඳහා මෙම ගොනුව පෙළගස්වා ඇත එබැවින් එය තවම ලබාගත නොහැක."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"බාගත් ගොනුව සොයා ගත නොහැක."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"බාගැනීම අවසන් කළ නොහැක. බාහිර බාගැනීම් ආචයනයේ අවශ්‍ය තරම් ඉඩක් නොමැත."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"බාගැනීම අවසන් කළ නොහැක. අභ්‍යන්තර බාගැනීම් ආචයනයේ අවශ්‍ය තරම් ඉඩක් නොමැත."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"බාගැනීමට බාධා ඇතිවූ අතර එය යළි ආරම්භ කළ නොහැක."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"බාගත නොහැක. ගමනාන්තයේ ගොනුව දැනටමත් ඇත."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"බාගත නොහැක. බාහිර මාධ්‍ය නොමැත."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"ගොනුව විවෘත කළ නොහැකි විය"</string>
+ <string name="remove_download" msgid="6372920256257247857">"ඉවත් කරන්න"</string>
+ <string name="delete_download" msgid="76629022653866471">"මකන්න"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"තබාගැනීම"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"අවලංගු කරන්න"</string>
+ <string name="retry_download" msgid="7617100787922717912">"නැවත උත්සාහ කරන්න"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"සියල්ල තේරීම අත්හරින්න"</string>
+ <string name="select_all" msgid="634074918366265804">"සියල්ල තෝරන්න"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="TOTAL">%2$d</xliff:g> ගෙන් <xliff:g id="NUMBER">%1$d</xliff:g> ක් තෝරා ගන්නා ලදී"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"බෙදාගන්නේ"</string>
+</resources>
diff --git a/ui/res/values-ta-rIN/strings.xml b/ui/res/values-ta-rIN/strings.xml
new file mode 100644
index 00000000..7056356c
--- /dev/null
+++ b/ui/res/values-ta-rIN/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"பதிவிறக்கங்கள்"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"பதிவிறக்கங்கள் - தேதியின்படி வரிசைப்படுத்தப்பட்டது"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"பதிவிறக்கங்கள் - அளவின்படி வரிசைப்படுத்தப்பட்டது"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"பதிவிறக்கங்கள் இல்லை."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;அறியப்படாதது&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"அளவின்படி வரிசைப்படுத்து"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"தேதிப்படி வரிசைப்படுத்து"</string>
+ <string name="download_queued" msgid="104973307780629904">"வரிசைப்படுத்தப்பட்டது"</string>
+ <string name="download_running" msgid="4656462962155580641">"செயலிலுள்ளது"</string>
+ <string name="download_success" msgid="7006048006543495236">"முடிந்தது"</string>
+ <string name="download_error" msgid="8081329546008568251">"தோல்வி"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"பதிவிறக்க முடியவில்லை"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"கோப்பைப் பின்னர் பதிவிறக்க முயற்சிக்கவா அல்லது வரிசையிலிருந்து நீக்க விரும்புகிறீர்களா?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"வரிசையில் உள்ள கோப்பு"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"இந்தக் கோப்பு எதிர்கால பதிவிறக்கத்திற்கு வரிசைப்படுத்தப்பட்டது, அதனால், இதுவரை இது கிடைக்கவில்லை."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"பதிவிறக்கிய கோப்பைக் கண்டறிய முடியவில்லை."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"பதிவிறக்கத்தை முடிக்க முடியவில்லை. வெளிப்புறச் சேமிப்பிடத்தில் போதுமான இடம் இல்லை."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"பதிவிறக்கத்தை முடிக்க முடியவில்லை. அகப் பதிவிறக்க சேமிப்பிடத்தில் போதுமான இடம் இல்லை."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"பதிவிறக்கம் குறுக்கிடப்பட்டது, மேலும் மீண்டும் தொடங்க முடியாது."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"பதிவிறக்க முடியவில்லை. இலக்குக் கோப்பு ஏற்கனவே உள்ளது."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"பதிவிறக்க முடியவில்லை. வெளிப்புற மீடியா கிடைக்கவில்லை."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"கோப்பைத் திறக்க முடியவில்லை"</string>
+ <string name="remove_download" msgid="6372920256257247857">"அகற்று"</string>
+ <string name="delete_download" msgid="76629022653866471">"நீக்கு"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"வைத்திரு"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"ரத்துசெய்"</string>
+ <string name="retry_download" msgid="7617100787922717912">"மீண்டும் முயற்சிசெய்க"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"எல்லாம் தேர்வுநீக்கு"</string>
+ <string name="select_all" msgid="634074918366265804">"எல்லாவற்றையும் தேர்ந்தெடு"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="TOTAL">%2$d</xliff:g> இல் <xliff:g id="NUMBER">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டன"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"இதன் வழியாகப் பகிர்"</string>
+</resources>
diff --git a/ui/res/values-te-rIN/strings.xml b/ui/res/values-te-rIN/strings.xml
new file mode 100644
index 00000000..9099044e
--- /dev/null
+++ b/ui/res/values-te-rIN/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"డౌన్‌లోడ్‌లు"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"డౌన్‌లోడ్‌లు - తేదీ ద్వారా క్రమబద్ధీకరించబడినవి"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"డౌన్‌లోడ్‌లు - పరిమాణం ద్వారా క్రమబద్ధీకరించబడినవి"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"డౌన్‌లోడ్‌లు ఏవీ లేవు."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;తెలియదు&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"పరిమాణం ద్వారా క్రమబద్ధీకరించు"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"తేదీ ద్వారా క్రమబద్ధీకరించు"</string>
+ <string name="download_queued" msgid="104973307780629904">"క్రమవరుసలో ఉంచబడింది"</string>
+ <string name="download_running" msgid="4656462962155580641">"ప్రోగ్రెస్‌లో ఉంది"</string>
+ <string name="download_success" msgid="7006048006543495236">"పూర్తయింది"</string>
+ <string name="download_error" msgid="8081329546008568251">"విఫలమైంది"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"డౌన్‌లోడ్ చేయడం సాధ్యపడలేదు"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"మీరు ఫైల్‌ను తర్వాత డౌన్‌లోడ్ చేయడానికి మళ్లీ ప్రయత్నించాలనుకుంటున్నారా లేదా దీన్ని క్రమవరుస నుండి తొలగించాలనుకుంటున్నారా?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"ఫైల్ క్రమవరుసలో ఉంది"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"ఈ ఫైల్ భవిష్యత్తు డౌన్‌లోడ్ కోసం క్రమవరుసలో ఉంచబడింది అందువలన ఇంకా అందుబాటులో లేదు."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"డౌన్‌లోడ్ చేయబడిన ఫైల్‌ను కనుగొనడం సాధ్యపడదు."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"డౌన్‌లోడ్‌ను పూర్తి చేయడం సాధ్యపడదు. బాహ్య నిల్వలో తగినంత స్థలం లేదు."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"డౌన్‌లోడ్‌ను పూర్తి చేయడం సాధ్యపడదు. అంతర్గత డౌన్‌లోడ్ నిల్వలో తగినంత స్థలం లేదు."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"డౌన్‌లోడ్‌కు అంతరాయం ఏర్పడింది మరియు పునఃప్రారంభించడం సాధ్యపడదు."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"డౌన్‌లోడ్ చేయడం సాధ్యపడదు. గమ్యస్థాన ఫైల్ ఇప్పటికే ఉంది."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"డౌన్‌లోడ్ చేయడం సాధ్యపడదు. బాహ్య మీడియా అందుబాటులో లేదు."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"ఫైల్‌ను తెరవడం సాధ్యపడదు"</string>
+ <string name="remove_download" msgid="6372920256257247857">"తీసివేయి"</string>
+ <string name="delete_download" msgid="76629022653866471">"తొలగించు"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"ఉంచు"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"రద్దు చేయి"</string>
+ <string name="retry_download" msgid="7617100787922717912">"మళ్లీ ప్రయత్నించు"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"అన్నింటి ఎంపికను తీసివేయి"</string>
+ <string name="select_all" msgid="634074918366265804">"అన్నీ ఎంచుకోండి"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="TOTAL">%2$d</xliff:g>లో <xliff:g id="NUMBER">%1$d</xliff:g> ఎంచుకోబడ్డాయి"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"వీటి ద్వారా భాగస్వామ్యం చేయండి"</string>
+</resources>
diff --git a/ui/res/values-ur-rPK/strings.xml b/ui/res/values-ur-rPK/strings.xml
new file mode 100644
index 00000000..f7a2feaa
--- /dev/null
+++ b/ui/res/values-ur-rPK/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"ڈاؤن لوڈز"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"ڈاؤن لوڈز - تاریخ کے لحاظ سے مرتب"</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"ڈاؤن لوڈز - سائز کے لحاظ سے مرتب"</string>
+ <string name="no_downloads" msgid="1029667411186146836">"کوئی ڈاؤن لوڈز نہیں ہیں۔"</string>
+ <string name="missing_title" msgid="830115697868833773">"‏‎&gt;‎نامعلوم‎&amp;It;‎"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"سائز کے لحاظ سے ترتیب دیں"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"ترتیب دیں بلحاظ تاریخ"</string>
+ <string name="download_queued" msgid="104973307780629904">"قطار بند"</string>
+ <string name="download_running" msgid="4656462962155580641">"پیشرفت میں"</string>
+ <string name="download_success" msgid="7006048006543495236">"مکمل"</string>
+ <string name="download_error" msgid="8081329546008568251">"ناکام"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"ڈاؤن لوڈ نہیں کیا جا سکا"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"کیا آپ بعد میں فائل کو ڈاؤن لوڈ کرنے کی دوبارہ کوشش کرنا یا اسے قطار سے حذف کرنا چاہتے ہیں؟"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"فائل قطار میں ہے"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"یہ فائل آئندہ کے ڈاؤن لوڈ کیلئے قطار بند ہے اس لیے ابھی دستیاب نہیں ہے۔"</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"ڈاؤن لوڈ کردہ فائل تلاش نہیں کی جا سکتی ہے۔"</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"ڈاؤن لوڈ کو مکمل نہیں کر سکتے ہیں۔ خارجی اسٹوریج پر کافی جگہ نہیں ہے۔"</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"ڈاؤن لوڈ کو مکمل نہیں کر سکتے ہیں۔ داخلی ڈاؤن لوڈ اسٹوریج پر کافی جگہ نہیں ہے۔"</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"ڈاؤن لوڈ میں خلل پیدا ہو گیا اور دوبارہ شروع نہیں ہو سکتا۔"</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"ڈاؤن لوڈ نہیں کر سکتے ہیں۔ منزل مقصود کی فائل پہلے سے موجود ہے۔"</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"ڈاؤن لوڈ نہیں کر سکتے ہیں۔ خارجی میڈیا دستیاب نہیں ہے۔"</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"فائل نہيں کھول سکتے ہیں"</string>
+ <string name="remove_download" msgid="6372920256257247857">"ہٹائیں"</string>
+ <string name="delete_download" msgid="76629022653866471">"حذف کریں"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"رکھیں"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"منسوخ کریں"</string>
+ <string name="retry_download" msgid="7617100787922717912">"دوبارہ کوشش کریں"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"سبھی کو غیر منتخب کریں"</string>
+ <string name="select_all" msgid="634074918366265804">"سبھی کو منتخب کریں"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="NUMBER">%1$d</xliff:g> از <xliff:g id="TOTAL">%2$d</xliff:g> کو منتخب کیا گیا"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"اشتراک کریں بذریعہ"</string>
+</resources>
diff --git a/ui/res/values-uz-rUZ/strings.xml b/ui/res/values-uz-rUZ/strings.xml
new file mode 100644
index 00000000..11add3f9
--- /dev/null
+++ b/ui/res/values-uz-rUZ/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="3070921713463294774">"Yuklab olishlar"</string>
+ <string name="download_title_sorted_by_date" msgid="5898014492155434221">"Yuklab olishlar - Sana bo‘yicha saralan."</string>
+ <string name="download_title_sorted_by_size" msgid="1417193166677094813">"Yuklab olishlar - Hajm bo‘yicha saralan."</string>
+ <string name="no_downloads" msgid="1029667411186146836">"Yuklab olishlar yo‘q."</string>
+ <string name="missing_title" msgid="830115697868833773">"&lt;Noma’lum&gt;"</string>
+ <string name="button_sort_by_size" msgid="7331549713691146251">"Hajmi bo‘yicha saralash"</string>
+ <string name="button_sort_by_date" msgid="8800842892684101528">"Sanasi bo‘yicha saralash"</string>
+ <string name="download_queued" msgid="104973307780629904">"Navbatda"</string>
+ <string name="download_running" msgid="4656462962155580641">"Yuk. amalda"</string>
+ <string name="download_success" msgid="7006048006543495236">"Y"</string>
+ <string name="download_error" msgid="8081329546008568251">"Muvaff-siz"</string>
+ <string name="dialog_title_not_available" msgid="5746317632356158515">"Yuklab olinmadi"</string>
+ <string name="dialog_failed_body" msgid="587545111677064427">"Faylni keyinroq qaytadan yuklab olishga urinib ko‘rasizmi yoki navbatdan o‘chirilsinmi?"</string>
+ <string name="dialog_title_queued_body" msgid="6760681913815015219">"Fayl navbatda"</string>
+ <string name="dialog_queued_body" msgid="708552801635572720">"Ushbu fayl keyinroq yuklab olish uchun navbatga qo‘shildi, shuning uchun hozir mavjud emas."</string>
+ <string name="dialog_file_missing_body" msgid="3223012612774276284">"Yukab olingan fayl topilmadi."</string>
+ <string name="dialog_insufficient_space_on_external" msgid="8692452156251449195">"Yuklab olish tugamadi. Tashqi yuklab olish xotirasida yetarlicha bo‘sh joy yo‘q."</string>
+ <string name="dialog_insufficient_space_on_cache" msgid="6313630206163908994">"Yuklab olish tugamadi. Ichki yuklab olish xotirasida yetarlicha bo‘sh joy yo‘q."</string>
+ <string name="dialog_cannot_resume" msgid="8664509751358983543">"Yuklab olish uzildi, shuning uchun davom ettirib bo‘lmaydi."</string>
+ <string name="dialog_file_already_exists" msgid="8308563940663449590">"Yuklab olinmadi. Mo‘ljaldagi fayl allaqachon mavjud."</string>
+ <string name="dialog_media_not_found" msgid="4468088418758018765">"Yuklab olinmadi. Tashqi xotira qurilmasi mavjud emas."</string>
+ <string name="download_no_application_title" msgid="7024782176657362251">"Fayl ochilmadi"</string>
+ <string name="remove_download" msgid="6372920256257247857">"O‘chirish"</string>
+ <string name="delete_download" msgid="76629022653866471">"O‘chirish"</string>
+ <string name="keep_queued_download" msgid="5144882786014818569">"Saqlash"</string>
+ <string name="cancel_running_download" msgid="5232704030969221112">"Bekor qilish"</string>
+ <string name="retry_download" msgid="7617100787922717912">"Qayta urinish"</string>
+ <string name="deselect_all" msgid="6348198946254776764">"Belgilashlarni bekor qil."</string>
+ <string name="select_all" msgid="634074918366265804">"Barchasini belgilash"</string>
+ <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="TOTAL">%2$d</xliff:g>dan <xliff:g id="NUMBER">%1$d</xliff:g>ta belgilandi"</string>
+ <string name="download_share_dialog" msgid="3355867339806448955">"Bu orqali ulashish:"</string>
+</resources>
diff --git a/ui/res/values/dimen.xml b/ui/res/values/dimen.xml
deleted file mode 100644
index 7519b878..00000000
--- a/ui/res/values/dimen.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources>
- <dimen name="checkmark_area">48dip</dimen>
-</resources>
diff --git a/ui/src/com/android/providers/downloads/ui/DateSortedDownloadAdapter.java b/ui/src/com/android/providers/downloads/ui/DateSortedDownloadAdapter.java
deleted file mode 100644
index b69fb8b8..00000000
--- a/ui/src/com/android/providers/downloads/ui/DateSortedDownloadAdapter.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.providers.downloads.ui;
-
-import android.app.DownloadManager;
-import android.database.Cursor;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ExpandableListView;
-import android.widget.RelativeLayout;
-
-/**
- * Adapter for a date-sorted list of downloads. Delegates all the real work to
- * {@link DownloadAdapter}.
- */
-public class DateSortedDownloadAdapter extends DateSortedExpandableListAdapter {
- private final DownloadAdapter mDelegate;
- private final DownloadList mDownloadList;
-
- public DateSortedDownloadAdapter(DownloadList downloadList, Cursor cursor) {
- super(downloadList, cursor,
- cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP));
- mDelegate = new DownloadAdapter(downloadList, cursor);
- mDownloadList = downloadList;
- }
-
- @Override
- public View getChildView(int groupPosition, int childPosition,
- boolean isLastChild, View convertView, ViewGroup parent) {
- // The layout file uses a RelativeLayout, whereas the GroupViews use TextView.
- if (null == convertView || !(convertView instanceof RelativeLayout)) {
- convertView = mDelegate.newView();
- }
-
- // Bail early if the Cursor is closed.
- if (!moveCursorToChildPosition(groupPosition, childPosition)) {
- return convertView;
- }
-
- int pos = mDownloadList.getExpandableListView().getFlatListPosition(
- ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
- mDelegate.bindView(convertView, pos);
- return convertView;
- }
-}
diff --git a/ui/src/com/android/providers/downloads/ui/DateSortedExpandableListAdapter.java b/ui/src/com/android/providers/downloads/ui/DateSortedExpandableListAdapter.java
deleted file mode 100644
index f5d70770..00000000
--- a/ui/src/com/android/providers/downloads/ui/DateSortedExpandableListAdapter.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.providers.downloads.ui;
-
-import android.app.DownloadManager;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.database.DataSetObserver;
-import android.os.Handler;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.webkit.DateSorter;
-import android.widget.ExpandableListAdapter;
-import android.widget.ExpandableListView;
-import android.widget.TextView;
-
-import java.util.Vector;
-
-/**
- * ExpandableListAdapter which separates data into categories based on date. Copied from
- * packages/apps/Browser.
- */
-public class DateSortedExpandableListAdapter implements ExpandableListAdapter {
- // Array for each of our bins. Each entry represents how many items are
- // in that bin.
- private int mItemMap[];
- // This is our GroupCount. We will have at most DateSorter.DAY_COUNT
- // bins, less if the user has no items in one or more bins.
- private int mNumberOfBins;
- private Vector<DataSetObserver> mObservers;
- private Cursor mCursor;
- private DateSorter mDateSorter;
- private int mDateIndex;
- private int mIdIndex;
- private Context mContext;
-
- private class ChangeObserver extends ContentObserver {
- public ChangeObserver() {
- super(new Handler());
- }
-
- @Override
- public boolean deliverSelfNotifications() {
- return true;
- }
-
- @Override
- public void onChange(boolean selfChange) {
- refreshData();
- }
- }
-
- private class MyDataSetObserver extends DataSetObserver {
- @Override
- public void onChanged() {
- buildMap();
- for (DataSetObserver o : mObservers) {
- o.onChanged();
- }
- }
- }
-
- public DateSortedExpandableListAdapter(Context context, Cursor cursor,
- int dateIndex) {
- mContext = context;
- mDateSorter = new DateSorter(context);
- mObservers = new Vector<DataSetObserver>();
- mCursor = cursor;
- mIdIndex = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID);
- cursor.registerContentObserver(new ChangeObserver());
- cursor.registerDataSetObserver(new MyDataSetObserver());
- mDateIndex = dateIndex;
- buildMap();
- }
-
- /**
- * Set up the bins for determining which items belong to which groups.
- */
- private void buildMap() {
- // The cursor is sorted by date
- // The ItemMap will store the number of items in each bin.
- int array[] = new int[DateSorter.DAY_COUNT];
- // Zero out the array.
- for (int j = 0; j < DateSorter.DAY_COUNT; j++) {
- array[j] = 0;
- }
- mNumberOfBins = 0;
- int dateIndex = -1;
- if (mCursor.moveToFirst() && mCursor.getCount() > 0) {
- while (!mCursor.isAfterLast()) {
- long date = getLong(mDateIndex);
- int index = mDateSorter.getIndex(date);
- if (index > dateIndex) {
- mNumberOfBins++;
- if (index == DateSorter.DAY_COUNT - 1) {
- // We are already in the last bin, so it will
- // include all the remaining items
- array[index] = mCursor.getCount()
- - mCursor.getPosition();
- break;
- }
- dateIndex = index;
- }
- array[dateIndex]++;
- mCursor.moveToNext();
- }
- }
- mItemMap = array;
- }
-
- /**
- * Get the byte array at cursorIndex from the Cursor. Assumes the Cursor
- * has already been moved to the correct position. Along with
- * {@link #getInt} and {@link #getString}, these are provided so the client
- * does not need to access the Cursor directly
- * @param cursorIndex Index to query the Cursor.
- * @return corresponding byte array from the Cursor.
- */
- /* package */ byte[] getBlob(int cursorIndex) {
- return mCursor.getBlob(cursorIndex);
- }
-
- /* package */ Context getContext() {
- return mContext;
- }
-
- /**
- * Get the integer at cursorIndex from the Cursor. Assumes the Cursor has
- * already been moved to the correct position. Along with
- * {@link #getBlob} and {@link #getString}, these are provided so the client
- * does not need to access the Cursor directly
- * @param cursorIndex Index to query the Cursor.
- * @return corresponding integer from the Cursor.
- */
- /* package */ int getInt(int cursorIndex) {
- return mCursor.getInt(cursorIndex);
- }
-
- /**
- * Get the long at cursorIndex from the Cursor. Assumes the Cursor has
- * already been moved to the correct position.
- */
- /* package */ long getLong(int cursorIndex) {
- return mCursor.getLong(cursorIndex);
- }
-
- /**
- * Get the String at cursorIndex from the Cursor. Assumes the Cursor has
- * already been moved to the correct position. Along with
- * {@link #getInt} and {@link #getInt}, these are provided so the client
- * does not need to access the Cursor directly
- * @param cursorIndex Index to query the Cursor.
- * @return corresponding String from the Cursor.
- */
- /* package */ String getString(int cursorIndex) {
- return mCursor.getString(cursorIndex);
- }
-
- /**
- * Determine which group an item belongs to.
- * @param childId ID of the child view in question.
- * @return int Group position of the containing group.
- /* package */ int groupFromChildId(long childId) {
- int group = -1;
- for (mCursor.moveToFirst(); !mCursor.isAfterLast();
- mCursor.moveToNext()) {
- if (getLong(mIdIndex) == childId) {
- int bin = mDateSorter.getIndex(getLong(mDateIndex));
- // bin is the same as the group if the number of bins is the
- // same as DateSorter
- if (DateSorter.DAY_COUNT == mNumberOfBins) return bin;
- // There are some empty bins. Find the corresponding group.
- group = 0;
- for (int i = 0; i < bin; i++) {
- if (mItemMap[i] != 0) group++;
- }
- break;
- }
- }
- return group;
- }
-
- /**
- * Translates from a group position in the ExpandableList to a bin. This is
- * necessary because some groups have no history items, so we do not include
- * those in the ExpandableList.
- * @param groupPosition Position in the ExpandableList's set of groups
- * @return The corresponding bin that holds that group.
- */
- private int groupPositionToBin(int groupPosition) {
- if (groupPosition < 0 || groupPosition >= DateSorter.DAY_COUNT) {
- throw new AssertionError("group position out of range");
- }
- if (DateSorter.DAY_COUNT == mNumberOfBins || 0 == mNumberOfBins) {
- // In the first case, we have exactly the same number of bins
- // as our maximum possible, so there is no need to do a
- // conversion
- // The second statement is in case this method gets called when
- // the array is empty, in which case the provided groupPosition
- // will do fine.
- return groupPosition;
- }
- int arrayPosition = -1;
- while (groupPosition > -1) {
- arrayPosition++;
- if (mItemMap[arrayPosition] != 0) {
- groupPosition--;
- }
- }
- return arrayPosition;
- }
-
- /**
- * Move the cursor to the position indicated.
- * @param packedPosition Position in packed position representation.
- * @return True on success, false otherwise.
- */
- boolean moveCursorToPackedChildPosition(long packedPosition) {
- if (ExpandableListView.getPackedPositionType(packedPosition) !=
- ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
- return false;
- }
- int groupPosition = ExpandableListView.getPackedPositionGroup(
- packedPosition);
- int childPosition = ExpandableListView.getPackedPositionChild(
- packedPosition);
- return moveCursorToChildPosition(groupPosition, childPosition);
- }
-
- /**
- * Move the cursor the the position indicated.
- * @param groupPosition Index of the group containing the desired item.
- * @param childPosition Index of the item within the specified group.
- * @return boolean False if the cursor is closed, so the Cursor was not
- * moved. True on success.
- */
- /* package */ boolean moveCursorToChildPosition(int groupPosition,
- int childPosition) {
- if (mCursor.isClosed()) return false;
- groupPosition = groupPositionToBin(groupPosition);
- int index = childPosition;
- for (int i = 0; i < groupPosition; i++) {
- index += mItemMap[i];
- }
- return mCursor.moveToPosition(index);
- }
-
- /* package */ void refreshData() {
- if (mCursor.isClosed()) {
- return;
- }
- mCursor.requery();
- }
-
- public View getGroupView(int groupPosition, boolean isExpanded,
- View convertView, ViewGroup parent) {
- TextView item;
- if (null == convertView || !(convertView instanceof TextView)) {
- LayoutInflater factory = LayoutInflater.from(mContext);
- item = (TextView) factory.inflate(R.layout.list_group_header, parent, false);
- } else {
- item = (TextView) convertView;
- }
- String label = mDateSorter.getLabel(groupPositionToBin(groupPosition));
- item.setText(label);
- return item;
- }
-
- public View getChildView(int groupPosition, int childPosition,
- boolean isLastChild, View convertView, ViewGroup parent) {
- return null;
- }
-
- public boolean areAllItemsEnabled() {
- return true;
- }
-
- public boolean isChildSelectable(int groupPosition, int childPosition) {
- return true;
- }
-
- public int getGroupCount() {
- return mNumberOfBins;
- }
-
- public int getChildrenCount(int groupPosition) {
- return mItemMap[groupPositionToBin(groupPosition)];
- }
-
- public Object getGroup(int groupPosition) {
- return null;
- }
-
- public Object getChild(int groupPosition, int childPosition) {
- return null;
- }
-
- public long getGroupId(int groupPosition) {
- return groupPosition;
- }
-
- public long getChildId(int groupPosition, int childPosition) {
- if (moveCursorToChildPosition(groupPosition, childPosition)) {
- return getLong(mIdIndex);
- }
- return 0;
- }
-
- public boolean hasStableIds() {
- return true;
- }
-
- public void registerDataSetObserver(DataSetObserver observer) {
- mObservers.add(observer);
- }
-
- public void unregisterDataSetObserver(DataSetObserver observer) {
- mObservers.remove(observer);
- }
-
- public void onGroupExpanded(int groupPosition) {
- }
-
- public void onGroupCollapsed(int groupPosition) {
- }
-
- public long getCombinedChildId(long groupId, long childId) {
- return childId;
- }
-
- public long getCombinedGroupId(long groupId) {
- return groupId;
- }
-
- public boolean isEmpty() {
- return mCursor.isClosed() || mCursor.getCount() == 0;
- }
-}
diff --git a/ui/src/com/android/providers/downloads/ui/DownloadAdapter.java b/ui/src/com/android/providers/downloads/ui/DownloadAdapter.java
deleted file mode 100644
index 9ce2a986..00000000
--- a/ui/src/com/android/providers/downloads/ui/DownloadAdapter.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.providers.downloads.ui;
-
-import android.app.DownloadManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.text.format.Formatter;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.CursorAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.text.DateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.List;
-
-/**
- * List adapter for Cursors returned by {@link DownloadManager}.
- */
-public class DownloadAdapter extends CursorAdapter {
- private final DownloadList mDownloadList;
- private Cursor mCursor;
- private Resources mResources;
- private DateFormat mDateFormat;
- private DateFormat mTimeFormat;
-
- private final int mTitleColumnId;
- private final int mDescriptionColumnId;
- private final int mStatusColumnId;
- private final int mReasonColumnId;
- private final int mTotalBytesColumnId;
- private final int mMediaTypeColumnId;
- private final int mDateColumnId;
- private final int mIdColumnId;
- private final int mFileNameColumnId;
-
- public DownloadAdapter(DownloadList downloadList, Cursor cursor) {
- super(downloadList, cursor);
- mDownloadList = downloadList;
- mCursor = cursor;
- mResources = mDownloadList.getResources();
- mDateFormat = DateFormat.getDateInstance(DateFormat.SHORT);
- mTimeFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
-
- mIdColumnId = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID);
- mTitleColumnId = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TITLE);
- mDescriptionColumnId = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_DESCRIPTION);
- mStatusColumnId = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS);
- mReasonColumnId = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON);
- mTotalBytesColumnId = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
- mMediaTypeColumnId = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_MEDIA_TYPE);
- mDateColumnId =
- cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP);
- mFileNameColumnId =
- cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_FILENAME);
- }
-
- public View newView() {
- final DownloadItem view = (DownloadItem) LayoutInflater.from(mDownloadList)
- .inflate(R.layout.download_list_item, null);
- view.setDownloadListObj(mDownloadList);
- return view;
- }
-
- public void bindView(View convertView, int position) {
- if (!(convertView instanceof DownloadItem)) {
- return;
- }
-
- long downloadId = mCursor.getLong(mIdColumnId);
- ((DownloadItem) convertView).setData(downloadId, position,
- mCursor.getString(mFileNameColumnId),
- mCursor.getString(mMediaTypeColumnId));
-
- // Retrieve the icon for this download
- retrieveAndSetIcon(convertView);
-
- String title = mCursor.getString(mTitleColumnId);
- if (title.isEmpty()) {
- title = mResources.getString(R.string.missing_title);
- }
- setTextForView(convertView, R.id.download_title, title);
- setTextForView(convertView, R.id.domain, mCursor.getString(mDescriptionColumnId));
- setTextForView(convertView, R.id.size_text, getSizeText());
-
- final int status = mCursor.getInt(mStatusColumnId);
- final CharSequence statusText;
- if (status == DownloadManager.STATUS_SUCCESSFUL) {
- statusText = getDateString();
- } else {
- statusText = mResources.getString(getStatusStringId(status));
- }
- setTextForView(convertView, R.id.status_text, statusText);
-
- ((DownloadItem) convertView).getCheckBox()
- .setChecked(mDownloadList.isDownloadSelected(downloadId));
- }
-
- private String getDateString() {
- Date date = new Date(mCursor.getLong(mDateColumnId));
- if (date.before(getStartOfToday())) {
- return mDateFormat.format(date);
- } else {
- return mTimeFormat.format(date);
- }
- }
-
- private Date getStartOfToday() {
- Calendar today = new GregorianCalendar();
- today.set(Calendar.HOUR_OF_DAY, 0);
- today.set(Calendar.MINUTE, 0);
- today.set(Calendar.SECOND, 0);
- today.set(Calendar.MILLISECOND, 0);
- return today.getTime();
- }
-
- private String getSizeText() {
- long totalBytes = mCursor.getLong(mTotalBytesColumnId);
- String sizeText = "";
- if (totalBytes >= 0) {
- sizeText = Formatter.formatFileSize(mContext, totalBytes);
- }
- return sizeText;
- }
-
- private int getStatusStringId(int status) {
- switch (status) {
- case DownloadManager.STATUS_FAILED:
- return R.string.download_error;
-
- case DownloadManager.STATUS_SUCCESSFUL:
- return R.string.download_success;
-
- case DownloadManager.STATUS_PENDING:
- case DownloadManager.STATUS_RUNNING:
- return R.string.download_running;
-
- case DownloadManager.STATUS_PAUSED:
- final int reason = mCursor.getInt(mReasonColumnId);
- switch (reason) {
- case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
- return R.string.download_queued;
- default:
- return R.string.download_running;
- }
- }
- throw new IllegalStateException("Unknown status: " + mCursor.getInt(mStatusColumnId));
- }
-
- private void retrieveAndSetIcon(View convertView) {
- String mediaType = mCursor.getString(mMediaTypeColumnId);
- ImageView iconView = (ImageView) convertView.findViewById(R.id.download_icon);
- iconView.setVisibility(View.INVISIBLE);
-
- if (mediaType == null) {
- return;
- }
-
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(Uri.fromParts("file", "", null), mediaType);
- PackageManager pm = mContext.getPackageManager();
- List<ResolveInfo> list = pm.queryIntentActivities(intent,
- PackageManager.MATCH_DEFAULT_ONLY);
- if (list.size() == 0) {
- // no icon found for this mediatype. use "unknown" icon
- iconView.setImageResource(R.drawable.ic_download_misc_file_type);
- } else {
- Drawable icon = list.get(0).activityInfo.loadIcon(pm);
- iconView.setImageDrawable(icon);
- }
- iconView.setVisibility(View.VISIBLE);
- }
-
- private void setTextForView(View parent, int textViewId, CharSequence text) {
- TextView view = (TextView) parent.findViewById(textViewId);
- view.setText(text);
- }
-
- // CursorAdapter overrides
-
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return newView();
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- bindView(view, cursor.getPosition());
- }
-}
diff --git a/ui/src/com/android/providers/downloads/ui/DownloadItem.java b/ui/src/com/android/providers/downloads/ui/DownloadItem.java
deleted file mode 100644
index 0562cd05..00000000
--- a/ui/src/com/android/providers/downloads/ui/DownloadItem.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.providers.downloads.ui;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.CheckBox;
-import android.widget.Checkable;
-import android.widget.GridLayout;
-
-/**
- * This class customizes RelativeLayout to directly handle clicks on the left part of the view and
- * treat them at clicks on the checkbox. This makes rapid selection of many items easier. This class
- * also keeps an ID associated with the currently displayed download and notifies a listener upon
- * selection changes with that ID.
- */
-public class DownloadItem extends GridLayout implements Checkable {
- private static float CHECKMARK_AREA = -1;
-
- private boolean mIsInDownEvent = false;
- private CheckBox mCheckBox;
- private long mDownloadId;
- private String mFileName;
- private String mMimeType;
- private DownloadList mDownloadList;
- private int mPosition;
-
- public DownloadItem(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- initialize();
- }
-
- public DownloadItem(Context context, AttributeSet attrs) {
- super(context, attrs);
- initialize();
- }
-
- public DownloadItem(Context context) {
- super(context);
- initialize();
- }
-
- private void initialize() {
- if (CHECKMARK_AREA == -1) {
- CHECKMARK_AREA = getResources().getDimensionPixelSize(R.dimen.checkmark_area);
- }
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mCheckBox = (CheckBox) findViewById(R.id.download_checkbox);
- }
-
- public void setData(long downloadId, int position, String fileName, String mimeType) {
- mDownloadId = downloadId;
- mPosition = position;
- mFileName = fileName;
- mMimeType = mimeType;
- if (mDownloadList.isDownloadSelected(downloadId)) {
- setChecked(true);
- }
- }
-
- public void setDownloadListObj(DownloadList downloadList) {
- mDownloadList = downloadList;
- }
-
- private boolean inCheckArea(MotionEvent event) {
- if (isLayoutRtl()) {
- return event.getX() > getWidth() - CHECKMARK_AREA;
- } else {
- return event.getX() < CHECKMARK_AREA;
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- boolean handled = false;
- switch(event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (inCheckArea(event)) {
- mIsInDownEvent = true;
- handled = true;
- }
- break;
-
- case MotionEvent.ACTION_CANCEL:
- mIsInDownEvent = false;
- break;
-
- case MotionEvent.ACTION_UP:
- if (mIsInDownEvent && inCheckArea(event)) {
- toggle();
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
- handled = true;
- }
- mIsInDownEvent = false;
- break;
- }
-
- if (handled) {
- postInvalidate();
- } else {
- handled = super.onTouchEvent(event);
- }
-
- return handled;
- }
-
- @Override
- public boolean isChecked() {
- return mCheckBox.isChecked();
- }
-
- @Override
- public void setChecked(boolean checked) {
- mCheckBox.setChecked(checked);
- mDownloadList.onDownloadSelectionChanged(mDownloadId, mCheckBox.isChecked(),
- mFileName, mMimeType);
- mDownloadList.getCurrentView().setItemChecked(mPosition, mCheckBox.isChecked());
- }
-
- @Override
- public void toggle() {
- setChecked(!isChecked());
- }
-
- public CheckBox getCheckBox() {
- return this.mCheckBox;
- }
-
- public String getFileName() {
- return mFileName;
- }
-
- public String getMimeType() {
- return mMimeType;
- }
-}
diff --git a/ui/src/com/android/providers/downloads/ui/DownloadList.java b/ui/src/com/android/providers/downloads/ui/DownloadList.java
index 107940c0..044bd4eb 100644
--- a/ui/src/com/android/providers/downloads/ui/DownloadList.java
+++ b/ui/src/com/android/providers/downloads/ui/DownloadList.java
@@ -17,134 +17,13 @@
package com.android.providers.downloads.ui;
import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.DownloadManager;
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.database.DataSetObserver;
-import android.net.Uri;
import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.Parcelable;
-import android.provider.BaseColumns;
import android.provider.DocumentsContract;
-import android.provider.Downloads;
-import android.util.Log;
-import android.util.SparseBooleanArray;
-import android.view.ActionMode;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AbsListView.MultiChoiceModeListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.Button;
-import android.widget.ExpandableListView;
-import android.widget.ExpandableListView.OnChildClickListener;
-import android.widget.ListView;
-import android.widget.Toast;
import com.android.providers.downloads.Constants;
-import com.android.providers.downloads.OpenHelper;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * View showing a list of all downloads the Download Manager knows about.
- */
public class DownloadList extends Activity {
- static final String LOG_TAG = "DownloadList";
-
- private ExpandableListView mDateOrderedListView;
- private ListView mSizeOrderedListView;
- private View mEmptyView;
-
- private DownloadManager mDownloadManager;
- private Cursor mDateSortedCursor;
- private DateSortedDownloadAdapter mDateSortedAdapter;
- private Cursor mSizeSortedCursor;
- private DownloadAdapter mSizeSortedAdapter;
- private ActionMode mActionMode;
- private MyContentObserver mContentObserver = new MyContentObserver();
- private MyDataSetObserver mDataSetObserver = new MyDataSetObserver();
-
- private int mStatusColumnId;
- private int mIdColumnId;
- private int mLocalUriColumnId;
- private int mMediaTypeColumnId;
- private int mReasonColumndId;
-
- // TODO this shouldn't be necessary
- private final Map<Long, SelectionObjAttrs> mSelectedIds =
- new HashMap<Long, SelectionObjAttrs>();
- private static class SelectionObjAttrs {
- private String mFileName;
- private String mMimeType;
- SelectionObjAttrs(String fileName, String mimeType) {
- mFileName = fileName;
- mMimeType = mimeType;
- }
- String getFileName() {
- return mFileName;
- }
- String getMimeType() {
- return mMimeType;
- }
- }
- private ListView mCurrentView;
- private Cursor mCurrentCursor;
- private boolean mCurrentViewIsExpandableListView = false;
- private boolean mIsSortedBySize = false;
-
- /**
- * We keep track of when a dialog is being displayed for a pending download, because if that
- * download starts running, we want to immediately hide the dialog.
- */
- private Long mQueuedDownloadId = null;
- private AlertDialog mQueuedDialog;
- String mSelectedCountFormat;
-
- private Button mSortOption;
-
- private class MyContentObserver extends ContentObserver {
- public MyContentObserver() {
- super(new Handler());
- }
-
- @Override
- public void onChange(boolean selfChange) {
- handleDownloadsChanged();
- }
- }
-
- private class MyDataSetObserver extends DataSetObserver {
- @Override
- public void onChanged() {
- // ignore change notification if there are selections
- if (mSelectedIds.size() > 0) {
- return;
- }
- // may need to switch to or from the empty view
- chooseListToShow();
- ensureSomeGroupIsExpanded();
- }
- }
-
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -156,648 +35,4 @@ public class DownloadList extends Activity {
startActivity(intent);
finish();
}
-
- public void onCreateLegacy(Bundle icicle) {
- super.onCreate(icicle);
- setFinishOnTouchOutside(true);
- setupViews();
-
- mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
- mDownloadManager.setAccessAllDownloads(true);
- DownloadManager.Query baseQuery = new DownloadManager.Query()
- .setOnlyIncludeVisibleInDownloadsUi(true);
- //TODO don't do both queries - do them as needed
- mDateSortedCursor = mDownloadManager.query(baseQuery);
- mSizeSortedCursor = mDownloadManager.query(baseQuery
- .orderBy(DownloadManager.COLUMN_TOTAL_SIZE_BYTES,
- DownloadManager.Query.ORDER_DESCENDING));
-
- // only attach everything to the listbox if we can access the download database. Otherwise,
- // just show it empty
- if (haveCursors()) {
- startManagingCursor(mDateSortedCursor);
- startManagingCursor(mSizeSortedCursor);
-
- mStatusColumnId =
- mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS);
- mIdColumnId =
- mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID);
- mLocalUriColumnId =
- mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_URI);
- mMediaTypeColumnId =
- mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_MEDIA_TYPE);
- mReasonColumndId =
- mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON);
-
- mDateSortedAdapter = new DateSortedDownloadAdapter(this, mDateSortedCursor);
- mDateOrderedListView.setAdapter(mDateSortedAdapter);
- mSizeSortedAdapter = new DownloadAdapter(this, mSizeSortedCursor);
- mSizeOrderedListView.setAdapter(mSizeSortedAdapter);
-
- ensureSomeGroupIsExpanded();
- }
-
- // did the caller want to display the data sorted by size?
- Bundle extras = getIntent().getExtras();
- if (extras != null &&
- extras.getBoolean(DownloadManager.INTENT_EXTRAS_SORT_BY_SIZE, false)) {
- mIsSortedBySize = true;
- }
- mSortOption = (Button) findViewById(R.id.sort_button);
- mSortOption.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // flip the view
- mIsSortedBySize = !mIsSortedBySize;
- // clear all selections
- mSelectedIds.clear();
- chooseListToShow();
- }
- });
-
- chooseListToShow();
- mSelectedCountFormat = getString(R.string.selected_count);
- }
-
- /**
- * If no group is expanded in the date-sorted list, expand the first one.
- */
- private void ensureSomeGroupIsExpanded() {
- mDateOrderedListView.post(new Runnable() {
- public void run() {
- if (mDateSortedAdapter.getGroupCount() == 0) {
- return;
- }
- for (int group = 0; group < mDateSortedAdapter.getGroupCount(); group++) {
- if (mDateOrderedListView.isGroupExpanded(group)) {
- return;
- }
- }
- mDateOrderedListView.expandGroup(0);
- }
- });
- }
-
- private void setupViews() {
- setContentView(R.layout.download_list);
- ModeCallback modeCallback = new ModeCallback(this);
-
- //TODO don't create both views. create only the one needed.
- mDateOrderedListView = (ExpandableListView) findViewById(R.id.date_ordered_list);
- mDateOrderedListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
- mDateOrderedListView.setMultiChoiceModeListener(modeCallback);
- mDateOrderedListView.setOnChildClickListener(new OnChildClickListener() {
- // called when a child is clicked on (this is NOT the checkbox click)
- @Override
- public boolean onChildClick(ExpandableListView parent, View v,
- int groupPosition, int childPosition, long id) {
- if (!(v instanceof DownloadItem)) {
- // can this even happen?
- return false;
- }
- if (mSelectedIds.size() > 0) {
- ((DownloadItem)v).setChecked(true);
- } else {
- mDateSortedAdapter.moveCursorToChildPosition(groupPosition, childPosition);
- handleItemClick(mDateSortedCursor);
- }
- return true;
- }
- });
- mSizeOrderedListView = (ListView) findViewById(R.id.size_ordered_list);
- mSizeOrderedListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
- mSizeOrderedListView.setMultiChoiceModeListener(modeCallback);
- mSizeOrderedListView.setOnItemClickListener(new OnItemClickListener() {
- // handle a click from the size-sorted list. (this is NOT the checkbox click)
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- mSizeSortedCursor.moveToPosition(position);
- handleItemClick(mSizeSortedCursor);
- }
- });
- mEmptyView = findViewById(R.id.empty);
- }
-
- private static class ModeCallback implements MultiChoiceModeListener {
- private final DownloadList mDownloadList;
-
- public ModeCallback(DownloadList downloadList) {
- mDownloadList = downloadList;
- }
-
- @Override public void onDestroyActionMode(ActionMode mode) {
- mDownloadList.mSelectedIds.clear();
- mDownloadList.mActionMode = null;
- }
-
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- return true;
- }
-
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- if (mDownloadList.haveCursors()) {
- final MenuInflater inflater = mDownloadList.getMenuInflater();
- inflater.inflate(R.menu.download_menu, menu);
- }
- mDownloadList.mActionMode = mode;
- return true;
- }
-
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- if (mDownloadList.mSelectedIds.size() == 0) {
- // nothing selected.
- return true;
- }
- switch (item.getItemId()) {
- case R.id.delete_download:
- for (Long downloadId : mDownloadList.mSelectedIds.keySet()) {
- mDownloadList.deleteDownload(downloadId);
- }
- // uncheck all checked items
- ListView lv = mDownloadList.getCurrentView();
- SparseBooleanArray checkedPositionList = lv.getCheckedItemPositions();
- int checkedPositionListSize = checkedPositionList.size();
- ArrayList<DownloadItem> sharedFiles = null;
- for (int i = 0; i < checkedPositionListSize; i++) {
- int position = checkedPositionList.keyAt(i);
- if (checkedPositionList.get(position, false)) {
- lv.setItemChecked(position, false);
- onItemCheckedStateChanged(mode, position, 0, false);
- }
- }
- mDownloadList.mSelectedIds.clear();
- // update the subtitle
- onItemCheckedStateChanged(mode, 1, 0, false);
- break;
- case R.id.share_download:
- mDownloadList.shareDownloadedFiles();
- break;
- }
- return true;
- }
-
- @Override
- public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
- boolean checked) {
- // ignore long clicks on groups
- if (mDownloadList.isCurrentViewExpandableListView()) {
- ExpandableListView ev = mDownloadList.getExpandableListView();
- long pos = ev.getExpandableListPosition(position);
- if (checked && (ExpandableListView.getPackedPositionType(pos) ==
- ExpandableListView.PACKED_POSITION_TYPE_GROUP)) {
- // ignore this click
- ev.setItemChecked(position, false);
- return;
- }
- }
- mDownloadList.setActionModeTitle(mode);
- }
- }
-
- void setActionModeTitle(ActionMode mode) {
- int numSelected = mSelectedIds.size();
- if (numSelected > 0) {
- mode.setTitle(String.format(mSelectedCountFormat, numSelected,
- mCurrentCursor.getCount()));
- } else {
- mode.setTitle("");
- }
- }
-
- private boolean haveCursors() {
- return mDateSortedCursor != null && mSizeSortedCursor != null;
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (haveCursors()) {
- mDateSortedCursor.registerContentObserver(mContentObserver);
- mDateSortedCursor.registerDataSetObserver(mDataSetObserver);
- refresh();
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- if (haveCursors()) {
- mDateSortedCursor.unregisterContentObserver(mContentObserver);
- mDateSortedCursor.unregisterDataSetObserver(mDataSetObserver);
- }
- }
-
- private static final String BUNDLE_SAVED_DOWNLOAD_IDS = "download_ids";
- private static final String BUNDLE_SAVED_FILENAMES = "filenames";
- private static final String BUNDLE_SAVED_MIMETYPES = "mimetypes";
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putBoolean("isSortedBySize", mIsSortedBySize);
- int len = mSelectedIds.size();
- if (len == 0) {
- return;
- }
- long[] selectedIds = new long[len];
- String[] fileNames = new String[len];
- String[] mimeTypes = new String[len];
- int i = 0;
- for (long id : mSelectedIds.keySet()) {
- selectedIds[i] = id;
- SelectionObjAttrs obj = mSelectedIds.get(id);
- fileNames[i] = obj.getFileName();
- mimeTypes[i] = obj.getMimeType();
- i++;
- }
- outState.putLongArray(BUNDLE_SAVED_DOWNLOAD_IDS, selectedIds);
- outState.putStringArray(BUNDLE_SAVED_FILENAMES, fileNames);
- outState.putStringArray(BUNDLE_SAVED_MIMETYPES, mimeTypes);
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- mIsSortedBySize = savedInstanceState.getBoolean("isSortedBySize");
- mSelectedIds.clear();
- long[] selectedIds = savedInstanceState.getLongArray(BUNDLE_SAVED_DOWNLOAD_IDS);
- String[] fileNames = savedInstanceState.getStringArray(BUNDLE_SAVED_FILENAMES);
- String[] mimeTypes = savedInstanceState.getStringArray(BUNDLE_SAVED_MIMETYPES);
- if (selectedIds != null && selectedIds.length > 0) {
- for (int i = 0; i < selectedIds.length; i++) {
- mSelectedIds.put(selectedIds[i], new SelectionObjAttrs(fileNames[i], mimeTypes[i]));
- }
- }
- chooseListToShow();
- }
-
- /**
- * Show the correct ListView and hide the other, or hide both and show the empty view.
- */
- private void chooseListToShow() {
- mDateOrderedListView.setVisibility(View.GONE);
- mSizeOrderedListView.setVisibility(View.GONE);
-
- if (mDateSortedCursor == null || mDateSortedCursor.getCount() == 0) {
- mEmptyView.setVisibility(View.VISIBLE);
- mSortOption.setVisibility(View.GONE);
- } else {
- mEmptyView.setVisibility(View.GONE);
- mSortOption.setVisibility(View.VISIBLE);
- ListView lv = activeListView();
- lv.setVisibility(View.VISIBLE);
- lv.invalidateViews(); // ensure checkboxes get updated
- }
- // restore the ActionMode title if there are selections
- if (mActionMode != null) {
- setActionModeTitle(mActionMode);
- }
- }
-
- ListView getCurrentView() {
- return mCurrentView;
- }
-
- ExpandableListView getExpandableListView() {
- return mDateOrderedListView;
- }
-
- boolean isCurrentViewExpandableListView() {
- return mCurrentViewIsExpandableListView;
- }
-
- private ListView activeListView() {
- if (mIsSortedBySize) {
- mCurrentCursor = mSizeSortedCursor;
- mCurrentView = mSizeOrderedListView;
- setTitle(R.string.download_title_sorted_by_size);
- mSortOption.setText(R.string.button_sort_by_date);
- mCurrentViewIsExpandableListView = false;
- } else {
- mCurrentCursor = mDateSortedCursor;
- mCurrentView = mDateOrderedListView;
- setTitle(R.string.download_title_sorted_by_date);
- mSortOption.setText(R.string.button_sort_by_size);
- mCurrentViewIsExpandableListView = true;
- }
- if (mActionMode != null) {
- mActionMode.finish();
- }
- return mCurrentView;
- }
-
- /**
- * @return an OnClickListener to delete the given downloadId from the Download Manager
- */
- private DialogInterface.OnClickListener getDeleteClickHandler(final long downloadId) {
- return new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- deleteDownload(downloadId);
- }
- };
- }
-
- /**
- * @return an OnClickListener to restart the given downloadId in the Download Manager
- */
- private DialogInterface.OnClickListener getRestartClickHandler(final long downloadId) {
- return new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- mDownloadManager.restartDownload(downloadId);
- }
- };
- }
-
- /**
- * Send an Intent to open the download currently pointed to by the given cursor.
- */
- private void openCurrentDownload(Cursor cursor) {
- final Uri localUri = Uri.parse(cursor.getString(mLocalUriColumnId));
- try {
- getContentResolver().openFileDescriptor(localUri, "r").close();
- } catch (FileNotFoundException exc) {
- Log.d(LOG_TAG, "Failed to open download " + cursor.getLong(mIdColumnId), exc);
- showFailedDialog(cursor.getLong(mIdColumnId),
- getString(R.string.dialog_file_missing_body));
- return;
- } catch (IOException exc) {
- // close() failed, not a problem
- }
-
- final long id = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID));
- if (!OpenHelper.startViewIntent(this, id, 0)) {
- Toast.makeText(this, R.string.download_no_application_title, Toast.LENGTH_SHORT).show();
- }
- }
-
- private void handleItemClick(Cursor cursor) {
- long id = cursor.getInt(mIdColumnId);
- switch (cursor.getInt(mStatusColumnId)) {
- case DownloadManager.STATUS_PENDING:
- case DownloadManager.STATUS_RUNNING:
- sendRunningDownloadClickedBroadcast(id);
- break;
-
- case DownloadManager.STATUS_PAUSED:
- if (isPausedForWifi(cursor)) {
- mQueuedDownloadId = id;
- mQueuedDialog = new AlertDialog.Builder(this)
- .setTitle(R.string.dialog_title_queued_body)
- .setMessage(R.string.dialog_queued_body)
- .setPositiveButton(R.string.keep_queued_download, null)
- .setNegativeButton(R.string.remove_download, getDeleteClickHandler(id))
- .setOnCancelListener(new DialogInterface.OnCancelListener() {
- /**
- * Called when a dialog for a pending download is canceled.
- */
- @Override
- public void onCancel(DialogInterface dialog) {
- mQueuedDownloadId = null;
- mQueuedDialog = null;
- }
- })
- .show();
- } else {
- sendRunningDownloadClickedBroadcast(id);
- }
- break;
-
- case DownloadManager.STATUS_SUCCESSFUL:
- openCurrentDownload(cursor);
- break;
-
- case DownloadManager.STATUS_FAILED:
- showFailedDialog(id, getErrorMessage(cursor));
- break;
- }
- }
-
- /**
- * @return the appropriate error message for the failed download pointed to by cursor
- */
- private String getErrorMessage(Cursor cursor) {
- switch (cursor.getInt(mReasonColumndId)) {
- case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
- if (isOnExternalStorage(cursor)) {
- return getString(R.string.dialog_file_already_exists);
- } else {
- // the download manager should always find a free filename for cache downloads,
- // so this indicates a strange internal error
- return getUnknownErrorMessage();
- }
-
- case DownloadManager.ERROR_INSUFFICIENT_SPACE:
- if (isOnExternalStorage(cursor)) {
- return getString(R.string.dialog_insufficient_space_on_external);
- } else {
- return getString(R.string.dialog_insufficient_space_on_cache);
- }
-
- case DownloadManager.ERROR_DEVICE_NOT_FOUND:
- return getString(R.string.dialog_media_not_found);
-
- case DownloadManager.ERROR_CANNOT_RESUME:
- return getString(R.string.dialog_cannot_resume);
-
- default:
- return getUnknownErrorMessage();
- }
- }
-
- private boolean isOnExternalStorage(Cursor cursor) {
- String localUriString = cursor.getString(mLocalUriColumnId);
- if (localUriString == null) {
- return false;
- }
- Uri localUri = Uri.parse(localUriString);
- if (!localUri.getScheme().equals("file")) {
- return false;
- }
- String path = localUri.getPath();
- String externalRoot = Environment.getExternalStorageDirectory().getPath();
- return path.startsWith(externalRoot);
- }
-
- private String getUnknownErrorMessage() {
- return getString(R.string.dialog_failed_body);
- }
-
- private void showFailedDialog(long downloadId, String dialogBody) {
- new AlertDialog.Builder(this)
- .setTitle(R.string.dialog_title_not_available)
- .setMessage(dialogBody)
- .setNegativeButton(R.string.delete_download, getDeleteClickHandler(downloadId))
- .setPositiveButton(R.string.retry_download, getRestartClickHandler(downloadId))
- .show();
- }
-
- private void sendRunningDownloadClickedBroadcast(long id) {
- final Intent intent = new Intent(Constants.ACTION_LIST);
- intent.setPackage(Constants.PROVIDER_PACKAGE_NAME);
- intent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS,
- new long[] { id });
- sendBroadcast(intent);
- }
-
- // handle a click on one of the download item checkboxes
- public void onDownloadSelectionChanged(long downloadId, boolean isSelected,
- String fileName, String mimeType) {
- if (isSelected) {
- mSelectedIds.put(downloadId, new SelectionObjAttrs(fileName, mimeType));
- } else {
- mSelectedIds.remove(downloadId);
- }
- }
-
- /**
- * Requery the database and update the UI.
- */
- private void refresh() {
- mDateSortedCursor.requery();
- mSizeSortedCursor.requery();
- // Adapters get notification of changes and update automatically
- }
-
- /**
- * Delete a download from the Download Manager.
- */
- private void deleteDownload(long downloadId) {
- // let DownloadService do the job of cleaning up the downloads db, mediaprovider db,
- // and removal of file from sdcard
- // TODO do the following in asynctask - not on main thread.
- mDownloadManager.markRowDeleted(downloadId);
- }
-
- public boolean isDownloadSelected(long id) {
- return mSelectedIds.containsKey(id);
- }
-
- /**
- * Called when there's a change to the downloads database.
- */
- void handleDownloadsChanged() {
- checkSelectionForDeletedEntries();
-
- if (mQueuedDownloadId != null && moveToDownload(mQueuedDownloadId)) {
- if (mDateSortedCursor.getInt(mStatusColumnId) != DownloadManager.STATUS_PAUSED
- || !isPausedForWifi(mDateSortedCursor)) {
- mQueuedDialog.cancel();
- }
- }
- }
-
- private boolean isPausedForWifi(Cursor cursor) {
- return cursor.getInt(mReasonColumndId) == DownloadManager.PAUSED_QUEUED_FOR_WIFI;
- }
-
- /**
- * Check if any of the selected downloads have been deleted from the downloads database, and
- * remove such downloads from the selection.
- */
- private void checkSelectionForDeletedEntries() {
- // gather all existing IDs...
- Set<Long> allIds = new HashSet<Long>();
- for (mDateSortedCursor.moveToFirst(); !mDateSortedCursor.isAfterLast();
- mDateSortedCursor.moveToNext()) {
- allIds.add(mDateSortedCursor.getLong(mIdColumnId));
- }
-
- // ...and check if any selected IDs are now missing
- for (Iterator<Long> iterator = mSelectedIds.keySet().iterator(); iterator.hasNext(); ) {
- if (!allIds.contains(iterator.next())) {
- iterator.remove();
- }
- }
- }
-
- /**
- * Move {@link #mDateSortedCursor} to the download with the given ID.
- * @return true if the specified download ID was found; false otherwise
- */
- private boolean moveToDownload(long downloadId) {
- for (mDateSortedCursor.moveToFirst(); !mDateSortedCursor.isAfterLast();
- mDateSortedCursor.moveToNext()) {
- if (mDateSortedCursor.getLong(mIdColumnId) == downloadId) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * handle share menu button click when one more files are selected for sharing
- */
- public boolean shareDownloadedFiles() {
- Intent intent = new Intent();
- if (mSelectedIds.size() > 1) {
- intent.setAction(Intent.ACTION_SEND_MULTIPLE);
- ArrayList<Parcelable> attachments = new ArrayList<Parcelable>();
- ArrayList<String> mimeTypes = new ArrayList<String>();
- for (Map.Entry<Long, SelectionObjAttrs> item : mSelectedIds.entrySet()) {
- final Uri uri = ContentUris.withAppendedId(
- Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, item.getKey());
- final String mimeType = item.getValue().getMimeType();
- attachments.add(uri);
- if (mimeType != null) {
- mimeTypes.add(mimeType);
- }
- }
- intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, attachments);
- intent.setType(findCommonMimeType(mimeTypes));
- } else {
- // get the entry
- // since there is ONLY one entry in this, we can do the following
- for (Map.Entry<Long, SelectionObjAttrs> item : mSelectedIds.entrySet()) {
- final Uri uri = ContentUris.withAppendedId(
- Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, item.getKey());
- final String mimeType = item.getValue().getMimeType();
- intent.setAction(Intent.ACTION_SEND);
- intent.putExtra(Intent.EXTRA_STREAM, uri);
- intent.setType(mimeType);
- }
- }
- intent = Intent.createChooser(intent, getText(R.string.download_share_dialog));
- startActivity(intent);
- return true;
- }
-
- private String findCommonMimeType(ArrayList<String> mimeTypes) {
- // are all mimeypes the same?
- String str = findCommonString(mimeTypes);
- if (str != null) {
- return str;
- }
-
- // are all prefixes of the given mimetypes the same?
- ArrayList<String> mimeTypePrefixes = new ArrayList<String>();
- for (String s : mimeTypes) {
- if (s != null) {
- mimeTypePrefixes.add(s.substring(0, s.indexOf('/')));
- }
- }
- str = findCommonString(mimeTypePrefixes);
- if (str != null) {
- return str + "/*";
- }
-
- // return generic mimetype
- return "*/*";
- }
- private String findCommonString(Collection<String> set) {
- String str = null;
- boolean found = true;
- for (String s : set) {
- if (str == null) {
- str = s;
- } else if (!str.equals(s)) {
- found = false;
- break;
- }
- }
- return (found) ? str : null;
- }
}