From 579be0d0d0de6af307ee94af07720a568ed2e7d1 Mon Sep 17 00:00:00 2001 From: Hideki Hayami Date: Tue, 14 Feb 2012 14:19:52 +0900 Subject: avoid repetition of retrying download If isReadyToStart returns 'true' for STATUS_INSUFFICIENT_SPACE_ERROR, DownloadProvider retries downloading after it gets requests from browser to download contents. The retrying loop won't stop until its completion (recovering from space error), or user stops downloading. This retry loop impacts to network traffic, battery consumption and packet charge. So, change this method to return 'false' for the error in order to stop the loop. Change-Id: Ia3466db60d86c5900842c7c28d294898ae3ff2bc --- src/com/android/providers/downloads/DownloadInfo.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/com/android/providers/downloads/DownloadInfo.java b/src/com/android/providers/downloads/DownloadInfo.java index 00b10452..47b7bc5a 100644 --- a/src/com/android/providers/downloads/DownloadInfo.java +++ b/src/com/android/providers/downloads/DownloadInfo.java @@ -312,11 +312,8 @@ public class DownloadInfo { // is the media mounted? return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); case Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR: - // should check space to make sure it is worth retrying the download. - // but thats the first thing done by the thread when it retries to download - // it will fail pretty quickly if there is no space. - // so, it is not that bad to skip checking space availability here. - return true; + // avoids repetition of retrying download + return false; } return false; } -- cgit v1.2.3 From 4d4e156805880676b27b80117011a7d350d504e2 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Mon, 30 Apr 2012 11:22:29 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I9ac17052609031b73a0711e20a34613acf15a4de --- res/values-in/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index 29cd3f29..75dad7f1 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -26,8 +26,8 @@ "Lihat semua unduhan pada penyimpanan USB" "Melihat semua unduhan pada kartu SD" "Mengizinkan apl melihat semua unduhan ke kartu SD, terlepas apl apa yang mengunduhnya." - "Ruang penyimpanan dalam tembolok unduhan" - "Mengizinkan apl mengunduh file ke tembolok unduhan yang tidak dapat dihapus secara otomatis saat pengelola unduhan memerlukan lebih banyak ruang." + "Ruang penyimpanan dalam cache unduhan" + "Mengizinkan apl mengunduh file ke cache unduhan yang tidak dapat dihapus secara otomatis saat pengelola unduhan memerlukan lebih banyak ruang." "unduh file tanpa pemberitahuan" "Mengizinkan apl mengunduh file melalui pengelola unduhan tanpa menampilkan pemberitahuan apa pun kepada pengguna." "Akses semua unduhan sistem" -- cgit v1.2.3 From 4f4cac5304ffa6b6f717e4c988b0a5947fcd81bc Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Fri, 25 May 2012 11:59:05 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I952cc9c502b2896d4ec4e17fb184f93ad97ae1b4 --- res/values-zh-rCN/strings.xml | 2 +- ui/res/values-zh-rCN/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 2197fe79..40681fcc 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -16,7 +16,7 @@ - "下载管理器" + "下载管理程序" "访问下载管理器。" "允许该应用使用下载管理器并通过它下载文件。恶意应用可能会借此中断下载并访问私人信息。" "高级下载管理器功能。" diff --git a/ui/res/values-zh-rCN/strings.xml b/ui/res/values-zh-rCN/strings.xml index d876d02d..ae003361 100644 --- a/ui/res/values-zh-rCN/strings.xml +++ b/ui/res/values-zh-rCN/strings.xml @@ -16,7 +16,7 @@ - "下载内容" + "下载" "下载内容 - 按日期排序" "下载内容 - 按大小排序" "无下载内容。" -- cgit v1.2.3 From 899045aa19154cc1ea153345ef60d9abf94bb2b5 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Thu, 7 Jun 2012 13:16:23 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I9e117db77c61afa73e9d2bdaeb6080270ac4ca4c --- res/values-ru/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 58ea71e5..af380780 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -28,7 +28,7 @@ "Приложение получит доступ ко всем загрузкам на SD-карте независимо от того, через какое ПО они были загружены." "Резервировать место в кэше загрузки" "Приложение сможет загружать файлы в кэш загрузки (который не может быть автоматически очищен), если менеджеру загрузки потребуется больше места." - "загружать файлы без оповещения" + "Загрузка файлов без оповещения" "Приложение сможет загружать файлы через диспетчер загрузок без уведомления пользователя." "Доступ ко всем загрузкам" "Приложение сможет открывать и изменять загрузки независимо от того, через какое ПО они были загружены." -- cgit v1.2.3 From b78813f1095f724d50a1c2fea22e24a573a0d906 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Mon, 18 Jun 2012 11:05:40 -0700 Subject: Import translations. DO NOT MERGE Change-Id: Ia9138f7b8611650a3dfab998de558c1b53b0f27b --- res/values-tr/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index ece86bd4..66cb2ab3 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -23,7 +23,7 @@ "Uygulamaya, indirme yöneticisinin gelişmiş fonksiyonlarına erişme izni verir. Zararlı uygulamalar indirme işlemlerini kesmek ve özel bilgilere erişmek için bunu kullanabilir." "İndirme bildirimleri gönder." "Uygulamaya, tamamlanan indirme işlemleriyle ilgili bildirim gönderme izni verir. Zararlı uygulamalar dosya indiren diğer uygulamaların çalışma biçimini etkilemek için bunu kullanabilir." - "USB dp brmne yapln tüm indr göst" + "USB belleğe yapln tüm indr göster" "SD karta yapılan tüm indirmeleri gör" "Uygulamaya, indiren uygulamadan bağımsız olarak, SD karta yapılan tüm indirme işlemlerini görme izni verir." "İndirme önbelleğinde alan ayır" -- cgit v1.2.3 From a6af804b960996dd8a42452e26c56d63974f173c Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Tue, 3 Jul 2012 14:36:02 -0700 Subject: No echo or earcon after checking/unchecking items in the download screen. 1. The problem is that download provider is using a custom view to intercept clicks to toggle the state of the nested check box. However, the when toggling the code is not calling performClick() on the check box which aside of toggling will also send the right accessibility event. bug:6705105 Change-Id: Ia7253ff05f6e4575a346b9aaf3fbceecd68b9782 --- ui/src/com/android/providers/downloads/ui/DownloadItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/com/android/providers/downloads/ui/DownloadItem.java b/ui/src/com/android/providers/downloads/ui/DownloadItem.java index 25f58638..fc78ca49 100644 --- a/ui/src/com/android/providers/downloads/ui/DownloadItem.java +++ b/ui/src/com/android/providers/downloads/ui/DownloadItem.java @@ -130,7 +130,7 @@ public class DownloadItem extends GridLayout implements Checkable { @Override public void toggle() { - setChecked(!isChecked()); + mCheckBox.performClick(); } public CheckBox getCheckBox() { -- cgit v1.2.3 From 61dc320aa883a2fcf68d44ef0bbe4cd7c51a7655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kan3=20Johansson?= Date: Wed, 8 Feb 2012 21:07:27 +0100 Subject: Adds missing Bluetooth as network type. The network connection type for Bluetooth is added so that it is possible to use Bluetooth as Hotspot during download from the Internet. Change-Id: Ic32b083068d8316a41f2c31a3575a28163f6c7f3 --- src/com/android/providers/downloads/DownloadInfo.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/android/providers/downloads/DownloadInfo.java b/src/com/android/providers/downloads/DownloadInfo.java index 9ce58cd8..e452e5bf 100644 --- a/src/com/android/providers/downloads/DownloadInfo.java +++ b/src/com/android/providers/downloads/DownloadInfo.java @@ -422,6 +422,9 @@ public class DownloadInfo { case ConnectivityManager.TYPE_WIFI: return DownloadManager.Request.NETWORK_WIFI; + case ConnectivityManager.TYPE_BLUETOOTH: + return DownloadManager.Request.NETWORK_BLUETOOTH; + default: return 0; } -- cgit v1.2.3 From 2b4a51b5f4cb82cc3ed8a63526ff5e98951b0e48 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Fri, 13 Jul 2012 11:04:09 -0700 Subject: Import translations. DO NOT MERGE Change-Id: Icb03811c70a091981b748e50004b2db597c68280 Auto-generated-cl: translation import --- res/values-fa/strings.xml | 16 ++++++++-------- ui/res/values-fa/strings.xml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 82284299..37708a72 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -18,20 +18,20 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Download Manager" "دسترسی به Download Manager." - "به برنامه کاربردی اجازه میدهد تا به download manager دسترسی داشته باشد و از آن برای دانلود فایل‌ها استفاده کند. برنامه‌های مضر میتوانند از این امکان استفاده کرده و برای دانلودها مشکل ایجاد کنند و به اطلاعات خصوصی دسترسی داشته باشند." + "به برنامه کاربردی اجازه می‌دهد تا به download manager دسترسی داشته باشد و از آن برای دانلود فایل‌ها استفاده کند. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای دانلودها مشکل ایجاد کنند و به اطلاعات خصوصی دسترسی داشته باشند." "عملکرد Download Manager پیشرفته." - "به برنامه کاربردی اجازه میدهد تا به عملکردهای پیشرفته download manager دسترسی داشته باشد. برنامه‌های مضر میتوانند از این امکان استفاده کرده و برای دانلودها مشکل ایجاد کنند و به اطلاعات خصوصی دسترسی داشته باشند." + "به برنامه کاربردی اجازه می‌دهد تا به عملکردهای پیشرفته download manager دسترسی داشته باشد. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای دانلودها مشکل ایجاد کنند و به اطلاعات خصوصی دسترسی داشته باشند." "اعلان های دانلود ارسال شود." - "به برنامه کاربردی اجازه میدهد اعلان‌های مربوط به دانلودهای کامل شده را ارسال کند. برنامه‌های مضر میتوانند از این امکان استفاده کرده و برای سایر برنامه‌هایی که فایل‌ها را دانلود میکنند، مشکلاتی را ایجاد کنند." - "مشاهده همه دانلودها در حافظه USB" + "به برنامه کاربردی اجازه می‌دهد اعلان‌های مربوط به دانلودهای کامل شده را ارسال کند. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای سایر برنامه‌هایی که فایل‌ها را دانلود می‌کنند، مشکلاتی را ایجاد کنند." + "مشاهده همه دانلودها در حافظهٔ USB" "مشاهده همه دانلودها در کارت SD" - "به برنامه کاربردی اجازه میدهد بدون در نظر گرفتن اینکه کدام برنامه دانلود را انجام داده است، تمام دانلودهای موجود در کارت SD را مشاهده کند." + "به برنامه کاربردی اجازه می‌دهد بدون در نظر گرفتن اینکه کدام برنامه دانلود را انجام داده است، تمام دانلودهای موجود در کارت SD را مشاهده کند." "رزرو فضا در حافظه موقت دانلود" "به برنامه کاربردی اجازه می‌دهد فایل‌ها را در حافظه پنهان دانلود کند، تا هنگامی که Download Manager به فضای بیشتری احتیاج دارد، بطور خودکار حذف نشوند.+" "دانلود فایلها بدون اطلاع" - "به برنامه کاربردی اجازه میدهد فایل‌ها را از طریق Download Manager، بدون نمایش اعلان به کاربر دانلود کند." + "به برنامه کاربردی اجازه می‌دهد فایل‌ها را از طریق Download Manager، بدون نمایش اعلان به کاربر دانلود کند." "دسترسی به همه دانلودهای سیستم" - "به برنامه کاربردی اجازه میدهد تمام دانلودهای شروع شده توسط هر برنامه‌ای را در سیستم مشاهده کرده و تغییر دهد." + "به برنامه کاربردی اجازه می‌دهد تمام دانلودهای شروع شده توسط هر برنامه‌ای را در سیستم مشاهده کرده و تغییر دهد." "<بدون عنوان>" "، " " و %d بیشتر" @@ -42,7 +42,7 @@ "دانلود برای شبکه اپراتور بسیار بزرگ است" "برای تکمیل این دانلود %s باید از Wi-Fi استفاده کنید. در اتصال بعدی به شبکه Wi-Fi و برای شروع دانلود، "\n\n"لمس%s کنید." "برای دانلود در فرصتی دیگر در صف گذاشته شود؟" - "شروع دانلود %s سبب کم شدن طول عمر باتری و/یا استفاده بیش از حد از اتصال داده تلفن همراه میشود که بسته به قرارداد ارائه داده شما ممکن است از طرف اپراتور تلفن هزینه‌هایی برای شما در نظر گرفته شود. "\n\n"%s را لمس کنید تا در اتصال بعدی به شبکه Wi-Fi، این دانلود شروع شود." + "شروع دانلود %s سبب کم شدن طول عمر باتری و/یا استفاده بیش از حد از اتصال داده تلفن همراه می‌شود که بسته به قرارداد ارائه داده شما ممکن است از طرف اپراتور تلفن هزینه‌هایی برای شما در نظر گرفته شود. "\n\n"%s را لمس کنید تا در اتصال بعدی به شبکه Wi-Fi، این دانلود شروع شود." "صف" "لغو" "اکنون شروع" diff --git a/ui/res/values-fa/strings.xml b/ui/res/values-fa/strings.xml index 5668de9f..5117848f 100644 --- a/ui/res/values-fa/strings.xml +++ b/ui/res/values-fa/strings.xml @@ -28,12 +28,12 @@ "کامل" "ناموفق" "دانلود ممکن نیست." - "می خواهید بعداً دوباره برای دانلود فایل تلاش کنید یا آن را از صف خارج کنید؟" + "می‌خواهید بعداً دوباره برای دانلود فایل تلاش کنید یا آن را از صف خارج کنید؟" "فایل‌ در نوبت" "این فایل برای دانلود در آینده در نوبت قرار گرفته است، بنابراین هنوز در دسترس نیست." "نمی‌توانم فایل‌های دانلود شده را پیدا کنم." "نمی‌توان دانلود را به پایان رساند. فضای کافی در حافظه خارجی وجود ندارد." - "نمی‌توان دانلود را به پایان رساند. فضای کافی در حافظه داخلی دانلود وجود ندارد." + "نمی‌توان دانلود را به پایان رساند. فضای کافی در حافظهٔ داخلی دانلود وجود ندارد." "دانلود قطع شد و نمی‌توان آن را از سرگیری کرد." "دانلود نمی‌شود. فایل مقصد از قبل موجود است." "دانلود نمی‌شود. رسانه خارجی در دسترس نیست." -- cgit v1.2.3 From 690a81bdb145b74205f320328167b289a4129222 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Mon, 16 Jul 2012 10:42:46 -0700 Subject: Import translations. DO NOT MERGE Change-Id: Id1e521b41e4807247a99c2d4fac6b092799c4097 Auto-generated-cl: translation import --- res/values-fa/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 37708a72..9a58e073 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -21,14 +21,14 @@ "به برنامه کاربردی اجازه می‌دهد تا به download manager دسترسی داشته باشد و از آن برای دانلود فایل‌ها استفاده کند. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای دانلودها مشکل ایجاد کنند و به اطلاعات خصوصی دسترسی داشته باشند." "عملکرد Download Manager پیشرفته." "به برنامه کاربردی اجازه می‌دهد تا به عملکردهای پیشرفته download manager دسترسی داشته باشد. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای دانلودها مشکل ایجاد کنند و به اطلاعات خصوصی دسترسی داشته باشند." - "اعلان های دانلود ارسال شود." + "اعلان‌های دانلود ارسال شود." "به برنامه کاربردی اجازه می‌دهد اعلان‌های مربوط به دانلودهای کامل شده را ارسال کند. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای سایر برنامه‌هایی که فایل‌ها را دانلود می‌کنند، مشکلاتی را ایجاد کنند." "مشاهده همه دانلودها در حافظهٔ USB" "مشاهده همه دانلودها در کارت SD" "به برنامه کاربردی اجازه می‌دهد بدون در نظر گرفتن اینکه کدام برنامه دانلود را انجام داده است، تمام دانلودهای موجود در کارت SD را مشاهده کند." "رزرو فضا در حافظه موقت دانلود" "به برنامه کاربردی اجازه می‌دهد فایل‌ها را در حافظه پنهان دانلود کند، تا هنگامی که Download Manager به فضای بیشتری احتیاج دارد، بطور خودکار حذف نشوند.+" - "دانلود فایلها بدون اطلاع" + "دانلود فایل‌ها بدون اطلاع" "به برنامه کاربردی اجازه می‌دهد فایل‌ها را از طریق Download Manager، بدون نمایش اعلان به کاربر دانلود کند." "دسترسی به همه دانلودهای سیستم" "به برنامه کاربردی اجازه می‌دهد تمام دانلودهای شروع شده توسط هر برنامه‌ای را در سیستم مشاهده کرده و تغییر دهد." -- cgit v1.2.3 From 450e3aa05e4109ed0c75d1193d8601a960c692dd Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Wed, 18 Jul 2012 12:41:11 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I4fb5bdc4c7aff92e7d04cdfbd61d985539a25be4 Auto-generated-cl: translation import --- ui/res/values-fa/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/res/values-fa/strings.xml b/ui/res/values-fa/strings.xml index 5117848f..fd81dd26 100644 --- a/ui/res/values-fa/strings.xml +++ b/ui/res/values-fa/strings.xml @@ -46,5 +46,5 @@ "لغو انتخاب همه" "انتخاب همه" "%1$d مورد انتخاب شده از %2$d مورد" - "اشتراک گذاری از طریق" + "اشتراک‌گذاری از طریق" -- cgit v1.2.3 From d571f07eb75af17fa15049238cfeac2543098240 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Fri, 20 Jul 2012 11:11:31 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I50f7efa62f6cb011cc8cda96b572e0327481e275 Auto-generated-cl: translation import --- res/values-fa/strings.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 9a58e073..d8ccb116 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -18,20 +18,20 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Download Manager" "دسترسی به Download Manager." - "به برنامه کاربردی اجازه می‌دهد تا به download manager دسترسی داشته باشد و از آن برای دانلود فایل‌ها استفاده کند. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای دانلودها مشکل ایجاد کنند و به اطلاعات خصوصی دسترسی داشته باشند." + "به برنامهٔ کاربردی اجازه می‌دهد تا به download manager دسترسی داشته باشد و از آن برای دانلود فایل‌ها استفاده کند. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای دانلودها مشکل ایجاد کنند و به اطلاعات خصوصی دسترسی داشته باشند." "عملکرد Download Manager پیشرفته." - "به برنامه کاربردی اجازه می‌دهد تا به عملکردهای پیشرفته download manager دسترسی داشته باشد. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای دانلودها مشکل ایجاد کنند و به اطلاعات خصوصی دسترسی داشته باشند." + "به برنامهٔ کاربردی اجازه می‌دهد تا به عملکردهای پیشرفته download manager دسترسی داشته باشد. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای دانلودها مشکل ایجاد کنند و به اطلاعات خصوصی دسترسی داشته باشند." "اعلان‌های دانلود ارسال شود." - "به برنامه کاربردی اجازه می‌دهد اعلان‌های مربوط به دانلودهای کامل شده را ارسال کند. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای سایر برنامه‌هایی که فایل‌ها را دانلود می‌کنند، مشکلاتی را ایجاد کنند." - "مشاهده همه دانلودها در حافظهٔ USB" - "مشاهده همه دانلودها در کارت SD" - "به برنامه کاربردی اجازه می‌دهد بدون در نظر گرفتن اینکه کدام برنامه دانلود را انجام داده است، تمام دانلودهای موجود در کارت SD را مشاهده کند." + "به برنامهٔ کاربردی اجازه می‌دهد اعلان‌های مربوط به دانلودهای کامل شده را ارسال کند. برنامه‌های مضر می‌توانند از این امکان استفاده کرده و برای سایر برنامه‌هایی که فایل‌ها را دانلود می‌کنند، مشکلاتی را ایجاد کنند." + "مشاهدهٔ همه دانلودها در حافظهٔ USB" + "مشاهدهٔ همه دانلودها در کارت SD" + "به برنامهٔ کاربردی اجازه می‌دهد بدون در نظر گرفتن اینکه کدام برنامه دانلود را انجام داده است، تمام دانلودهای موجود در کارت SD را مشاهده کند." "رزرو فضا در حافظه موقت دانلود" - "به برنامه کاربردی اجازه می‌دهد فایل‌ها را در حافظه پنهان دانلود کند، تا هنگامی که Download Manager به فضای بیشتری احتیاج دارد، بطور خودکار حذف نشوند.+" + "به برنامهٔ کاربردی اجازه می‌دهد فایل‌ها را در حافظهٔ پنهان دانلود کند، تا هنگامی که Download Manager به فضای بیشتری احتیاج دارد، بطور خودکار حذف نشوند.+" "دانلود فایل‌ها بدون اطلاع" - "به برنامه کاربردی اجازه می‌دهد فایل‌ها را از طریق Download Manager، بدون نمایش اعلان به کاربر دانلود کند." + "به برنامهٔ کاربردی اجازه می‌دهد فایل‌ها را از طریق Download Manager، بدون نمایش اعلان به کاربر دانلود کند." "دسترسی به همه دانلودهای سیستم" - "به برنامه کاربردی اجازه می‌دهد تمام دانلودهای شروع شده توسط هر برنامه‌ای را در سیستم مشاهده کرده و تغییر دهد." + "به برنامهٔ کاربردی اجازه می‌دهد تمام دانلودهای شروع شده توسط هر برنامه‌ای را در سیستم مشاهده کرده و تغییر دهد." "<بدون عنوان>" "، " " و %d بیشتر" -- cgit v1.2.3 From ebcc93801eb9545004536587d10f82db378aeab5 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 20 Jul 2012 16:06:35 -0700 Subject: Reduce deletion logging. Bug: 6544953 Change-Id: I4157c67b9b9cddab4ade795c328a202f6a230f95 --- .../android/providers/downloads/DownloadService.java | 9 ++++++--- src/com/android/providers/downloads/DownloadThread.java | 17 +++++++++++------ src/com/android/providers/downloads/StorageManager.java | 11 ++++++----- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/com/android/providers/downloads/DownloadService.java b/src/com/android/providers/downloads/DownloadService.java index 3b566f8e..55efefcf 100644 --- a/src/com/android/providers/downloads/DownloadService.java +++ b/src/com/android/providers/downloads/DownloadService.java @@ -38,7 +38,6 @@ import android.os.RemoteException; import android.provider.Downloads; import android.text.TextUtils; import android.util.Log; -import android.util.Slog; import com.android.internal.util.IndentingPrintWriter; import com.google.android.collect.Maps; @@ -483,7 +482,9 @@ public class DownloadService extends Service { info.mStatus = Downloads.Impl.STATUS_CANCELED; } if (info.mDestination != Downloads.Impl.DESTINATION_EXTERNAL && info.mFileName != null) { - Slog.d(TAG, "deleteDownloadLocked() deleting " + info.mFileName); + if (Constants.LOGVV) { + Log.d(TAG, "deleteDownloadLocked() deleting " + info.mFileName); + } new File(info.mFileName).delete(); } mSystemFacade.cancelNotification(info.mId); @@ -559,7 +560,9 @@ public class DownloadService extends Service { private void deleteFileIfExists(String path) { try { if (!TextUtils.isEmpty(path)) { - Slog.d(TAG, "deleteFileIfExists() deleting " + path); + if (Constants.LOGVV) { + Log.d(TAG, "deleteFileIfExists() deleting " + path); + } File file = new File(path); file.delete(); } diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java index bd91eaa1..37db32b1 100644 --- a/src/com/android/providers/downloads/DownloadThread.java +++ b/src/com/android/providers/downloads/DownloadThread.java @@ -33,7 +33,6 @@ import android.provider.Downloads; import android.text.TextUtils; import android.util.Log; import android.util.Pair; -import android.util.Slog; import org.apache.http.Header; import org.apache.http.HttpResponse; @@ -330,7 +329,9 @@ public class DownloadThread extends Thread { closeDestination(state); if (state.mFilename != null && Downloads.Impl.isStatusError(finalStatus)) { - Slog.d(TAG, "cleanupDestination() deleting " + state.mFilename); + if (Constants.LOGVV) { + Log.d(TAG, "cleanupDestination() deleting " + state.mFilename); + } new File(state.mFilename).delete(); state.mFilename = null; } @@ -847,8 +848,10 @@ public class DownloadThread extends Thread { long fileLength = f.length(); if (fileLength == 0) { // The download hadn't actually started, we can restart from scratch - Slog.d(TAG, "setupDestinationFile() found fileLength=0, deleting " - + state.mFilename); + if (Constants.LOGVV) { + Log.d(TAG, "setupDestinationFile() found fileLength=0, deleting " + + state.mFilename); + } f.delete(); state.mFilename = null; if (Constants.LOGV) { @@ -857,8 +860,10 @@ public class DownloadThread extends Thread { } } else if (mInfo.mETag == null && !mInfo.mNoIntegrity) { // This should've been caught upon failure - Slog.d(TAG, "setupDestinationFile() unable to resume download, deleting " - + state.mFilename); + 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"); diff --git a/src/com/android/providers/downloads/StorageManager.java b/src/com/android/providers/downloads/StorageManager.java index 4b51921f..915d141b 100644 --- a/src/com/android/providers/downloads/StorageManager.java +++ b/src/com/android/providers/downloads/StorageManager.java @@ -30,7 +30,6 @@ import android.os.StatFs; import android.provider.Downloads; import android.text.TextUtils; import android.util.Log; -import android.util.Slog; import com.android.internal.R; @@ -342,9 +341,9 @@ class StorageManager { if (TextUtils.isEmpty(data)) continue; File file = new File(data); - if (true || Constants.LOGV) { - Slog.d(Constants.TAG, "purging " + file.getAbsolutePath() + " for " + - file.length() + " bytes"); + if (Constants.LOGV) { + Log.d(Constants.TAG, "purging " + file.getAbsolutePath() + " for " + + file.length() + " bytes"); } totalFreed += file.length(); file.delete(); @@ -416,7 +415,9 @@ class StorageManager { try { final StructStat stat = Libcore.os.stat(path); if (stat.st_uid == myUid) { - Slog.d(TAG, "deleting spurious file " + path); + if (Constants.LOGVV) { + Log.d(TAG, "deleting spurious file " + path); + } file.delete(); } } catch (ErrnoException e) { -- cgit v1.2.3 From 36612d27b67ff2e79ffff8eb12d95d2058abde02 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 24 Jul 2012 17:42:25 -0700 Subject: Move notification tests to LittleMock. Directly mock NotificationManager instead of using SystemFacade. Change-Id: If932d26e23816e8674469c275a828701cce5fc2d --- .../providers/downloads/DownloadNotification.java | 15 +++--- .../providers/downloads/DownloadReceiver.java | 5 +- .../providers/downloads/DownloadService.java | 10 ++-- .../providers/downloads/RealSystemFacade.java | 43 +++++++---------- .../android/providers/downloads/SystemFacade.java | 32 ++++++------- tests/Android.mk | 2 +- .../AbstractDownloadProviderFunctionalTest.java | 28 +++++------ .../providers/downloads/FakeSystemFacade.java | 29 ----------- .../downloads/PublicApiFunctionalTest.java | 56 +++++++++++++++++----- 9 files changed, 108 insertions(+), 112 deletions(-) diff --git a/src/com/android/providers/downloads/DownloadNotification.java b/src/com/android/providers/downloads/DownloadNotification.java index bbd39f60..f5778e79 100644 --- a/src/com/android/providers/downloads/DownloadNotification.java +++ b/src/com/android/providers/downloads/DownloadNotification.java @@ -17,6 +17,7 @@ package com.android.providers.downloads; import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ContentUris; import android.content.Context; @@ -38,9 +39,9 @@ import java.util.HashMap; */ class DownloadNotification { - Context mContext; - HashMap mNotifications; - private SystemFacade mSystemFacade; + private Context mContext; + private NotificationManager mNotifManager; + private HashMap mNotifications; /** Time when each {@link DownloadInfo#mId} was first shown. */ private SparseLongArray mFirstShown = new SparseLongArray(); @@ -102,7 +103,8 @@ class DownloadNotification { */ DownloadNotification(Context ctx, SystemFacade systemFacade) { mContext = ctx; - mSystemFacade = systemFacade; + mNotifManager = (NotificationManager) mContext.getSystemService( + Context.NOTIFICATION_SERVICE); mNotifications = new HashMap(); } @@ -207,8 +209,7 @@ class DownloadNotification { builder.setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent, 0)); - mSystemFacade.postNotification(item.mId, builder.getNotification()); - + mNotifManager.notify(item.mId, builder.build()); } } @@ -262,7 +263,7 @@ class DownloadNotification { intent.setData(contentUri); builder.setDeleteIntent(PendingIntent.getBroadcast(mContext, 0, intent, 0)); - mSystemFacade.postNotification(id, builder.getNotification()); + mNotifManager.notify((int) id, builder.build()); } private boolean isActiveAndVisible(DownloadInfo download) { diff --git a/src/com/android/providers/downloads/DownloadReceiver.java b/src/com/android/providers/downloads/DownloadReceiver.java index 26ad992e..81ff4040 100644 --- a/src/com/android/providers/downloads/DownloadReceiver.java +++ b/src/com/android/providers/downloads/DownloadReceiver.java @@ -17,6 +17,7 @@ package com.android.providers.downloads; import android.app.DownloadManager; +import android.app.NotificationManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentUris; @@ -120,7 +121,9 @@ public class DownloadReceiver extends BroadcastReceiver { * @param cursor Cursor for reading the download's fields */ private void hideNotification(Context context, Uri uri, Cursor cursor) { - mSystemFacade.cancelNotification(ContentUris.parseId(uri)); + final NotificationManager notifManager = (NotificationManager) context.getSystemService( + Context.NOTIFICATION_SERVICE); + notifManager.cancel((int) ContentUris.parseId(uri)); int statusColumn = cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS); int status = cursor.getInt(statusColumn); diff --git a/src/com/android/providers/downloads/DownloadService.java b/src/com/android/providers/downloads/DownloadService.java index 55efefcf..7030deae 100644 --- a/src/com/android/providers/downloads/DownloadService.java +++ b/src/com/android/providers/downloads/DownloadService.java @@ -19,6 +19,7 @@ package com.android.providers.downloads; import static com.android.providers.downloads.Constants.TAG; import android.app.AlarmManager; +import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.ComponentName; @@ -65,6 +66,7 @@ public class DownloadService extends Service { /** Class to handle Notification Manager updates */ private DownloadNotification mNotifier; + private NotificationManager mNotifManager; /** * The Service's view of the list of downloads, mapping download IDs to the corresponding info @@ -221,7 +223,9 @@ public class DownloadService extends Service { mMediaScannerConnection = new MediaScannerConnection(); mNotifier = new DownloadNotification(this, mSystemFacade); - mSystemFacade.cancelAllNotifications(); + mNotifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + mNotifManager.cancelAll(); + mStorageManager = StorageManager.getInstance(getApplicationContext()); updateFromProvider(); } @@ -464,7 +468,7 @@ public class DownloadService extends Service { !Downloads.Impl.isStatusCompleted(oldStatus) && Downloads.Impl.isStatusCompleted(info.mStatus); if (lostVisibility || justCompleted) { - mSystemFacade.cancelNotification(info.mId); + mNotifManager.cancel((int) info.mId); } info.startIfReady(now, mStorageManager); @@ -487,7 +491,7 @@ public class DownloadService extends Service { } new File(info.mFileName).delete(); } - mSystemFacade.cancelNotification(info.mId); + mNotifManager.cancel((int) info.mId); mDownloads.remove(info.mId); } diff --git a/src/com/android/providers/downloads/RealSystemFacade.java b/src/com/android/providers/downloads/RealSystemFacade.java index 6580f909..228c7165 100644 --- a/src/com/android/providers/downloads/RealSystemFacade.java +++ b/src/com/android/providers/downloads/RealSystemFacade.java @@ -1,26 +1,35 @@ +/* + * 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. + */ + package com.android.providers.downloads; import android.app.DownloadManager; -import android.app.Notification; -import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; import android.telephony.TelephonyManager; import android.util.Log; class RealSystemFacade implements SystemFacade { private Context mContext; - private NotificationManager mNotificationManager; public RealSystemFacade(Context context) { mContext = context; - mNotificationManager = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); } public long currentTimeMillis() { @@ -84,26 +93,6 @@ class RealSystemFacade implements SystemFacade { return mContext.getPackageManager().getApplicationInfo(packageName, 0).uid == uid; } - @Override - public void postNotification(long id, Notification notification) { - /** - * TODO: The system notification manager takes ints, not longs, as IDs, but the download - * manager uses IDs take straight from the database, which are longs. This will have to be - * dealt with at some point. - */ - mNotificationManager.notify((int) id, notification); - } - - @Override - public void cancelNotification(long id) { - mNotificationManager.cancel((int) id); - } - - @Override - public void cancelAllNotifications() { - mNotificationManager.cancelAll(); - } - @Override public void startThread(Thread thread) { thread.start(); diff --git a/src/com/android/providers/downloads/SystemFacade.java b/src/com/android/providers/downloads/SystemFacade.java index d1439354..fda97e08 100644 --- a/src/com/android/providers/downloads/SystemFacade.java +++ b/src/com/android/providers/downloads/SystemFacade.java @@ -1,12 +1,25 @@ +/* + * 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. + */ package com.android.providers.downloads; -import android.app.Notification; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.net.NetworkInfo; - interface SystemFacade { /** * @see System#currentTimeMillis() @@ -49,21 +62,6 @@ interface SystemFacade { */ public boolean userOwnsPackage(int uid, String pckg) throws NameNotFoundException; - /** - * Post a system notification to the NotificationManager. - */ - public void postNotification(long id, Notification notification); - - /** - * Cancel a system notification. - */ - public void cancelNotification(long id); - - /** - * Cancel all system notifications. - */ - public void cancelAllNotifications(); - /** * Start a thread. */ diff --git a/tests/Android.mk b/tests/Android.mk index aaf32ba4..ff3e1d47 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -8,7 +8,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_INSTRUMENTATION_FOR := DownloadProvider LOCAL_JAVA_LIBRARIES := android.test.runner -LOCAL_STATIC_JAVA_LIBRARIES := mockwebserver +LOCAL_STATIC_JAVA_LIBRARIES := mockwebserver littlemock dexmaker LOCAL_PACKAGE_NAME := DownloadProviderTests LOCAL_CERTIFICATE := media diff --git a/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java b/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java index 1912e84c..a65693fa 100644 --- a/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java +++ b/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java @@ -16,6 +16,9 @@ package com.android.providers.downloads; +import static com.google.testing.littlemock.LittleMock.mock; + +import android.app.NotificationManager; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -42,9 +45,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; public abstract class AbstractDownloadProviderFunctionalTest extends ServiceTestCase { @@ -94,19 +94,14 @@ public abstract class AbstractDownloadProviderFunctionalTest extends static class TestContext extends RenamingDelegatingContext { private static final String FILENAME_PREFIX = "test."; - private Context mRealContext; - private Set mAllowedSystemServices; private ContentResolver mResolver; + private final NotificationManager mNotifManager; boolean mHasServiceBeenStarted = false; public TestContext(Context realContext) { super(realContext, FILENAME_PREFIX); - mRealContext = realContext; - mAllowedSystemServices = new HashSet(Arrays.asList(new String[] { - Context.NOTIFICATION_SERVICE, - Context.POWER_SERVICE, - })); + mNotifManager = mock(NotificationManager.class); } public void setResolver(ContentResolver resolver) { @@ -118,7 +113,6 @@ public abstract class AbstractDownloadProviderFunctionalTest extends */ @Override public ContentResolver getContentResolver() { - assert mResolver != null; return mResolver; } @@ -127,9 +121,10 @@ public abstract class AbstractDownloadProviderFunctionalTest extends */ @Override public Object getSystemService(String name) { - if (mAllowedSystemServices.contains(name)) { - return mRealContext.getSystemService(name); + if (Context.NOTIFICATION_SERVICE.equals(name)) { + return mNotifManager; } + return super.getSystemService(name); } @@ -155,10 +150,13 @@ public abstract class AbstractDownloadProviderFunctionalTest extends protected void setUp() throws Exception { super.setUp(); - Context realContext = getContext(); + // Since we're testing a system app, AppDataDirGuesser doesn't find our + // cache dir, so set it explicitly. + System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); + + final Context realContext = getContext(); mTestContext = new TestContext(realContext); setupProviderAndResolver(); - mTestContext.setResolver(mResolver); setContext(mTestContext); setupService(); diff --git a/tests/src/com/android/providers/downloads/FakeSystemFacade.java b/tests/src/com/android/providers/downloads/FakeSystemFacade.java index c184de83..6898efdb 100644 --- a/tests/src/com/android/providers/downloads/FakeSystemFacade.java +++ b/tests/src/com/android/providers/downloads/FakeSystemFacade.java @@ -1,17 +1,13 @@ package com.android.providers.downloads; -import android.app.Notification; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.test.AssertionFailedError; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Queue; public class FakeSystemFacade implements SystemFacade { @@ -22,8 +18,6 @@ public class FakeSystemFacade implements SystemFacade { Long mMaxBytesOverMobile = null; Long mRecommendedMaxBytesOverMobile = null; List mBroadcastsSent = new ArrayList(); - Map mActiveNotifications = new HashMap(); - List mCanceledNotifications = new ArrayList(); Queue mStartedThreads = new LinkedList(); private boolean returnActualTime = false; @@ -73,29 +67,6 @@ public class FakeSystemFacade implements SystemFacade { return true; } - @Override - public void postNotification(long id, Notification notification) { - if (notification == null) { - throw new AssertionFailedError("Posting null notification"); - } - mActiveNotifications.put(id, notification); - } - - @Override - public void cancelNotification(long id) { - Notification notification = mActiveNotifications.remove(id); - if (notification != null) { - mCanceledNotifications.add(notification); - } - } - - @Override - public void cancelAllNotifications() { - for (long id : mActiveNotifications.keySet()) { - cancelNotification(id); - } - } - public boolean startThreadsWithoutWaiting = false; public void setStartThreadsWithoutWaiting(boolean flag) { this.startThreadsWithoutWaiting = flag; diff --git a/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java b/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java index 2f5282ae..34a69df9 100644 --- a/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java +++ b/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java @@ -16,7 +16,17 @@ package com.android.providers.downloads; +import static com.google.testing.littlemock.LittleMock.anyInt; +import static com.google.testing.littlemock.LittleMock.atLeastOnce; +import static com.google.testing.littlemock.LittleMock.isA; +import static com.google.testing.littlemock.LittleMock.never; +import static com.google.testing.littlemock.LittleMock.times; +import static com.google.testing.littlemock.LittleMock.verify; + import android.app.DownloadManager; +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.ConnectivityManager; @@ -24,7 +34,6 @@ import android.net.Uri; import android.os.Environment; import android.provider.Downloads; import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; import com.google.mockwebserver.MockResponse; import com.google.mockwebserver.RecordedRequest; @@ -37,12 +46,14 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.util.List; + @LargeTest public class PublicApiFunctionalTest extends AbstractPublicApiTest { private static final String REDIRECTED_PATH = "/other_path"; private static final String ETAG = "my_etag"; protected File mTestDirectory; + private NotificationManager mNotifManager; public PublicApiFunctionalTest() { super(new FakeSystemFacade()); @@ -52,6 +63,9 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest { protected void setUp() throws Exception { super.setUp(); + mNotifManager = (NotificationManager) getContext() + .getSystemService(Context.NOTIFICATION_SERVICE); + mTestDirectory = new File(Environment.getExternalStorageDirectory() + File.separator + "download_manager_functional_test"); if (mTestDirectory.exists()) { @@ -501,24 +515,42 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest { assertTrue(mResolver.mNotifyWasCalled); } - public void testNotifications() throws Exception { - enqueueResponse(buildEmptyResponse(HTTP_OK)); + public void testNotificationNever() throws Exception { enqueueResponse(buildEmptyResponse(HTTP_OK)); - Download download = enqueueRequest(getRequest().setShowRunningNotification(false)); + final Download download = enqueueRequest( + getRequest().setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN)); download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL); - assertEquals(0, mSystemFacade.mActiveNotifications.size()); - assertEquals(0, mSystemFacade.mCanceledNotifications.size()); + runService(); + + verify(mNotifManager, never()).notify(anyInt(), isA(Notification.class)); + // TODO: verify that it never cancels + } + + public void testNotificationVisible() throws Exception { + enqueueResponse(buildEmptyResponse(HTTP_OK)); - download = enqueueRequest(getRequest()); // notifications by default + // only shows in-progress notifications + final Download download = enqueueRequest(getRequest()); download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL); - assertEquals(1, mSystemFacade.mActiveNotifications.size()); + runService(); + + // TODO: verify different notif types with tags + verify(mNotifManager, atLeastOnce()).notify(anyInt(), isA(Notification.class)); + verify(mNotifManager, times(1)).cancel(anyInt()); + } - // The notification doesn't actually get canceled until the UpdateThread runs again, which - // gets triggered by the DownloadThread updating the status in the provider. + public void testNotificationVisibleComplete() throws Exception { + enqueueResponse(buildEmptyResponse(HTTP_OK)); + + final Download download = enqueueRequest(getRequest().setNotificationVisibility( + DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)); + download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL); runService(); - assertEquals(0, mSystemFacade.mActiveNotifications.size()); - assertEquals(1, mSystemFacade.mCanceledNotifications.size()); + + // TODO: verify different notif types with tags + verify(mNotifManager, atLeastOnce()).notify(anyInt(), isA(Notification.class)); + verify(mNotifManager, times(1)).cancel(anyInt()); } public void testRetryAfter() throws Exception { -- cgit v1.2.3 From 6c26e6e1abea4529b2f9a9ab941127d42edba984 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Sat, 28 Jul 2012 15:29:30 -0700 Subject: Explicitly export content providers In a future version of Android, the default value for will change from true to false. Explicitly set android:exported="true" Bug: 3306452 Change-Id: Id23f16a8527ba97be1d8617ccfc4346734f695d0 --- AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 05df6cd3..7a1ce39e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -58,7 +58,7 @@ + android:authorities="downloads" android:exported="true"> Date: Mon, 27 Aug 2012 21:53:30 -0700 Subject: Send ORIGINATING_URI and REFERRER to installer. When building PackageInstaller intents, include ORIGINATING_URI and REFERRER extras. Unify view intent building for both notifications and list UI. Bug: 6900672 Change-Id: I18435e0f8aa549880ec594f82b6a250232706135 --- .../providers/downloads/DownloadReceiver.java | 22 +---- .../android/providers/downloads/OpenHelper.java | 105 +++++++++++++++++++++ ui/Android.mk | 5 +- .../providers/downloads/ui/DownloadList.java | 20 +--- 4 files changed, 119 insertions(+), 33 deletions(-) create mode 100644 src/com/android/providers/downloads/OpenHelper.java diff --git a/src/com/android/providers/downloads/DownloadReceiver.java b/src/com/android/providers/downloads/DownloadReceiver.java index 81ff4040..aa165e41 100644 --- a/src/com/android/providers/downloads/DownloadReceiver.java +++ b/src/com/android/providers/downloads/DownloadReceiver.java @@ -28,13 +28,12 @@ import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; +import android.provider.BaseColumns; import android.provider.Downloads; import android.util.Log; import com.google.common.annotations.VisibleForTesting; -import java.io.File; - /** * Receives system broadcasts (boot, network connectivity) */ @@ -144,23 +143,12 @@ public class DownloadReceiver extends BroadcastReceiver { * has been clicked. */ private void openDownload(Context context, Cursor cursor) { - String filename = cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl._DATA)); - String mimetype = - cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_MIME_TYPE)); - Uri path = Uri.parse(filename); - // If there is no scheme, then it must be a file - if (path.getScheme() == null) { - path = Uri.fromFile(new File(filename)); - } - - Intent activityIntent = new Intent(Intent.ACTION_VIEW); - mimetype = DownloadDrmHelper.getOriginalMimeType(context, filename, mimetype); - activityIntent.setDataAndType(path, mimetype); - activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + final long id = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID)); + final Intent intent = OpenHelper.buildViewIntent(context, id); try { - context.startActivity(activityIntent); + context.startActivity(intent); } catch (ActivityNotFoundException ex) { - Log.d(Constants.TAG, "no activity for " + mimetype, ex); + Log.d(Constants.TAG, "no activity for " + intent, ex); } } diff --git a/src/com/android/providers/downloads/OpenHelper.java b/src/com/android/providers/downloads/OpenHelper.java new file mode 100644 index 00000000..0151c8de --- /dev/null +++ b/src/com/android/providers/downloads/OpenHelper.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2012 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_LOCAL_URI; +import static android.app.DownloadManager.COLUMN_MEDIA_TYPE; +import static android.app.DownloadManager.COLUMN_URI; +import static android.provider.Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI; + +import android.app.DownloadManager; +import android.content.ContentUris; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.provider.Downloads.Impl.RequestHeaders; + +public class OpenHelper { + /** + * Build an {@link Intent} to view the download at current {@link Cursor} + * position, handling subtleties around installing packages. + */ + public static Intent buildViewIntent(Context context, long id) { + final DownloadManager downManager = (DownloadManager) context.getSystemService( + Context.DOWNLOAD_SERVICE); + downManager.setAccessAllDownloads(true); + + final Cursor cursor = downManager.query(new DownloadManager.Query().setFilterById(id)); + try { + if (!cursor.moveToFirst()) { + throw new IllegalArgumentException("Missing download " + id); + } + + final Uri localUri = getCursorUri(cursor, COLUMN_LOCAL_URI); + final String mimeType = getCursorString(cursor, COLUMN_MEDIA_TYPE); + + final Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION); + + if ("application/vnd.android.package-archive".equals(mimeType)) { + // PackageInstaller doesn't like content URIs, so open file + intent.setDataAndType(localUri, mimeType); + + // Also splice in details about where it came from + final Uri remoteUri = getCursorUri(cursor, COLUMN_URI); + intent.putExtra(Intent.EXTRA_ORIGINATING_URI, remoteUri); + intent.putExtra(Intent.EXTRA_REFERRER, getRefererUri(context, id)); + } else if ("file".equals(localUri.getScheme())) { + intent.setDataAndType( + ContentUris.withAppendedId(ALL_DOWNLOADS_CONTENT_URI, id), mimeType); + } else { + intent.setDataAndType(localUri, mimeType); + } + + return intent; + } finally { + cursor.close(); + } + } + + private static Uri getRefererUri(Context context, long id) { + final Uri headersUri = Uri.withAppendedPath( + ContentUris.withAppendedId(ALL_DOWNLOADS_CONTENT_URI, id), + RequestHeaders.URI_SEGMENT); + final Cursor headers = context.getContentResolver() + .query(headersUri, null, null, null, null); + try { + while (headers.moveToNext()) { + final String header = getCursorString(headers, RequestHeaders.COLUMN_HEADER); + if ("Referer".equalsIgnoreCase(header)) { + return getCursorUri(headers, RequestHeaders.COLUMN_VALUE); + } + } + } finally { + headers.close(); + } + return null; + } + + private static String getCursorString(Cursor cursor, String column) { + return cursor.getString(cursor.getColumnIndexOrThrow(column)); + } + + private static Uri getCursorUri(Cursor cursor, String column) { + return Uri.parse(getCursorString(cursor, column)); + } + + private static long getCursorLong(Cursor cursor, String column) { + return cursor.getLong(cursor.getColumnIndexOrThrow(column)); + } +} diff --git a/ui/Android.mk b/ui/Android.mk index 8c925f64..14211ea2 100644 --- a/ui/Android.mk +++ b/ui/Android.mk @@ -3,7 +3,10 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_SRC_FILES := $(call all-java-files-under, src) \ + ../src/com/android/providers/downloads/OpenHelper.java \ + ../src/com/android/providers/downloads/Constants.java \ + ../src/com/android/providers/downloads/DownloadDrmHelper.java LOCAL_PACKAGE_NAME := DownloadProviderUi LOCAL_CERTIFICATE := media diff --git a/ui/src/com/android/providers/downloads/ui/DownloadList.java b/ui/src/com/android/providers/downloads/ui/DownloadList.java index 103d3f83..6ffa0691 100644 --- a/ui/src/com/android/providers/downloads/ui/DownloadList.java +++ b/ui/src/com/android/providers/downloads/ui/DownloadList.java @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Parcelable; +import android.provider.BaseColumns; import android.provider.Downloads; import android.util.Log; import android.util.SparseBooleanArray; @@ -50,6 +51,8 @@ import android.widget.ExpandableListView.OnChildClickListener; import android.widget.ListView; import android.widget.Toast; +import com.android.providers.downloads.OpenHelper; + import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; @@ -499,7 +502,6 @@ public class DownloadList extends Activity { * Send an Intent to open the download currently pointed to by the given cursor. */ private void openCurrentDownload(Cursor cursor) { - final long id = cursor.getInt(mIdColumnId); final Uri localUri = Uri.parse(cursor.getString(mLocalUriColumnId)); try { getContentResolver().openFileDescriptor(localUri, "r").close(); @@ -512,20 +514,8 @@ public class DownloadList extends Activity { // close() failed, not a problem } - final Uri viewUri; - final String mimeType = cursor.getString(mMediaTypeColumnId); - if ("application/vnd.android.package-archive".equals(mimeType)) { - // PackageInstaller doesn't like content URIs, so open file - viewUri = localUri; - } else if ("file".equals(localUri.getScheme())) { - viewUri = ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id); - } else { - viewUri = localUri; - } - - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(viewUri, mimeType); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION); + final long id = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID)); + final Intent intent = OpenHelper.buildViewIntent(this, id); try { startActivity(intent); } catch (ActivityNotFoundException ex) { -- cgit v1.2.3 From 14991c65911034a97268840d36cf9549e06fd56e Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Thu, 13 Sep 2012 16:19:46 -0700 Subject: Properly dispatch checkbox toggling Bug #6995003 Change-Id: I3dba57d7ee9697bfdb976432096c680a0f0a4480 --- ui/src/com/android/providers/downloads/ui/DownloadItem.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/src/com/android/providers/downloads/ui/DownloadItem.java b/ui/src/com/android/providers/downloads/ui/DownloadItem.java index fc78ca49..e24ac4a4 100644 --- a/ui/src/com/android/providers/downloads/ui/DownloadItem.java +++ b/ui/src/com/android/providers/downloads/ui/DownloadItem.java @@ -18,6 +18,7 @@ package com.android.providers.downloads.ui; import android.content.Context; import android.util.AttributeSet; +import android.view.accessibility.AccessibilityEvent; import android.view.MotionEvent; import android.widget.CheckBox; import android.widget.Checkable; @@ -100,6 +101,7 @@ public class DownloadItem extends GridLayout implements Checkable { case MotionEvent.ACTION_UP: if (mIsInDownEvent && event.getX() < CHECKMARK_AREA) { toggle(); + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); handled = true; } mIsInDownEvent = false; @@ -130,7 +132,7 @@ public class DownloadItem extends GridLayout implements Checkable { @Override public void toggle() { - mCheckBox.performClick(); + setChecked(!isChecked()); } public CheckBox getCheckBox() { -- cgit v1.2.3 From a2304fb28026f3da1bb91931c4cdd52110c82577 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Mon, 24 Sep 2012 14:37:19 -0700 Subject: Remove FLAG_ACTIVITY_NEW_TASK from the VIEW intent. Bug: 7164238 Bug: 7237908 Got rid of FLAG_ACTIVITY_NEW_TASK for proper back behavior Change-Id: I50af9aeafb27d6079bda4f81f4a116b6bb600676 --- src/com/android/providers/downloads/DownloadReceiver.java | 1 + src/com/android/providers/downloads/OpenHelper.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/android/providers/downloads/DownloadReceiver.java b/src/com/android/providers/downloads/DownloadReceiver.java index aa165e41..7469508d 100644 --- a/src/com/android/providers/downloads/DownloadReceiver.java +++ b/src/com/android/providers/downloads/DownloadReceiver.java @@ -145,6 +145,7 @@ public class DownloadReceiver extends BroadcastReceiver { private void openDownload(Context context, Cursor cursor) { final long id = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID)); final Intent intent = OpenHelper.buildViewIntent(context, id); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { context.startActivity(intent); } catch (ActivityNotFoundException ex) { diff --git a/src/com/android/providers/downloads/OpenHelper.java b/src/com/android/providers/downloads/OpenHelper.java index 0151c8de..6424bcde 100644 --- a/src/com/android/providers/downloads/OpenHelper.java +++ b/src/com/android/providers/downloads/OpenHelper.java @@ -49,7 +49,7 @@ public class OpenHelper { final String mimeType = getCursorString(cursor, COLUMN_MEDIA_TYPE); final Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); if ("application/vnd.android.package-archive".equals(mimeType)) { // PackageInstaller doesn't like content URIs, so open file -- cgit v1.2.3 From 46bb7dd18c9b092d352d76ab44a4e52951941b2c Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Thu, 27 Sep 2012 11:12:30 -0700 Subject: Send uid of the application that initiated the download Bug: 6923241 Change-Id: Idf4037b4e360cb6453b315d1cc95608762c9e0c8 --- src/com/android/providers/downloads/OpenHelper.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/com/android/providers/downloads/OpenHelper.java b/src/com/android/providers/downloads/OpenHelper.java index 0151c8de..c7d90edd 100644 --- a/src/com/android/providers/downloads/OpenHelper.java +++ b/src/com/android/providers/downloads/OpenHelper.java @@ -59,6 +59,7 @@ public class OpenHelper { final Uri remoteUri = getCursorUri(cursor, COLUMN_URI); intent.putExtra(Intent.EXTRA_ORIGINATING_URI, remoteUri); intent.putExtra(Intent.EXTRA_REFERRER, getRefererUri(context, id)); + intent.putExtra(Intent.EXTRA_ORIGINATING_UID, getOriginatingUid(context, id)); } else if ("file".equals(localUri.getScheme())) { intent.setDataAndType( ContentUris.withAppendedId(ALL_DOWNLOADS_CONTENT_URI, id), mimeType); @@ -91,6 +92,22 @@ public class OpenHelper { return null; } + private static int getOriginatingUid(Context context, long id) { + final Uri uri = ContentUris.withAppendedId(ALL_DOWNLOADS_CONTENT_URI, id); + final Cursor cursor = context.getContentResolver().query(uri, new String[]{Constants.UID}, + null, null, null); + if (cursor != null) { + try { + if (cursor.moveToFirst()) { + return cursor.getInt(cursor.getColumnIndexOrThrow(Constants.UID)); + } + } finally { + cursor.close(); + } + } + return -1; + } + private static String getCursorString(Cursor cursor, String column) { return cursor.getString(cursor.getColumnIndexOrThrow(column)); } -- cgit v1.2.3 From b92aa3a88dd25a798bbedc860d9b29aef42bbb0f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 3 Oct 2012 11:26:56 -0700 Subject: Handle not fully connected networks. When checking network status, treat non-connected networks as disconnected. This handles cases like captive portal checks, and slow DHCP servers. Bug: 7264340 Change-Id: I0b466cee5d5cb73037f3fb209c583711b8f9eefd --- src/com/android/providers/downloads/DownloadInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/providers/downloads/DownloadInfo.java b/src/com/android/providers/downloads/DownloadInfo.java index e452e5bf..b6d57a05 100644 --- a/src/com/android/providers/downloads/DownloadInfo.java +++ b/src/com/android/providers/downloads/DownloadInfo.java @@ -342,7 +342,7 @@ public class DownloadInfo { */ public int checkCanUseNetwork() { final NetworkInfo info = mSystemFacade.getActiveNetworkInfo(mUid); - if (info == null) { + if (info == null || !info.isConnected()) { return NETWORK_NO_CONNECTION; } if (DetailedState.BLOCKED.equals(info.getDetailedState())) { -- cgit v1.2.3 From 70b5c30db87b3405e2e001c06c4a4a5dd6e25b72 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 5 Oct 2012 15:09:00 -0700 Subject: Skip scanning a file which will be deleted. When deleting a download, don't bother scanning it, since we'll just delete it moments later. This was already racy since it didn't even wait for the scan to complete. Bug: 7256243 Change-Id: I8c3b96823d94bc1688ef336cb45746ccd35fc760 --- src/com/android/providers/downloads/DownloadService.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/com/android/providers/downloads/DownloadService.java b/src/com/android/providers/downloads/DownloadService.java index 7030deae..8380830a 100644 --- a/src/com/android/providers/downloads/DownloadService.java +++ b/src/com/android/providers/downloads/DownloadService.java @@ -479,9 +479,6 @@ public class DownloadService extends Service { */ private void deleteDownloadLocked(long id) { DownloadInfo info = mDownloads.get(id); - if (info.shouldScanFile()) { - scanFile(info, false, false); - } if (info.mStatus == Downloads.Impl.STATUS_RUNNING) { info.mStatus = Downloads.Impl.STATUS_CANCELED; } -- cgit v1.2.3 From 7444bae122a6f0922792813c6200fe135b4daaa3 Mon Sep 17 00:00:00 2001 From: Jason Chen Date: Fri, 12 Oct 2012 08:50:10 -0700 Subject: Let's enhance Add mipmap-xxhdpi launcher icon asset. Bug: 6718166 Change-Id: I9fbe8e6c5345fddc78b0129e329205aaf973ea6c --- ui/res/mipmap-xxhdpi/ic_launcher_download.png | Bin 0 -> 21228 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ui/res/mipmap-xxhdpi/ic_launcher_download.png diff --git a/ui/res/mipmap-xxhdpi/ic_launcher_download.png b/ui/res/mipmap-xxhdpi/ic_launcher_download.png new file mode 100644 index 00000000..0921c124 Binary files /dev/null and b/ui/res/mipmap-xxhdpi/ic_launcher_download.png differ -- cgit v1.2.3 From 169ab531ca6bb2f43ed18fe2b03f66c808f12b81 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 19 Oct 2012 14:42:24 -0700 Subject: Bring back DRM mimetypes. I don't like DRM, but other people do. Bug: 7370549 Change-Id: I44220404eab6e6cc85ea16cfcf58474135c03f83 --- src/com/android/providers/downloads/OpenHelper.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/com/android/providers/downloads/OpenHelper.java b/src/com/android/providers/downloads/OpenHelper.java index 356375b8..7eca95c9 100644 --- a/src/com/android/providers/downloads/OpenHelper.java +++ b/src/com/android/providers/downloads/OpenHelper.java @@ -16,6 +16,7 @@ package com.android.providers.downloads; +import static android.app.DownloadManager.COLUMN_LOCAL_FILENAME; import static android.app.DownloadManager.COLUMN_LOCAL_URI; import static android.app.DownloadManager.COLUMN_MEDIA_TYPE; import static android.app.DownloadManager.COLUMN_URI; @@ -46,7 +47,9 @@ public class OpenHelper { } final Uri localUri = getCursorUri(cursor, COLUMN_LOCAL_URI); - final String mimeType = getCursorString(cursor, COLUMN_MEDIA_TYPE); + final String filename = getCursorString(cursor, COLUMN_LOCAL_FILENAME); + String mimeType = getCursorString(cursor, COLUMN_MEDIA_TYPE); + mimeType = DownloadDrmHelper.getOriginalMimeType(context, filename, mimeType); final Intent intent = new Intent(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); -- cgit v1.2.3 From 2fa007ef678b2283d47d007aa3dc91af683cc52c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 24 Oct 2012 17:18:32 -0700 Subject: Better sanity checking for finished downloads. Downloads in the RUNNING state are considered ready to start so that downloads are correctly resumed when the process crashes. However, this causes a race condition while UpdateThread is processing a Cursor when a DownloadThread finishes. With this change, DownloadThread now skips requests for downloads already marked as finished. Apps listening for the DOWNLOAD_COMPLETE broadcast will no longer see data mutated by the second thread, and will not see the broadcast duplicated. Bug: 6948938, 6970458, 6818900 Change-Id: I35deac3cedbfe7f50091fab5818d85594dba558c --- .../android/providers/downloads/DownloadInfo.java | 21 ++++++++++++++++++++- .../android/providers/downloads/DownloadThread.java | 16 +++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/com/android/providers/downloads/DownloadInfo.java b/src/com/android/providers/downloads/DownloadInfo.java index b6d57a05..5172b696 100644 --- a/src/com/android/providers/downloads/DownloadInfo.java +++ b/src/com/android/providers/downloads/DownloadInfo.java @@ -36,7 +36,6 @@ import android.util.Pair; import com.android.internal.util.IndentingPrintWriter; -import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -576,4 +575,24 @@ public class DownloadInfo { StorageManager.getInstance(mContext)); mSystemFacade.startThread(downloader); } + + /** + * Query and return status of requested download. + */ + public static int queryDownloadStatus(ContentResolver resolver, long id) { + final Cursor cursor = resolver.query( + ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id), + new String[] { Downloads.Impl.COLUMN_STATUS }, null, null, null); + try { + if (cursor.moveToFirst()) { + return cursor.getInt(0); + } else { + // TODO: increase strictness of value returned for unknown + // downloads; this is safe default for now. + return Downloads.Impl.STATUS_PENDING; + } + } finally { + cursor.close(); + } + } } diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java index 37db32b1..e74d5c72 100644 --- a/src/com/android/providers/downloads/DownloadThread.java +++ b/src/com/android/providers/downloads/DownloadThread.java @@ -130,6 +130,21 @@ public class DownloadThread extends Thread { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + try { + runInternal(); + } finally { + DownloadHandler.getInstance().dequeueDownload(mInfo.mId); + } + } + + 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) + == Downloads.Impl.STATUS_SUCCESS) { + Log.d(TAG, "Download " + mInfo.mId + " already finished; skipping"); + return; + } State state = new State(mInfo); AndroidHttpClient client = null; @@ -210,7 +225,6 @@ public class DownloadThread extends Thread { notifyDownloadCompleted(finalStatus, state.mCountRetry, state.mRetryAfter, state.mGotData, state.mFilename, state.mNewUri, state.mMimeType, errorMsg); - DownloadHandler.getInstance().dequeueDownload(mInfo.mId); netPolicy.unregisterListener(mPolicyListener); -- cgit v1.2.3