summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml5
-rw-r--r--res/values-hi/strings.xml6
-rw-r--r--res/values-iw/strings.xml34
-rw-r--r--res/values-ja/strings.xml14
-rw-r--r--res/values-ka/strings.xml2
-rw-r--r--src/com/android/providers/downloads/Constants.java11
-rw-r--r--src/com/android/providers/downloads/DownloadIdleService.java2
-rw-r--r--src/com/android/providers/downloads/DownloadProvider.java99
-rw-r--r--src/com/android/providers/downloads/Helpers.java24
-rw-r--r--src/com/android/providers/downloads/MediaScanTriggerJob.java122
-rw-r--r--ui/res/values-hy/strings.xml2
-rw-r--r--ui/res/values-iw/strings.xml40
12 files changed, 268 insertions, 93 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 45e2888a..302a58e5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -107,6 +107,11 @@
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
+ <service
+ android:name=".MediaScanTriggerJob"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
+
<receiver android:name=".DownloadReceiver" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 25fdef60..24eb32b6 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -18,17 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3658948994665187911">"डाउनलोड प्रबंधक"</string>
<string name="storage_description" msgid="7982444311558023664">"डाउनलोड"</string>
- <string name="permlab_downloadManager" msgid="7779544811202855500">"डाउनलोड प्रबंधक में पहुंच प्राप्त करें."</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="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"ऐप्लिकेशन को डाउनलोड मैनेजर के बेहतर फ़ंक्शन के इस्तेमाल की मंज़ूरी देता है. धोखा देने वाले ऐप्लिकेशन इसका इस्तेमाल डाउनलोड को रोकने और निजी जानकारी तक पहुंचने के लिए कर सकते हैं."</string>
<string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"डाउनलोड सूचनाएं भेजें."</string>
<string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"पूरे किए गए डाउनलोड के बारे में ऐप को सूचना भेजने देता है. धोखा देने वाले ऐप इसका इस्तेमाल फ़ाइलों को डाउनलोड करने वाले दूसरे ऐप को भ्रम में डालने के लिए कर सकते हैं."</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="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>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index ab41db9c..e4c75dfc 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -19,29 +19,29 @@
<string name="app_label" msgid="3658948994665187911">"מנהל ההורדות"</string>
<string name="storage_description" msgid="7982444311558023664">"הורדות"</string>
<string name="permlab_downloadManager" msgid="7779544811202855500">"גישה למנהל ההורדות."</string>
- <string name="permdesc_downloadManager" msgid="4237406545998908947">"מאפשר לאפליקציה לגשת למנהל ההורדות ולהשתמש בו לצורך הורדת קבצים. אפליקציות זדוניות עלולות לנצל אפשרות זו כדי לשבש הורדות ולגשת למידע פרטי."</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_downloadCacheNonPurgeable" msgid="3069534308882047412">"שמור מקום במטמון ההורדות"</string>
- <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"מאפשר לאפליקציה להוריד קבצים למטמון ההורדות שלא ניתן למחוק באופן אוטומטי כאשר דרוש למנהל ההורדות שטח נוסף."</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_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="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="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">%1$s </xliff:g>. \n \n גע ב-<xliff:g id="QUEUE_TEXT">%2$s </xliff:g> כדי להפעיל את ההורדה בפעם הבאה שתתחבר לרשת Wi-Fi."</string>
+ <string name="wifi_required_body" msgid="3067694630143784449">"‏עליך להשתמש ב-Wi-Fi כדי להשלים את ההורדה שגודלה <xliff:g id="SIZE">%1$s </xliff:g>. \n \n אפשר לגעת ב-<xliff:g id="QUEUE_TEXT">%2$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">%1$s </xliff:g>) עשויה לקצר את חיי הסוללה שלך ו/או לגרום לניצול מופרז של חיבור הנתונים הנייד שלך, אשר עשוי להיות כרוך בחיוב מצד ספק השירות הנייד שלך, בהתאם לתוכנית הנתונים הרלוונטית.\n\nגע ב-<xliff:g id="QUEUE_TEXT">%2$s</xliff:g> כדי להתחיל בהורדה בפעם הבאה שתתחבר לרשת Wi-Fi."</string>
- <string name="button_queue_for_wifi" msgid="422576726189179221">"תור"</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"‏הפעלת הורדה זו (<xliff:g id="SIZE">%1$s </xliff:g>) עשויה לקצר את חיי הסוללה ו/או לגרום לניצול מופרז של חבילת הגלישה, שהשימוש בה עשוי להיות כרוך בתשלום לספק השירות לנייד.\n\nאפשר לגעת ב-<xliff:g id="QUEUE_TEXT">%2$s</xliff:g> כדי להפעיל את ההורדה הזו בפעם הבאה שהמכשיר יהיה מחובר לרשת Wi-Fi."</string>
+ <string name="button_queue_for_wifi" msgid="422576726189179221">"הוספה לתור"</string>
<string name="button_cancel_download" msgid="2430166148737975604">"ביטול"</string>
- <string name="button_start_now" msgid="792123674007840864">"התחל כעת"</string>
+ <string name="button_start_now" msgid="792123674007840864">"אפשר להתחיל"</string>
<plurals name="notif_summary_active" formatted="false" msgid="7290448463204837173">
<item quantity="two">מתבצעת הורדה של <xliff:g id="NUMBER">%d</xliff:g> קבצים</item>
<item quantity="many">מתבצעת הורדה של <xliff:g id="NUMBER">%d</xliff:g> קבצים</item>
@@ -58,7 +58,7 @@
<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="4305080769167320204">"מתבצע, <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="download_running" msgid="3925050393361158266">"ההורדה מתבצעת"</string>
+ <string name="download_error" msgid="5144180777324573236">"ההורדה נכשלה"</string>
+ <string name="download_running_percent" msgid="4305080769167320204">"ההורדה מתבצעת, <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index efa9ed24..97ae7e6a 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -16,18 +16,18 @@
<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="app_label" msgid="3658948994665187911">"ダウンロード マネージャー"</string>
<string name="storage_description" msgid="7982444311558023664">"ダウンロード"</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_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_downloadCacheNonPurgeable" msgid="3069534308882047412">"ダウンロードキャッシュの領域を予約"</string>
- <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"ダウンロードマネージャーで領域が不足しているときに、自動的に削除できないダウンロードキャッシュへのファイルのダウンロードをアプリに許可します。"</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/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 37d2d5b2..81c376ed 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -38,7 +38,7 @@
<string name="wifi_required_title" msgid="1995971416871498179">"ჩამოტვირთვა ოპერატორის ქსელისთვის ძალიან დიდია"</string>
<string name="wifi_required_body" msgid="3067694630143784449">"ამ <xliff:g id="SIZE">%1$s </xliff:g> ჩამოტვირთვის განსახორციელებლად უნდა გამოიყენოთ WiFi. \n\nშეეხეთ <xliff:g id="QUEUE_TEXT">%2$s </xliff:g>, რათა დაიწყოთ ეს ჩამოტვირთვა მომავალში, როგორც კი ჩაერთვებით WiFi ქსელში."</string>
<string name="wifi_recommended_title" msgid="7441589306734687400">"ჩააყენებთ ჩამოტვირთვების რიგში?"</string>
- <string name="wifi_recommended_body" msgid="1314735166699936073">"ამ <xliff:g id="SIZE">%1$s </xliff:g> ჩამოტვირთვის დაწყება ახლა შეამცირებს თქვენი ელემენტის სიცოცხლეს და/ან გამოიწვევს თქვენი მობილური ინტერნეტის ინტენსიურ გამოყენებას. ეს თავისთავად განაპირობებს თქვენი მობილური ოპერატორისთვის შესაბამისი საფასურის გადახდას თქვენი ინტერნეტ გეგმიდან გამომდინარე. \n\n შეეხეთ <xliff:g id="QUEUE_TEXT">%2$s</xliff:g>, რათა დაიწყოთ ეს ჩამოტვირთვა მომავალში, როგორც კი ჩაერთვებით WiFi ქსელში."</string>
+ <string name="wifi_recommended_body" msgid="1314735166699936073">"ამ <xliff:g id="SIZE">%1$s </xliff:g> ჩამოტვირთვის დაწყება ახლა შეამცირებს თქვენი ბატარეის სიცოცხლეს და/ან გამოიწვევს თქვენი მობილური ინტერნეტის ინტენსიურ გამოყენებას. ეს თავისთავად განაპირობებს თქვენი მობილური ოპერატორისთვის შესაბამისი საფასურის გადახდას თქვენი ინტერნეტ გეგმიდან გამომდინარე. \n\n შეეხეთ <xliff:g id="QUEUE_TEXT">%2$s</xliff:g>, რათა დაიწყოთ ეს ჩამოტვირთვა მომავალში, როგორც კი ჩაერთვებით WiFi ქსელში."</string>
<string name="button_queue_for_wifi" msgid="422576726189179221">"რიგი"</string>
<string name="button_cancel_download" msgid="2430166148737975604">"გაუქმება"</string>
<string name="button_start_now" msgid="792123674007840864">"დაწყება ახლავე"</string>
diff --git a/src/com/android/providers/downloads/Constants.java b/src/com/android/providers/downloads/Constants.java
index 79daeaed..c822c7c6 100644
--- a/src/com/android/providers/downloads/Constants.java
+++ b/src/com/android/providers/downloads/Constants.java
@@ -83,6 +83,17 @@ public class Constants {
/** The default user agent used for downloads */
public static final String DEFAULT_USER_AGENT;
+ /**
+ * Job id for the periodic service to clean-up stale and orphan downloads.
+ */
+ public static final int IDLE_JOB_ID = -100;
+
+ /**
+ * Job id for a one-time clean-up job to trigger mediascan on files which should have been
+ * mediascanned earlier when they were downloaded but didn't get scanned.
+ */
+ public static final int MEDIA_SCAN_TRIGGER_JOB_ID = -101;
+
static {
final StringBuilder builder = new StringBuilder();
diff --git a/src/com/android/providers/downloads/DownloadIdleService.java b/src/com/android/providers/downloads/DownloadIdleService.java
index ecebb0f8..2a689548 100644
--- a/src/com/android/providers/downloads/DownloadIdleService.java
+++ b/src/com/android/providers/downloads/DownloadIdleService.java
@@ -16,6 +16,7 @@
package com.android.providers.downloads;
+import static com.android.providers.downloads.Constants.IDLE_JOB_ID;
import static com.android.providers.downloads.Constants.TAG;
import static com.android.providers.downloads.StorageUtils.listFilesRecursive;
@@ -53,7 +54,6 @@ import java.util.HashSet;
* deleted directly on disk.
*/
public class DownloadIdleService extends JobService {
- private static final int IDLE_JOB_ID = -100;
private class IdleRunnable implements Runnable {
private JobParameters mParams;
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
index c68d702a..d61ed843 100644
--- a/src/com/android/providers/downloads/DownloadProvider.java
+++ b/src/com/android/providers/downloads/DownloadProvider.java
@@ -31,6 +31,9 @@ import static android.provider.Downloads.Impl.MEDIA_SCANNED;
import static android.provider.Downloads.Impl.PERMISSION_ACCESS_ALL;
import static android.provider.Downloads.Impl._DATA;
+import static com.android.providers.downloads.Helpers.convertToMediaStoreDownloadsUri;
+import static com.android.providers.downloads.Helpers.triggerMediaScan;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
@@ -104,7 +107,7 @@ public final class DownloadProvider extends ContentProvider {
/** Database filename */
private static final String DB_NAME = "downloads.db";
/** Current database version */
- private static final int DB_VERSION = 113;
+ private static final int DB_VERSION = 114;
/** Name of table in the database */
private static final String DB_TABLE = "downloads";
/** Memory optimization - close idle connections after 30s of inactivity */
@@ -398,6 +401,11 @@ public final class DownloadProvider extends ContentProvider {
canonicalizeDataPaths(db);
break;
+ case 114:
+ nullifyMediaStoreUris(db);
+ MediaScanTriggerJob.schedule(getContext());
+ break;
+
default:
throw new IllegalStateException("Don't know how to upgrade to " + version);
}
@@ -538,6 +546,24 @@ public final class DownloadProvider extends ContentProvider {
}
/**
+ * Set mediastore uri column to null before the clean-up job and fill it again while
+ * running the job so that if the clean-up job gets preempted, we could use it
+ * as a way to know the entries which are already handled when the job gets restarted.
+ */
+ private void nullifyMediaStoreUris(SQLiteDatabase db) {
+ final String whereClause = Downloads.Impl._DATA + " IS NOT NULL"
+ + " AND (" + COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI + "=1"
+ + " OR " + COLUMN_MEDIA_SCANNED + "=" + MEDIA_SCANNED + ")"
+ + " AND (" + COLUMN_DESTINATION + "=" + Downloads.Impl.DESTINATION_EXTERNAL
+ + " OR " + COLUMN_DESTINATION + "=" + DESTINATION_FILE_URI
+ + " OR " + COLUMN_DESTINATION + "=" + DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD
+ + ")";
+ final ContentValues values = new ContentValues();
+ values.putNull(COLUMN_MEDIASTORE_URI);
+ db.update(DB_TABLE, values, whereClause, null);
+ }
+
+ /**
* Add a column to a table using ALTER TABLE.
* @param dbTable name of the table
* @param columnName name of the column to add
@@ -898,19 +924,28 @@ public final class DownloadProvider extends ContentProvider {
if (shouldBeVisibleToUser && filteredValues.getAsInteger(COLUMN_DESTINATION)
== DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) {
final CallingIdentity token = clearCallingIdentity();
- try (ContentProviderClient client = getContext().getContentResolver()
- .acquireContentProviderClient(MediaStore.AUTHORITY)) {
- final Uri mediaStoreUri = updateMediaProvider(client,
- convertToMediaProviderValues(filteredValues));
+ try {
+ final Uri mediaStoreUri = MediaStore.scanFile(getContext(),
+ new File(filteredValues.getAsString(Downloads.Impl._DATA)));
if (mediaStoreUri != null) {
+ final ContentValues mediaValues = new ContentValues();
+ mediaValues.put(MediaStore.Downloads.DOWNLOAD_URI,
+ filteredValues.getAsString(Downloads.Impl.COLUMN_URI));
+ mediaValues.put(MediaStore.Downloads.REFERER_URI,
+ filteredValues.getAsString(Downloads.Impl.COLUMN_REFERER));
+ mediaValues.put(MediaStore.Downloads.OWNER_PACKAGE_NAME,
+ Helpers.getPackageForUid(getContext(),
+ filteredValues.getAsInteger(Constants.UID)));
+ getContext().getContentResolver().update(
+ convertToMediaStoreDownloadsUri(mediaStoreUri),
+ mediaValues, null, null);
+
filteredValues.put(Downloads.Impl.COLUMN_MEDIASTORE_URI,
mediaStoreUri.toString());
filteredValues.put(Downloads.Impl.COLUMN_MEDIAPROVIDER_URI,
mediaStoreUri.toString());
filteredValues.put(COLUMN_MEDIA_SCANNED, MEDIA_SCANNED);
}
- MediaStore.scanFile(getContext(),
- new File(filteredValues.getAsString(Downloads.Impl._DATA)));
} finally {
restoreCallingIdentity(token);
}
@@ -1006,48 +1041,21 @@ public final class DownloadProvider extends ContentProvider {
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
+ final boolean downloadCompleted = Downloads.Impl.isStatusCompleted(info.mStatus);
final ContentValues mediaValues = new ContentValues();
mediaValues.put(MediaStore.Downloads.DATA, filePath);
- mediaValues.put(MediaStore.Downloads.SIZE, info.mTotalBytes);
+ mediaValues.put(MediaStore.Downloads.SIZE,
+ downloadCompleted ? info.mTotalBytes : info.mCurrentBytes);
mediaValues.put(MediaStore.Downloads.DOWNLOAD_URI, info.mUri);
mediaValues.put(MediaStore.Downloads.REFERER_URI, info.mReferer);
mediaValues.put(MediaStore.Downloads.MIME_TYPE, info.mMimeType);
- mediaValues.put(MediaStore.Downloads.IS_PENDING,
- Downloads.Impl.isStatusSuccess(info.mStatus) ? 0 : 1);
+ mediaValues.put(MediaStore.Downloads.IS_PENDING, downloadCompleted ? 0 : 1);
mediaValues.put(MediaStore.Downloads.OWNER_PACKAGE_NAME,
Helpers.getPackageForUid(getContext(), info.mUid));
mediaValues.put(MediaStore.Files.FileColumns.IS_DOWNLOAD, info.mIsVisibleInDownloadsUi);
return mediaValues;
}
- private ContentValues convertToMediaProviderValues(ContentValues downloadValues) {
- final String filePath;
- try {
- filePath = new File(downloadValues.getAsString(Downloads.Impl._DATA))
- .getCanonicalPath();
- } catch (IOException e) {
- throw new IllegalArgumentException(e);
- }
- final ContentValues mediaValues = new ContentValues();
- mediaValues.put(MediaStore.Downloads.DATA, filePath);
- mediaValues.put(MediaStore.Downloads.SIZE,
- downloadValues.getAsLong(Downloads.Impl.COLUMN_TOTAL_BYTES));
- mediaValues.put(MediaStore.Downloads.DOWNLOAD_URI,
- downloadValues.getAsString(Downloads.Impl.COLUMN_URI));
- mediaValues.put(MediaStore.Downloads.REFERER_URI,
- downloadValues.getAsString(Downloads.Impl.COLUMN_REFERER));
- mediaValues.put(MediaStore.Downloads.MIME_TYPE,
- downloadValues.getAsString(Downloads.Impl.COLUMN_MIME_TYPE));
- final boolean isPending = downloadValues.getAsInteger(Downloads.Impl.COLUMN_STATUS)
- != Downloads.Impl.STATUS_SUCCESS;
- mediaValues.put(MediaStore.Downloads.IS_PENDING, isPending ? 1 : 0);
- mediaValues.put(MediaStore.Downloads.OWNER_PACKAGE_NAME,
- Helpers.getPackageForUid(getContext(), downloadValues.getAsInteger(Constants.UID)));
- mediaValues.put(MediaStore.Files.FileColumns.IS_DOWNLOAD,
- downloadValues.getAsBoolean(COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI));
- return mediaValues;
- }
-
private static Uri getFileUri(String uriString) {
final Uri uri = Uri.parse(uriString);
return TextUtils.equals(uri.getScheme(), ContentResolver.SCHEME_FILE) ? uri : null;
@@ -1555,8 +1563,16 @@ public final class DownloadProvider extends ContentProvider {
|| info.mDestination == Downloads.Impl
.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD)
&& visibleToUser) {
- final Uri mediaStoreUri = updateMediaProvider(client,
- convertToMediaProviderValues(info));
+ final ContentValues mediaValues = convertToMediaProviderValues(info);
+ final Uri mediaStoreUri;
+ if (Downloads.Impl.isStatusCompleted(info.mStatus)) {
+ // Set size to 0 to ensure MediaScanner will scan this file.
+ mediaValues.put(MediaStore.Downloads.SIZE, 0);
+ updateMediaProvider(client, mediaValues);
+ mediaStoreUri = triggerMediaScan(client, new File(info.mFileName));
+ } else {
+ mediaStoreUri = updateMediaProvider(client, mediaValues);
+ }
if (!TextUtils.equals(info.mMediaStoreUri,
mediaStoreUri == null ? null : mediaStoreUri.toString())) {
updateValues.clear();
@@ -1574,9 +1590,6 @@ public final class DownloadProvider extends ContentProvider {
qb.update(db, updateValues, Downloads.Impl._ID + "=?",
new String[] { Long.toString(info.mId) });
}
- if (Downloads.Impl.isStatusSuccess(info.mStatus)) {
- MediaStore.scanFile(getContext(), new File(info.mFileName));
- }
}
if (updateSchedule) {
Helpers.scheduleJob(context, info);
diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java
index 226fb481..57cdf04a 100644
--- a/src/com/android/providers/downloads/Helpers.java
+++ b/src/com/android/providers/downloads/Helpers.java
@@ -34,18 +34,22 @@ import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.provider.Downloads;
+import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.util.LongSparseArray;
@@ -490,6 +494,26 @@ public class Helpers {
throw new IOException("Failed to generate an available filename");
}
+ public static Uri convertToMediaStoreDownloadsUri(Uri mediaStoreUri) {
+ final String volumeName = MediaStore.getVolumeName(mediaStoreUri);
+ final long id = android.content.ContentUris.parseId(mediaStoreUri);
+ return MediaStore.Downloads.getContentUri(volumeName, id);
+ }
+
+ // TODO: Move it to MediaStore.
+ public static Uri triggerMediaScan(android.content.ContentProviderClient mediaProviderClient,
+ File file) {
+ try {
+ final Bundle in = new Bundle();
+ in.putParcelable(Intent.EXTRA_STREAM, Uri.fromFile(file));
+ final Bundle out = mediaProviderClient.call(MediaStore.SCAN_FILE_CALL, null, in);
+ return out.getParcelable(Intent.EXTRA_STREAM);
+ } catch (RemoteException e) {
+ // Should not happen
+ }
+ return null;
+ }
+
public static boolean isFileInExternalAndroidDirs(String filePath) {
return PATTERN_ANDROID_DIRS.matcher(filePath).matches();
}
diff --git a/src/com/android/providers/downloads/MediaScanTriggerJob.java b/src/com/android/providers/downloads/MediaScanTriggerJob.java
new file mode 100644
index 00000000..8da25258
--- /dev/null
+++ b/src/com/android/providers/downloads/MediaScanTriggerJob.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.providers.downloads;
+
+import static android.provider.BaseColumns._ID;
+import static android.provider.Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI;
+import static android.provider.Downloads.Impl.COLUMN_DESTINATION;
+import static android.provider.Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI;
+import static android.provider.Downloads.Impl.COLUMN_MEDIASTORE_URI;
+import static android.provider.Downloads.Impl.COLUMN_MEDIA_SCANNED;
+import static android.provider.Downloads.Impl.DESTINATION_EXTERNAL;
+import static android.provider.Downloads.Impl.DESTINATION_FILE_URI;
+import static android.provider.Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD;
+import static android.provider.Downloads.Impl.MEDIA_SCANNED;
+import static android.provider.Downloads.Impl._DATA;
+
+import static com.android.providers.downloads.Constants.MEDIA_SCAN_TRIGGER_JOB_ID;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.ContentProviderClient;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.provider.Downloads;
+import android.provider.MediaStore;
+
+import java.io.File;
+
+/**
+ * Clean-up job to force mediascan on downloads which should have been but didn't get mediascanned.
+ */
+public class MediaScanTriggerJob extends JobService {
+ private volatile boolean mJobStopped;
+
+ @Override
+ public boolean onStartJob(JobParameters parameters) {
+ Helpers.getAsyncHandler().post(() -> {
+ final String selection = _DATA + " IS NOT NULL"
+ + " AND (" + COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI + "=1"
+ + " OR " + COLUMN_MEDIA_SCANNED + "=" + MEDIA_SCANNED + ")"
+ + " AND (" + COLUMN_DESTINATION + "=" + DESTINATION_EXTERNAL
+ + " OR " + COLUMN_DESTINATION + "=" + DESTINATION_FILE_URI
+ + " OR " + COLUMN_DESTINATION + "=" + DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD
+ + ")";
+ try (ContentProviderClient downloadProviderClient
+ = getContentResolver().acquireContentProviderClient(Downloads.Impl.AUTHORITY);
+ ContentProviderClient mediaProviderClient
+ = getContentResolver().acquireContentProviderClient(MediaStore.AUTHORITY)) {
+ try (Cursor cursor = downloadProviderClient.query(ALL_DOWNLOADS_CONTENT_URI,
+ new String[] {_ID, _DATA, COLUMN_MEDIASTORE_URI},
+ selection, null, null)) {
+ while (cursor.moveToNext()) {
+ if (mJobStopped) {
+ return;
+ }
+ // This indicates that this entry has been handled already (perhaps when
+ // this job ran earlier and got preempted), so skip.
+ if (cursor.getString(2) != null) {
+ continue;
+ }
+ final long id = cursor.getLong(0);
+ final String filePath = cursor.getString(1);
+ final ContentValues mediaValues = new ContentValues();
+ mediaValues.put(MediaStore.Files.FileColumns.SIZE, 0);
+ mediaProviderClient.update(MediaStore.Files.getContentUriForPath(filePath),
+ mediaValues,
+ MediaStore.Files.FileColumns.DATA + "=?",
+ new String[] { filePath });
+
+ final Uri mediaStoreUri = Helpers.triggerMediaScan(mediaProviderClient,
+ new File(filePath));
+ if (mediaStoreUri != null) {
+ final ContentValues downloadValues = new ContentValues();
+ downloadValues.put(COLUMN_MEDIASTORE_URI, mediaStoreUri.toString());
+ downloadProviderClient.update(ALL_DOWNLOADS_CONTENT_URI,
+ downloadValues, _ID + "=" + id, null);
+ }
+ }
+ } catch (RemoteException e) {
+ // Should not happen
+ }
+ }
+ jobFinished(parameters, false);
+ });
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters parameters) {
+ mJobStopped = true;
+ return true;
+ }
+
+ public static void schedule(Context context) {
+ final JobScheduler scheduler = context.getSystemService(JobScheduler.class);
+ final JobInfo job = new JobInfo.Builder(MEDIA_SCAN_TRIGGER_JOB_ID,
+ new ComponentName(context, MediaScanTriggerJob.class))
+ .setRequiresCharging(true)
+ .setRequiresDeviceIdle(true)
+ .build();
+ scheduler.schedule(job);
+ }
+}
diff --git a/ui/res/values-hy/strings.xml b/ui/res/values-hy/strings.xml
index b9619420..56fcf366 100644
--- a/ui/res/values-hy/strings.xml
+++ b/ui/res/values-hy/strings.xml
@@ -44,7 +44,7 @@
<string name="cancel_running_download" msgid="5232704030969221112">"Չեղարկել"</string>
<string name="retry_download" msgid="7617100787922717912">"Կրկնել"</string>
<string name="start_now_download" msgid="1564642872809509681">"Սկսել հիմա"</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="NUMBER">%1$d</xliff:g>-ը <xliff:g id="TOTAL">%2$d</xliff:g>-ից"</string>
<string name="download_share_dialog" msgid="3355867339806448955">"Կիսվել"</string>
diff --git a/ui/res/values-iw/strings.xml b/ui/res/values-iw/strings.xml
index d58ee688..58e2783a 100644
--- a/ui/res/values-iw/strings.xml
+++ b/ui/res/values-iw/strings.xml
@@ -17,35 +17,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">"הורדות"</string>
- <string name="download_title_sorted_by_date" msgid="5898014492155434221">"הורדות - ממוינות לפי תאריך"</string>
- <string name="download_title_sorted_by_size" msgid="1417193166677094813">"הורדות - ממוינות לפי גודל"</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_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="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_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="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="start_now_download" msgid="1564642872809509681">"התחל כעת"</string>
- <string name="deselect_all" msgid="6348198946254776764">"בטל בחירה של הכל"</string>
- <string name="select_all" msgid="634074918366265804">"בחר הכל"</string>
+ <string name="retry_download" msgid="7617100787922717912">"ניסיון חוזר"</string>
+ <string name="start_now_download" msgid="1564642872809509681">"אפשר להתחיל"</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>
+ <string name="download_share_dialog" msgid="3355867339806448955">"שיתוף באמצעות"</string>
</resources>