diff options
-rw-r--r-- | Android.mk | 2 | ||||
-rw-r--r-- | res/values-lt/strings.xml | 10 | ||||
-rw-r--r-- | res/values-my-rMM/strings.xml | 4 | ||||
-rw-r--r-- | src/com/android/providers/downloads/DownloadNotifier.java | 4 | ||||
-rw-r--r-- | src/com/android/providers/downloads/DownloadProvider.java | 67 | ||||
-rw-r--r-- | src/com/android/providers/downloads/DownloadStorageProvider.java | 145 | ||||
-rw-r--r-- | src/com/android/providers/downloads/DownloadThread.java | 1 | ||||
-rw-r--r-- | src/com/android/providers/downloads/OpenHelper.java | 17 | ||||
-rw-r--r-- | ui/res/values-my-rMM/strings.xml | 4 |
9 files changed, 185 insertions, 69 deletions
@@ -11,6 +11,8 @@ LOCAL_PRIVILEGED_MODULE := true LOCAL_STATIC_JAVA_LIBRARIES := guava \ android-support-documents-archive +LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.providers.downloads.* + include $(BUILD_PACKAGE) # build UI + tests diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index 856d33d8..ef2d382b 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -18,18 +18,18 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="3658948994665187911">"Atsisiuntimų tvarkytuvė"</string> <string name="permlab_downloadManager" msgid="7779544811202855500">"Pasiekti atsisiuntimo tvarkyklę."</string> - <string name="permdesc_downloadManager" msgid="4237406545998908947">"Leidžiama programai pasiekti atsisiuntimų tvarkyklę ir naudoti ją failams atsisiųsti. Kenkėjiškos programos gali naudoti šią funkciją atsisiuntimams stabdyti ir asmeninei informacijai pasiekti."</string> - <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Išplėstinės atsisiuntimo tvarkyklės funkcijos."</string> - <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Leidžiama programai pasiekti išplėstines atsisiuntimų tvarkyklės funkcijas. Kenkėjiškos programos gali naudoti šią funkciją atsisiuntimams stabdyti ir asmeninei informacijai gauti."</string> + <string name="permdesc_downloadManager" msgid="4237406545998908947">"Leidžiama programai pasiekti atsisiuntimų tvarkytuvę ir naudoti ją failams atsisiųsti. Kenkėjiškos programos gali naudoti šią funkciją atsisiuntimams stabdyti ir asmeninei informacijai pasiekti."</string> + <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Išplėstinės atsisiuntimo tvarkytuvės funkcijos."</string> + <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Leidžiama programai pasiekti išplėstines atsisiuntimų tvarkytuvės funkcijas. Kenkėjiškos programos gali naudoti šią funkciją atsisiuntimams stabdyti ir asmeninei informacijai gauti."</string> <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Siųsti atsisiuntimo pranešimus."</string> <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Leidžiama programai siųsti pranešimus apie baigtus atsisiuntimus. Kenkėjiškos programos gali naudoti šią funkciją, kad supainiotų kitas programas, kurias naudojant siunčiami failai."</string> <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"Žr. visus atsis. į USB atm."</string> <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"Žiūrėti visus atsisiuntimus į SD kortelę"</string> <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"Leidžiama programai matyti visus atsisiuntimus į SD kortelę, neatsižvelgiant į tai, kokia programa jie buvo atsiųsti."</string> <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Rezervuoti vietą atsisiuntimo talpykloje"</string> - <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Leidžiama programai atsisiųsti failus į atsisiuntimo talpyklą, kurios negalima automatiškai ištrinti, kai atsisiuntimo tvarkyklei prireikia daugiau vietos."</string> + <string name="permdesc_downloadCacheNonPurgeable" msgid="2408760720334570420">"Leidžiama programai atsisiųsti failus į atsisiuntimo talpyklą, kurios negalima automatiškai ištrinti, kai atsisiuntimo tvarkytuvei prireikia daugiau vietos."</string> <string name="permlab_downloadWithoutNotification" msgid="8837971946078327262">"atsisiųsti failus be pranešimo"</string> - <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Leidžiama programai atsisiųsti failus naudojant atsisiuntimo tvarkyklę, naudotojui nepateikus jokio pranešimo."</string> + <string name="permdesc_downloadWithoutNotification" msgid="8483135034298639727">"Leidžiama programai atsisiųsti failus naudojant atsisiuntimo tvarkytuvę, naudotojui nepateikus jokio pranešimo."</string> <string name="permlab_accessAllDownloads" msgid="2436240495424393717">"Pasiekti visus sistemos atsisiuntimus"</string> <string name="permdesc_accessAllDownloads" msgid="1871832254578267128">"Leidžiama programai žiūrėti ir keisti visus atsisiuntimus, pradėtus naudojant bet kokią sistemos programą."</string> <string name="download_unknown_title" msgid="7015124071247271585">"<Be pavadinimo>"</string> diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml index 209fca4a..4cabab23 100644 --- a/res/values-my-rMM/strings.xml +++ b/res/values-my-rMM/strings.xml @@ -22,7 +22,7 @@ <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="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"အက်ပ်အား ဒေါင်းလုပ်ပြီးဆုံးပါက အကြောင်းကြားရန် ခွင့်ပြုမည်။ အန္တရာယ် ရှိသော အက်ပ်များက ၎င်းကို အသုံးပြုကာ ဖိုင်များကိုဒေါင်းလုပ်ပြုထားသော အက်ပ်ကို ရောထွေးအောင်ပြုလုပ်နိုင်သည်။"</string> <string name="permlab_seeAllExternal" product="nosdcard" msgid="4084575448409212628">"ဒေါင်းလုပ်အားလုံးကို USBသိုလှောင်ကတ်ထဲတွင် ကြည့်မည်"</string> <string name="permlab_seeAllExternal" product="default" msgid="140058400609165726">"ဒေါင်းလုပ်အားလုံးကို SDကတ်ထဲတွင် ကြည့်မည်"</string> <string name="permdesc_seeAllExternal" msgid="1672759909065511233">"အပလီကေးရှင်းအား SDကဒ်ထဲရှိ မည်သည့်အပလီကေးရှင်းမှမဆို ဒေါင်းလုပ်ပြုလုပ်ထားသည်များကို သုံးစွဲခွင့်ပြုမည်။"</string> @@ -42,7 +42,7 @@ <string name="wifi_recommended_title" msgid="7441589306734687400">"နောက်မှ ဒေါင်းလုပ်ပြုလုပ်ရန် တန်းစီထားမလား?"</string> <string name="wifi_recommended_body" msgid="1314735166699936073">"ဤ <xliff:g id="SIZE">%s </xliff:g>ဒေါင်းလုပ်ကို စတင်ခြင်းမှာ သင့်ဘက်ထရီ သက်တမ်းကို တိုစေသည် သို့မဟုတ် သင့်ဒေတာပလန်ပေါ် မူတည်၍ ကျသင့်ငွေ ပိုကုန်စေမည့် မိုဘိုင်းဒေတာ ချိတ်ဆက်မှုကို အလွန်အကျွံ သုံးနိုင်သည်။ \n\n နောက်တစ်ခါ ဝိုင်ဖိုင်ချိတ်ဆက်လျှင် ဒေါင်းလုပ်စတင်ရန် <xliff:g id="QUEUE_TEXT">%s</xliff:g> ကို တို့ထိပါ။"</string> <string name="button_queue_for_wifi" msgid="422576726189179221">"တန်းစီရန်"</string> - <string name="button_cancel_download" msgid="2430166148737975604">"မလုပ်တော့ပါ"</string> + <string name="button_cancel_download" msgid="2430166148737975604">"မလုပ်တော့"</string> <string name="button_start_now" msgid="792123674007840864">"ယခုအချိန်မှစတင်ပါ"</string> <plurals name="notif_summary_active" formatted="false" msgid="7290448463204837173"> <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> ဖိုင်များကို ဒေါင်းလုဒ် လုပ်နေပါသည်</item> diff --git a/src/com/android/providers/downloads/DownloadNotifier.java b/src/com/android/providers/downloads/DownloadNotifier.java index d5808690..d13bb5e2 100644 --- a/src/com/android/providers/downloads/DownloadNotifier.java +++ b/src/com/android/providers/downloads/DownloadNotifier.java @@ -213,7 +213,9 @@ public class DownloadNotifier { downloadIds); builder.setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); - builder.setOngoing(true); + if (type == TYPE_ACTIVE) { + builder.setOngoing(true); + } // Add a Cancel action final Uri cancelUri = new Uri.Builder().scheme("cancel-dl").appendPath(tag).build(); diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java index d50eedba..72975582 100644 --- a/src/com/android/providers/downloads/DownloadProvider.java +++ b/src/com/android/providers/downloads/DownloadProvider.java @@ -18,7 +18,6 @@ package com.android.providers.downloads; import static android.provider.BaseColumns._ID; import static android.provider.Downloads.Impl.COLUMN_DESTINATION; -import static android.provider.Downloads.Impl.COLUMN_MEDIAPROVIDER_URI; import static android.provider.Downloads.Impl.COLUMN_MEDIA_SCANNED; import static android.provider.Downloads.Impl.COLUMN_MIME_TYPE; import static android.provider.Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD; @@ -29,6 +28,7 @@ import android.app.DownloadManager; import android.app.DownloadManager.Request; import android.app.job.JobScheduler; import android.content.ContentProvider; +import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; @@ -1077,10 +1077,14 @@ public final class DownloadProvider extends ContentProvider { Helpers.validateSelection(where, sAppReadableColumnsSet); - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + final Context context = getContext(); + final ContentResolver resolver = context.getContentResolver(); + + final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count; boolean updateSchedule = false; + boolean isCompleting = false; ContentValues filteredValues; if (Binder.getCallingPid() != Process.myPid()) { @@ -1121,6 +1125,7 @@ public final class DownloadProvider extends ContentProvider { if (isRestart || isUserBypassingSizeLimit) { updateSchedule = true; } + isCompleting = status != null && Downloads.Impl.isStatusCompleted(status); } int match = sURIMatcher.match(uri); @@ -1137,14 +1142,20 @@ public final class DownloadProvider extends ContentProvider { final SqlSelection selection = getWhereClause(uri, where, whereArgs, match); count = db.update(DB_TABLE, filteredValues, selection.getSelection(), selection.getParameters()); - if (updateSchedule) { + if (updateSchedule || isCompleting) { final long token = Binder.clearCallingIdentity(); - try { - try (Cursor cursor = db.query(DB_TABLE, new String[] { _ID }, - selection.getSelection(), selection.getParameters(), - null, null, null)) { - while (cursor.moveToNext()) { - Helpers.scheduleJob(getContext(), cursor.getInt(0)); + try (Cursor cursor = db.query(DB_TABLE, null, selection.getSelection(), + selection.getParameters(), null, null, null)) { + final DownloadInfo.Reader reader = new DownloadInfo.Reader(resolver, + cursor); + final DownloadInfo info = new DownloadInfo(context); + while (cursor.moveToNext()) { + reader.updateFromDatabase(info); + if (updateSchedule) { + Helpers.scheduleJob(context, info); + } + if (isCompleting) { + info.sendIntentIfRequested(); } } } finally { @@ -1207,7 +1218,10 @@ public final class DownloadProvider extends ContentProvider { Helpers.validateSelection(where, sAppReadableColumnsSet); } - final JobScheduler scheduler = getContext().getSystemService(JobScheduler.class); + final Context context = getContext(); + final ContentResolver resolver = context.getContentResolver(); + final JobScheduler scheduler = context.getSystemService(JobScheduler.class); + final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count; int match = sURIMatcher.match(uri); @@ -1219,16 +1233,18 @@ public final class DownloadProvider extends ContentProvider { final SqlSelection selection = getWhereClause(uri, where, whereArgs, match); deleteRequestHeaders(db, selection.getSelection(), selection.getParameters()); - try (Cursor cursor = db.query(DB_TABLE, new String[] { - _ID, _DATA, COLUMN_MEDIAPROVIDER_URI - }, selection.getSelection(), selection.getParameters(), null, null, null)) { + try (Cursor cursor = db.query(DB_TABLE, null, selection.getSelection(), + selection.getParameters(), null, null, null)) { + final DownloadInfo.Reader reader = new DownloadInfo.Reader(resolver, cursor); + final DownloadInfo info = new DownloadInfo(context); while (cursor.moveToNext()) { - final long id = cursor.getLong(0); - scheduler.cancel((int) id); - revokeAllDownloadsPermission(id); - DownloadStorageProvider.onDownloadProviderDelete(getContext(), id); + reader.updateFromDatabase(info); + scheduler.cancel((int) info.mId); + + revokeAllDownloadsPermission(info.mId); + DownloadStorageProvider.onDownloadProviderDelete(getContext(), info.mId); - final String path = cursor.getString(1); + final String path = info.mFileName; if (!TextUtils.isEmpty(path)) { try { final File file = new File(path).getCanonicalFile(); @@ -1241,7 +1257,7 @@ public final class DownloadProvider extends ContentProvider { } } - final String mediaUri = cursor.getString(2); + final String mediaUri = info.mMediaProviderUri; if (!TextUtils.isEmpty(mediaUri)) { final long token = Binder.clearCallingIdentity(); try { @@ -1251,6 +1267,13 @@ public final class DownloadProvider extends ContentProvider { Binder.restoreCallingIdentity(token); } } + + // If the download wasn't completed yet, we're + // effectively completing it now, and we need to send + // any requested broadcasts + if (!Downloads.Impl.isStatusCompleted(info.mStatus)) { + info.sendIntentIfRequested(); + } } } @@ -1262,6 +1285,12 @@ public final class DownloadProvider extends ContentProvider { throw new UnsupportedOperationException("Cannot delete URI: " + uri); } notifyContentChanged(uri, match); + final long token = Binder.clearCallingIdentity(); + try { + Helpers.getDownloadNotifier(getContext()).update(); + } finally { + Binder.restoreCallingIdentity(token); + } return count; } diff --git a/src/com/android/providers/downloads/DownloadStorageProvider.java b/src/com/android/providers/downloads/DownloadStorageProvider.java index e0bb7cd1..4ec8e2d1 100644 --- a/src/com/android/providers/downloads/DownloadStorageProvider.java +++ b/src/com/android/providers/downloads/DownloadStorageProvider.java @@ -29,28 +29,36 @@ import android.net.Uri; import android.os.Binder; import android.os.CancellationSignal; import android.os.Environment; +import android.os.FileObserver; import android.os.FileUtils; import android.os.ParcelFileDescriptor; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import android.provider.DocumentsProvider; +import android.provider.Downloads; import android.support.provider.DocumentArchiveHelper; import android.text.TextUtils; -import android.webkit.MimeTypeMap; - -import libcore.io.IoUtils; +import android.util.Log; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.text.NumberFormat; +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; + +import libcore.io.IoUtils; + /** * Presents a {@link DocumentsContract} view of {@link DownloadManager} * contents. */ public class DownloadStorageProvider extends DocumentsProvider { + private static final String TAG = "DownloadStorageProvider"; + private static final boolean DEBUG = false; + private static final String AUTHORITY = Constants.STORAGE_AUTHORITY; private static final String DOC_ID_ROOT = Constants.STORAGE_ROOT_ID; @@ -74,6 +82,7 @@ public class DownloadStorageProvider extends DocumentsProvider { mDm.setAccessAllDownloads(true); mDm.setAccessFilename(true); mArchiveHelper = new DocumentArchiveHelper(this, ':'); + return true; } @@ -179,7 +188,8 @@ public class DownloadStorageProvider extends DocumentsProvider { return mArchiveHelper.queryDocument(docId, projection); } - final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); + final DownloadsCursor result = + new DownloadsCursor(projection, getContext().getContentResolver()); if (DOC_ID_ROOT.equals(docId)) { includeDefaultDocument(result); @@ -200,6 +210,8 @@ public class DownloadStorageProvider extends DocumentsProvider { Binder.restoreCallingIdentity(token); } } + + result.start(); return result; } @@ -211,7 +223,8 @@ public class DownloadStorageProvider extends DocumentsProvider { return mArchiveHelper.queryChildDocuments(docId, projection, sortOrder); } - final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); + final DownloadsCursor result = + new DownloadsCursor(projection, getContext().getContentResolver()); // Delegate to real provider final long token = Binder.clearCallingIdentity(); @@ -227,6 +240,8 @@ public class DownloadStorageProvider extends DocumentsProvider { IoUtils.closeQuietly(cursor); Binder.restoreCallingIdentity(token); } + + result.start(); return result; } @@ -238,7 +253,8 @@ public class DownloadStorageProvider extends DocumentsProvider { return mArchiveHelper.queryDocument(parentDocumentId, projection); } - final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); + final DownloadsCursor result = + new DownloadsCursor(projection, getContext().getContentResolver()); // Delegate to real provider final long token = Binder.clearCallingIdentity(); @@ -254,13 +270,17 @@ public class DownloadStorageProvider extends DocumentsProvider { IoUtils.closeQuietly(cursor); Binder.restoreCallingIdentity(token); } + + result.start(); return result; } @Override public Cursor queryRecentDocuments(String rootId, String[] projection) throws FileNotFoundException { - final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); + + final DownloadsCursor result = + new DownloadsCursor(projection, getContext().getContentResolver()); // Delegate to real provider final long token = Binder.clearCallingIdentity(); @@ -288,6 +308,8 @@ public class DownloadStorageProvider extends DocumentsProvider { IoUtils.closeQuietly(cursor); Binder.restoreCallingIdentity(token); } + + result.start(); return result; } @@ -325,6 +347,10 @@ public class DownloadStorageProvider extends DocumentsProvider { Document.FLAG_DIR_PREFERS_LAST_MODIFIED | Document.FLAG_DIR_SUPPORTS_CREATE); } + /** + * Adds the entry from the cursor to the result only if the entry is valid. That is, + * if the file exists in the file system. + */ private void includeDownloadFromCursor(MatrixCursor result, Cursor cursor) { final long id = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID)); final String docId = String.valueOf(id); @@ -344,12 +370,20 @@ public class DownloadStorageProvider extends DocumentsProvider { if (size == -1) { size = null; } + String localFilePath = cursor.getString( + cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_FILENAME)); int extraFlags = Document.FLAG_PARTIAL; final int status = cursor.getInt( cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)); switch (status) { case DownloadManager.STATUS_SUCCESSFUL: + // Verify that the document still exists in external storage. This is necessary + // because files can be deleted from the file system without their entry being + // removed from DownloadsManager. + if (localFilePath == null || !new File(localFilePath).exists()) { + return; + } extraFlags = Document.FLAG_SUPPORTS_RENAME; // only successful is non-partial break; case DownloadManager.STATUS_PAUSED: @@ -400,38 +434,97 @@ public class DownloadStorageProvider extends DocumentsProvider { row.add(Document.COLUMN_LAST_MODIFIED, lastModified); } - final String localFilePath = cursor.getString( - cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_FILENAME)); if (localFilePath != null) { row.add(DocumentArchiveHelper.COLUMN_LOCAL_FILE_PATH, localFilePath); } } /** - * Remove file extension from name, but only if exact MIME type mapping - * exists. This means we can reapply the extension later. + * A MatrixCursor that spins up a file observer when the first instance is + * started ({@link #start()}, and stops the file observer when the last instance + * closed ({@link #close()}. When file changes are observed, a content change + * notification is sent on the Downloads content URI. + * + * <p>This is necessary as other processes, like ExternalStorageProvider, + * can access and modify files directly (without sending operations + * through DownloadStorageProvider). + * + * <p>Without this, contents accessible by one a Downloads cursor instance + * (like the Downloads root in Files app) can become state. */ - private static String removeExtension(String mimeType, String name) { - final int lastDot = name.lastIndexOf('.'); - if (lastDot >= 0) { - final String extension = name.substring(lastDot + 1); - final String nameMime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - if (mimeType.equals(nameMime)) { - return name.substring(0, lastDot); + private static final class DownloadsCursor extends MatrixCursor { + + private static final Object mLock = new Object(); + @GuardedBy("mLock") + private static int mOpenCursorCount = 0; + @GuardedBy("mLock") + private static @Nullable ContentChangedRelay mFileWatcher; + + private final ContentResolver mResolver; + + DownloadsCursor(String[] projection, ContentResolver resolver) { + super(resolveDocumentProjection(projection)); + mResolver = resolver; + } + + void start() { + synchronized (mLock) { + if (mOpenCursorCount++ == 0) { + mFileWatcher = new ContentChangedRelay(mResolver); + mFileWatcher.startWatching(); + } + } + } + + @Override + public void close() { + super.close(); + synchronized (mLock) { + if (--mOpenCursorCount == 0) { + mFileWatcher.stopWatching(); + mFileWatcher = null; + } } } - return name; } /** - * Add file extension to name, but only if exact MIME type mapping exists. + * A file observer that notifies on the Downloads content URI(s) when + * files change on disk. */ - private static String addExtension(String mimeType, String name) { - final String extension = MimeTypeMap.getSingleton() - .getExtensionFromMimeType(mimeType); - if (extension != null) { - return name + "." + extension; + private static class ContentChangedRelay extends FileObserver { + private static final int NOTIFY_EVENTS = ATTRIB | CLOSE_WRITE | MOVED_FROM | MOVED_TO + | CREATE | DELETE | DELETE_SELF | MOVE_SELF; + + private static final String DOWNLOADS_PATH = + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + .getAbsolutePath(); + private final ContentResolver mResolver; + + public ContentChangedRelay(ContentResolver resolver) { + super(DOWNLOADS_PATH, NOTIFY_EVENTS); + mResolver = resolver; + } + + @Override + public void startWatching() { + super.startWatching(); + if (DEBUG) Log.d(TAG, "Started watching for file changes in: " + DOWNLOADS_PATH); + } + + @Override + public void stopWatching() { + super.stopWatching(); + if (DEBUG) Log.d(TAG, "Stopped watching for file changes in: " + DOWNLOADS_PATH); + } + + @Override + public void onEvent(int event, String path) { + if ((event & NOTIFY_EVENTS) != 0) { + if (DEBUG) Log.v(TAG, "Change detected at path: " + DOWNLOADS_PATH); + mResolver.notifyChange(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, null, false); + mResolver.notifyChange(Downloads.Impl.CONTENT_URI, null, false); + } } - return name; } } diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java index 40194038..c6b4c71a 100644 --- a/src/com/android/providers/downloads/DownloadThread.java +++ b/src/com/android/providers/downloads/DownloadThread.java @@ -382,7 +382,6 @@ public class DownloadThread extends Thread { } if (Downloads.Impl.isStatusCompleted(mInfoDelta.mStatus)) { - mInfo.sendIntentIfRequested(); if (mInfo.shouldScanFile(mInfoDelta.mStatus)) { DownloadScanner.requestScanBlocking(mContext, mInfo.mId, mInfoDelta.mFileName, mInfoDelta.mMimeType); diff --git a/src/com/android/providers/downloads/OpenHelper.java b/src/com/android/providers/downloads/OpenHelper.java index 27ab86b9..69a44922 100644 --- a/src/com/android/providers/downloads/OpenHelper.java +++ b/src/com/android/providers/downloads/OpenHelper.java @@ -17,10 +17,10 @@ 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; import static android.provider.Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI; + import static com.android.providers.downloads.Constants.TAG; import android.app.DownloadManager; @@ -30,7 +30,6 @@ import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; -import android.os.StrictMode; import android.provider.DocumentsContract; import android.provider.Downloads.Impl.RequestHeaders; import android.util.Log; @@ -51,14 +50,11 @@ public class OpenHelper { intent.addFlags(intentFlags); try { - StrictMode.disableDeathOnFileUriExposure(); context.startActivity(intent); return true; } catch (ActivityNotFoundException e) { Log.w(TAG, "Failed to start " + intent + ": " + e); return false; - } finally { - StrictMode.enableDeathOnFileUriExposure(); } } @@ -78,7 +74,6 @@ public class OpenHelper { return null; } - final Uri localUri = getCursorUri(cursor, COLUMN_LOCAL_URI); final File file = getCursorFile(cursor, COLUMN_LOCAL_FILENAME); String mimeType = getCursorString(cursor, COLUMN_MEDIA_TYPE); mimeType = DownloadDrmHelper.getOriginalMimeType(context, file, mimeType); @@ -87,20 +82,16 @@ public class OpenHelper { Constants.STORAGE_AUTHORITY, String.valueOf(id)); final Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(documentUri, mimeType); + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_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)); intent.putExtra(Intent.EXTRA_ORIGINATING_UID, getOriginatingUid(context, id)); - } else { - intent.setDataAndType(documentUri, mimeType); - intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION - | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } return intent; diff --git a/ui/res/values-my-rMM/strings.xml b/ui/res/values-my-rMM/strings.xml index 5d286723..ba7bfcc5 100644 --- a/ui/res/values-my-rMM/strings.xml +++ b/ui/res/values-my-rMM/strings.xml @@ -39,9 +39,9 @@ <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="delete_download" msgid="76629022653866471">"ဖျက်ရန်"</string> <string name="keep_queued_download" msgid="5144882786014818569">"သိမ်းထားပါ"</string> - <string name="cancel_running_download" msgid="5232704030969221112">"မလုပ်တော့ပါ"</string> + <string name="cancel_running_download" msgid="5232704030969221112">"မလုပ်တော့"</string> <string name="retry_download" msgid="7617100787922717912">"ပြန်ကြိုးစားပါ"</string> <string name="start_now_download" msgid="1564642872809509681">"ယခု စတင်ပါ"</string> <string name="deselect_all" msgid="6348198946254776764">"ဘာကိုမှ မရွေးပါ"</string> |