summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/downloads/DownloadService.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/providers/downloads/DownloadService.java')
-rw-r--r--src/com/android/providers/downloads/DownloadService.java545
1 files changed, 128 insertions, 417 deletions
diff --git a/src/com/android/providers/downloads/DownloadService.java b/src/com/android/providers/downloads/DownloadService.java
index b85fb902..62598b7c 100644
--- a/src/com/android/providers/downloads/DownloadService.java
+++ b/src/com/android/providers/downloads/DownloadService.java
@@ -25,12 +25,8 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.database.CharArrayBuffer;
import android.database.ContentObserver;
import android.database.Cursor;
-import android.drm.mobile1.DrmRawContent;
import android.media.IMediaScannerService;
import android.net.Uri;
import android.os.Environment;
@@ -39,27 +35,22 @@ import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.provider.Downloads;
-import android.util.Config;
import android.util.Log;
-import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
import com.google.common.annotations.VisibleForTesting;
import java.io.File;
-import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
/**
* Performs the background downloads requested by applications that use the Downloads provider.
*/
public class DownloadService extends Service {
-
- /* ------------ Constants ------------ */
-
- /* ------------ Members ------------ */
-
/** Observer to get notified when the content observer's data changes */
private DownloadManagerContentObserver mObserver;
@@ -67,12 +58,12 @@ public class DownloadService extends Service {
private DownloadNotification mNotifier;
/**
- * The Service's view of the list of downloads. This is kept independently
- * from the content provider, and the Service only initiates downloads
- * based on this data, so that it can deal with situation where the data
- * in the content provider changes or disappears.
+ * The Service's view of the list of downloads, mapping download IDs to the corresponding info
+ * object. This is kept independently from the content provider, and the Service only initiates
+ * downloads based on this data, so that it can deal with situation where the data in the
+ * content provider changes or disappears.
*/
- private ArrayList<DownloadInfo> mDownloads;
+ private Map<Long, DownloadInfo> mDownloads = Maps.newHashMap();
/**
* The thread that updates the internal download list from the content
@@ -100,21 +91,9 @@ public class DownloadService extends Service {
*/
private IMediaScannerService mMediaScannerService;
- /**
- * Array used when extracting strings from content provider
- */
- private CharArrayBuffer oldChars;
-
- /**
- * Array used when extracting strings from content provider
- */
- private CharArrayBuffer mNewChars;
-
@VisibleForTesting
SystemFacade mSystemFacade;
- /* ------------ Inner Classes ------------ */
-
/**
* Receives notifications when the data in the content provider changes
*/
@@ -183,8 +162,6 @@ public class DownloadService extends Service {
}
}
- /* ------------ Methods ------------ */
-
/**
* Returns an IBinder instance when someone wants to connect to this
* service. Binding to this service is not allowed.
@@ -208,8 +185,6 @@ public class DownloadService extends Service {
mSystemFacade = new RealSystemFacade(this);
}
- mDownloads = Lists.newArrayList();
-
mObserver = new DownloadManagerContentObserver();
getContentResolver().registerContentObserver(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
true, mObserver);
@@ -220,23 +195,20 @@ public class DownloadService extends Service {
mNotifier = new DownloadNotification(this, mSystemFacade);
mSystemFacade.cancelAllNotifications();
- mNotifier.updateNotification(mDownloads);
trimDatabase();
removeSpuriousFiles();
updateFromProvider();
}
- /**
- * Responds to a call to startService
- */
- public void onStart(Intent intent, int startId) {
- super.onStart(intent, startId);
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ int returnValue = super.onStartCommand(intent, flags, startId);
if (Constants.LOGVV) {
Log.v(Constants.TAG, "Service onStart");
}
-
updateFromProvider();
+ return returnValue;
}
/**
@@ -287,189 +259,101 @@ public class DownloadService extends Service {
stopSelf();
}
if (wakeUp != Long.MAX_VALUE) {
- AlarmManager alarms =
- (AlarmManager) getSystemService(Context.ALARM_SERVICE);
- if (alarms == null) {
- Log.e(Constants.TAG, "couldn't get alarm manager");
- } else {
- if (Constants.LOGV) {
- Log.v(Constants.TAG, "scheduling retry in " + wakeUp + "ms");
- }
- Intent intent = new Intent(Constants.ACTION_RETRY);
- intent.setClassName("com.android.providers.downloads",
- DownloadReceiver.class.getName());
- alarms.set(
- AlarmManager.RTC_WAKEUP,
- mSystemFacade.currentTimeMillis() + wakeUp,
- PendingIntent.getBroadcast(DownloadService.this, 0, intent,
- PendingIntent.FLAG_ONE_SHOT));
- }
+ scheduleAlarm(wakeUp);
}
- oldChars = null;
- mNewChars = null;
return;
}
mPendingUpdate = false;
}
+
long now = mSystemFacade.currentTimeMillis();
+ boolean mustScan = false;
+ keepService = false;
+ wakeUp = Long.MAX_VALUE;
+ Set<Long> idsNoLongerInDatabase = new HashSet<Long>(mDownloads.keySet());
Cursor cursor = getContentResolver().query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
- null, null, null, Downloads.Impl._ID);
-
+ null, null, null, null);
if (cursor == null) {
- // TODO: this doesn't look right, it'd leave the loop in an inconsistent state
- return;
+ continue;
}
+ try {
+ DownloadInfo.Reader reader =
+ new DownloadInfo.Reader(getContentResolver(), cursor);
+ int idColumn = cursor.getColumnIndexOrThrow(Downloads.Impl._ID);
+
+ for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+ long id = cursor.getLong(idColumn);
+ idsNoLongerInDatabase.remove(id);
+ DownloadInfo info = mDownloads.get(id);
+ if (info != null) {
+ updateDownload(reader, info, now);
+ } else {
+ info = insertDownload(reader, now);
+ }
- cursor.moveToFirst();
-
- int arrayPos = 0;
-
- boolean mustScan = false;
- keepService = false;
- wakeUp = Long.MAX_VALUE;
-
- boolean isAfterLast = cursor.isAfterLast();
-
- int idColumn = cursor.getColumnIndexOrThrow(Downloads.Impl._ID);
-
- /*
- * Walk the cursor and the local array to keep them in sync. The key
- * to the algorithm is that the ids are unique and sorted both in
- * the cursor and in the array, so that they can be processed in
- * order in both sources at the same time: at each step, both
- * sources point to the lowest id that hasn't been processed from
- * that source, and the algorithm processes the lowest id from
- * those two possibilities.
- * At each step:
- * -If the array contains an entry that's not in the cursor, remove the
- * entry, move to next entry in the array.
- * -If the array contains an entry that's in the cursor, nothing to do,
- * move to next cursor row and next array entry.
- * -If the cursor contains an entry that's not in the array, insert
- * a new entry in the array, move to next cursor row and next
- * array entry.
- */
- while (!isAfterLast || arrayPos < mDownloads.size()) {
- if (isAfterLast) {
- // We're beyond the end of the cursor but there's still some
- // stuff in the local array, which can only be junk
- if (Constants.LOGVV) {
- int arrayId = ((DownloadInfo) mDownloads.get(arrayPos)).mId;
- Log.v(Constants.TAG, "Array update: trimming " +
- arrayId + " @ " + arrayPos);
+ if (info.shouldScanFile() && !scanFile(info, true)) {
+ mustScan = true;
+ keepService = true;
}
- if (shouldScanFile(arrayPos) && mediaScannerConnected()) {
- scanFile(null, arrayPos);
+ if (info.hasCompletionNotification()) {
+ keepService = true;
}
- deleteDownload(arrayPos); // this advances in the array
- } else {
- int id = cursor.getInt(idColumn);
-
- if (arrayPos == mDownloads.size()) {
- insertDownload(cursor, arrayPos, now);
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "Array update: appending " +
- id + " @ " + arrayPos);
- }
- if (shouldScanFile(arrayPos)
- && (!mediaScannerConnected() || !scanFile(cursor, arrayPos))) {
- mustScan = true;
- keepService = true;
- }
- if (visibleNotification(arrayPos)) {
- keepService = true;
- }
- long next = nextAction(arrayPos, now);
- if (next == 0) {
- keepService = true;
- } else if (next > 0 && next < wakeUp) {
- wakeUp = next;
- }
- ++arrayPos;
- cursor.moveToNext();
- isAfterLast = cursor.isAfterLast();
- } else {
- int arrayId = mDownloads.get(arrayPos).mId;
-
- if (arrayId < id) {
- // The array entry isn't in the cursor
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "Array update: removing " + arrayId
- + " @ " + arrayPos);
- }
- if (shouldScanFile(arrayPos) && mediaScannerConnected()) {
- scanFile(null, arrayPos);
- }
- deleteDownload(arrayPos); // this advances in the array
- } else if (arrayId == id) {
- // This cursor row already exists in the stored array
- updateDownload(cursor, arrayPos, now);
- if (shouldScanFile(arrayPos)
- && (!mediaScannerConnected()
- || !scanFile(cursor, arrayPos))) {
- mustScan = true;
- keepService = true;
- }
- if (visibleNotification(arrayPos)) {
- keepService = true;
- }
- long next = nextAction(arrayPos, now);
- if (next == 0) {
- keepService = true;
- } else if (next > 0 && next < wakeUp) {
- wakeUp = next;
- }
- ++arrayPos;
- cursor.moveToNext();
- isAfterLast = cursor.isAfterLast();
- } else {
- // This cursor entry didn't exist in the stored array
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "Array update: inserting " +
- id + " @ " + arrayPos);
- }
- insertDownload(cursor, arrayPos, now);
- if (shouldScanFile(arrayPos)
- && (!mediaScannerConnected()
- || !scanFile(cursor, arrayPos))) {
- mustScan = true;
- keepService = true;
- }
- if (visibleNotification(arrayPos)) {
- keepService = true;
- }
- long next = nextAction(arrayPos, now);
- if (next == 0) {
- keepService = true;
- } else if (next > 0 && next < wakeUp) {
- wakeUp = next;
- }
- ++arrayPos;
- cursor.moveToNext();
- isAfterLast = cursor.isAfterLast();
- }
+ long next = info.nextAction(now);
+ if (next == 0) {
+ keepService = true;
+ } else if (next > 0 && next < wakeUp) {
+ wakeUp = next;
}
}
+ } finally {
+ cursor.close();
+ }
+
+ for (Long id : idsNoLongerInDatabase) {
+ deleteDownload(id);
}
- mNotifier.updateNotification(mDownloads);
+ mNotifier.updateNotification(mDownloads.values());
if (mustScan) {
- if (!mMediaScannerConnecting) {
- Intent intent = new Intent();
- intent.setClassName("com.android.providers.media",
- "com.android.providers.media.MediaScannerService");
- mMediaScannerConnecting = true;
- bindService(intent, mMediaScannerConnection, BIND_AUTO_CREATE);
- }
+ bindMediaScanner();
} else {
mMediaScannerConnection.disconnectMediaScanner();
}
+ }
+ }
- cursor.close();
+ private void bindMediaScanner() {
+ if (!mMediaScannerConnecting) {
+ Intent intent = new Intent();
+ intent.setClassName("com.android.providers.media",
+ "com.android.providers.media.MediaScannerService");
+ mMediaScannerConnecting = true;
+ bindService(intent, mMediaScannerConnection, BIND_AUTO_CREATE);
}
}
+
+ private void scheduleAlarm(long wakeUp) {
+ AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+ if (alarms == null) {
+ Log.e(Constants.TAG, "couldn't get alarm manager");
+ return;
+ }
+
+ if (Constants.LOGV) {
+ Log.v(Constants.TAG, "scheduling retry in " + wakeUp + "ms");
+ }
+
+ Intent intent = new Intent(Constants.ACTION_RETRY);
+ intent.setClassName("com.android.providers.downloads",
+ DownloadReceiver.class.getName());
+ alarms.set(
+ AlarmManager.RTC_WAKEUP,
+ mSystemFacade.currentTimeMillis() + wakeUp,
+ PendingIntent.getBroadcast(DownloadService.this, 0, intent,
+ PendingIntent.FLAG_ONE_SHOT));
+ }
}
/**
@@ -546,133 +430,40 @@ public class DownloadService extends Service {
* Keeps a local copy of the info about a download, and initiates the
* download if appropriate.
*/
- private void insertDownload(Cursor cursor, int arrayPos, long now) {
- DownloadInfo info = new DownloadInfo(this, mSystemFacade, cursor);
+ private DownloadInfo insertDownload(DownloadInfo.Reader reader, long now) {
+ DownloadInfo info = reader.newDownloadInfo(this, mSystemFacade);
+ mDownloads.put(info.mId, info);
if (Constants.LOGVV) {
- Log.v(Constants.TAG, "Service adding new entry");
- Log.v(Constants.TAG, "ID : " + info.mId);
- Log.v(Constants.TAG, "URI : " + ((info.mUri != null) ? "yes" : "no"));
- Log.v(Constants.TAG, "NO_INTEG: " + info.mNoIntegrity);
- Log.v(Constants.TAG, "HINT : " + info.mHint);
- Log.v(Constants.TAG, "FILENAME: " + info.mFileName);
- Log.v(Constants.TAG, "MIMETYPE: " + info.mMimeType);
- Log.v(Constants.TAG, "DESTINAT: " + info.mDestination);
- Log.v(Constants.TAG, "VISIBILI: " + info.mVisibility);
- Log.v(Constants.TAG, "CONTROL : " + info.mControl);
- Log.v(Constants.TAG, "STATUS : " + info.mStatus);
- Log.v(Constants.TAG, "FAILED_C: " + info.mNumFailed);
- Log.v(Constants.TAG, "RETRY_AF: " + info.mRetryAfter);
- Log.v(Constants.TAG, "REDIRECT: " + info.mRedirectCount);
- Log.v(Constants.TAG, "LAST_MOD: " + info.mLastMod);
- Log.v(Constants.TAG, "PACKAGE : " + info.mPackage);
- Log.v(Constants.TAG, "CLASS : " + info.mClass);
- Log.v(Constants.TAG, "COOKIES : " + ((info.mCookies != null) ? "yes" : "no"));
- Log.v(Constants.TAG, "AGENT : " + info.mUserAgent);
- Log.v(Constants.TAG, "REFERER : " + ((info.mReferer != null) ? "yes" : "no"));
- Log.v(Constants.TAG, "TOTAL : " + info.mTotalBytes);
- Log.v(Constants.TAG, "CURRENT : " + info.mCurrentBytes);
- Log.v(Constants.TAG, "ETAG : " + info.mETag);
- Log.v(Constants.TAG, "SCANNED : " + info.mMediaScanned);
- }
-
- mDownloads.add(arrayPos, info);
-
- if (info.mStatus == 0
- && (info.mDestination == Downloads.Impl.DESTINATION_EXTERNAL
- || info.mDestination == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE)
- && info.mMimeType != null
- && !DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(info.mMimeType)) {
- // Check to see if we are allowed to download this file. Only files
- // that can be handled by the platform can be downloaded.
- // special case DRM files, which we should always allow downloading.
- Intent mimetypeIntent = new Intent(Intent.ACTION_VIEW);
-
- // We can provide data as either content: or file: URIs,
- // so allow both. (I think it would be nice if we just did
- // everything as content: URIs)
- // Actually, right now the download manager's UId restrictions
- // prevent use from using content: so it's got to be file: or
- // nothing
-
- mimetypeIntent.setDataAndType(Uri.fromParts("file", "", null), info.mMimeType);
- ResolveInfo ri = getPackageManager().resolveActivity(mimetypeIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
- //Log.i(Constants.TAG, "*** QUERY " + mimetypeIntent + ": " + list);
-
- if (ri == null) {
- Log.d(Constants.TAG, "no application to handle MIME type " + info.mMimeType);
- info.mStatus = Downloads.Impl.STATUS_NOT_ACCEPTABLE;
-
- ContentValues values = new ContentValues();
- values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_NOT_ACCEPTABLE);
- getContentResolver().update(info.getAllDownloadsUri(), values, null, null);
- info.sendIntentIfRequested();
- return;
- }
+ info.logVerboseInfo();
}
if (info.isReadyToStart(now)) {
info.start(now);
}
+
+ return info;
}
/**
* Updates the local copy of the info about a download.
*/
- private void updateDownload(Cursor cursor, int arrayPos, long now) {
- DownloadInfo info = mDownloads.get(arrayPos);
- int statusColumn = cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS);
- int failedColumn = cursor.getColumnIndexOrThrow(Constants.FAILED_CONNECTIONS);
- info.mId = cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl._ID));
- info.mUri = stringFromCursor(info.mUri, cursor, Downloads.Impl.COLUMN_URI);
- info.mNoIntegrity = cursor.getInt(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_NO_INTEGRITY)) == 1;
- info.mHint = stringFromCursor(info.mHint, cursor, Downloads.Impl.COLUMN_FILE_NAME_HINT);
- info.mFileName = stringFromCursor(info.mFileName, cursor, Downloads.Impl._DATA);
- info.mMimeType = stringFromCursor(info.mMimeType, cursor, Downloads.Impl.COLUMN_MIME_TYPE);
- info.mDestination = cursor.getInt(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_DESTINATION));
- int newVisibility = cursor.getInt(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_VISIBILITY));
- if (info.mVisibility == Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED
- && newVisibility != Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED
- && Downloads.Impl.isStatusCompleted(info.mStatus)) {
- mSystemFacade.cancelNotification(info.mId);
- }
- info.mVisibility = newVisibility;
- synchronized (info) {
- info.mControl = cursor.getInt(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_CONTROL));
- }
- int newStatus = cursor.getInt(statusColumn);
- if (!Downloads.Impl.isStatusCompleted(info.mStatus) &&
- Downloads.Impl.isStatusCompleted(newStatus)) {
+ private void updateDownload(DownloadInfo.Reader reader, DownloadInfo info, long now) {
+ int oldVisibility = info.mVisibility;
+ int oldStatus = info.mStatus;
+
+ reader.updateFromDatabase(info);
+
+ boolean lostVisibility =
+ oldVisibility == Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED
+ && info.mVisibility != Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED
+ && Downloads.Impl.isStatusCompleted(info.mStatus);
+ boolean justCompleted =
+ !Downloads.Impl.isStatusCompleted(oldStatus)
+ && Downloads.Impl.isStatusCompleted(info.mStatus);
+ if (lostVisibility || justCompleted) {
mSystemFacade.cancelNotification(info.mId);
}
- info.mStatus = newStatus;
- info.mNumFailed = cursor.getInt(failedColumn);
- int retryRedirect =
- cursor.getInt(cursor.getColumnIndexOrThrow(Constants.RETRY_AFTER_X_REDIRECT_COUNT));
- info.mRetryAfter = retryRedirect & 0xfffffff;
- info.mRedirectCount = retryRedirect >> 28;
- info.mLastMod = cursor.getLong(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_LAST_MODIFICATION));
- info.mPackage = stringFromCursor(
- info.mPackage, cursor, Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE);
- info.mClass = stringFromCursor(
- info.mClass, cursor, Downloads.Impl.COLUMN_NOTIFICATION_CLASS);
- info.mCookies = stringFromCursor(info.mCookies, cursor, Downloads.Impl.COLUMN_COOKIE_DATA);
- info.mUserAgent = stringFromCursor(
- info.mUserAgent, cursor, Downloads.Impl.COLUMN_USER_AGENT);
- info.mReferer = stringFromCursor(info.mReferer, cursor, Downloads.Impl.COLUMN_REFERER);
- info.mTotalBytes = cursor.getInt(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_TOTAL_BYTES));
- info.mCurrentBytes = cursor.getInt(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_CURRENT_BYTES));
- info.mETag = stringFromCursor(info.mETag, cursor, Constants.ETAG);
- info.mMediaScanned =
- cursor.getInt(cursor.getColumnIndexOrThrow(Constants.MEDIA_SCANNED)) == 1;
if (info.isReadyToRestart(now)) {
info.start(now);
@@ -680,128 +471,48 @@ public class DownloadService extends Service {
}
/**
- * Returns a String that holds the current value of the column,
- * optimizing for the case where the value hasn't changed.
- */
- private String stringFromCursor(String old, Cursor cursor, String column) {
- int index = cursor.getColumnIndexOrThrow(column);
- if (old == null) {
- return cursor.getString(index);
- }
- if (mNewChars == null) {
- mNewChars = new CharArrayBuffer(128);
- }
- cursor.copyStringToBuffer(index, mNewChars);
- int length = mNewChars.sizeCopied;
- if (length != old.length()) {
- return cursor.getString(index);
- }
- if (oldChars == null || oldChars.sizeCopied < length) {
- oldChars = new CharArrayBuffer(length);
- }
- char[] oldArray = oldChars.data;
- char[] newArray = mNewChars.data;
- old.getChars(0, length, oldArray, 0);
- for (int i = length - 1; i >= 0; --i) {
- if (oldArray[i] != newArray[i]) {
- return new String(newArray, 0, length);
- }
- }
- return old;
- }
-
- /**
* Removes the local copy of the info about a download.
*/
- private void deleteDownload(int arrayPos) {
- DownloadInfo info = (DownloadInfo) mDownloads.get(arrayPos);
+ private void deleteDownload(long id) {
+ DownloadInfo info = mDownloads.get(id);
+ if (info.shouldScanFile()) {
+ scanFile(info, false);
+ }
if (info.mStatus == Downloads.Impl.STATUS_RUNNING) {
info.mStatus = Downloads.Impl.STATUS_CANCELED;
- } else if (info.mDestination != Downloads.Impl.DESTINATION_EXTERNAL
- && info.mFileName != null) {
+ }
+ if (info.mDestination != Downloads.Impl.DESTINATION_EXTERNAL && info.mFileName != null) {
new File(info.mFileName).delete();
}
mSystemFacade.cancelNotification(info.mId);
-
- mDownloads.remove(arrayPos);
- }
-
- /**
- * Returns the amount of time (as measured from the "now" parameter)
- * at which a download will be active.
- * 0 = immediately - service should stick around to handle this download.
- * -1 = never - service can go away without ever waking up.
- * positive value - service must wake up in the future, as specified in ms from "now"
- */
- private long nextAction(int arrayPos, long now) {
- DownloadInfo info = (DownloadInfo) mDownloads.get(arrayPos);
- if (Downloads.Impl.isStatusCompleted(info.mStatus)) {
- return -1;
- }
- if (info.mStatus != Downloads.Impl.STATUS_RUNNING_PAUSED) {
- return 0;
- }
- if (info.mNumFailed == 0) {
- return 0;
- }
- long when = info.restartTime();
- if (when <= now) {
- return 0;
- }
- return when - now;
- }
-
- /**
- * Returns whether there's a visible notification for this download
- */
- private boolean visibleNotification(int arrayPos) {
- DownloadInfo info = (DownloadInfo) mDownloads.get(arrayPos);
- return info.hasCompletionNotification();
- }
-
- /**
- * Returns whether a file should be scanned
- */
- private boolean shouldScanFile(int arrayPos) {
- DownloadInfo info = (DownloadInfo) mDownloads.get(arrayPos);
- return !info.mMediaScanned
- && info.mDestination == Downloads.Impl.DESTINATION_EXTERNAL
- && Downloads.Impl.isStatusSuccess(info.mStatus)
- && !DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(info.mMimeType);
- }
-
- /**
- * Returns whether we have a live connection to the Media Scanner
- */
- private boolean mediaScannerConnected() {
- return mMediaScannerService != null;
+ mDownloads.remove(info.mId);
}
/**
* Attempts to scan the file if necessary.
- * Returns true if the file has been properly scanned.
+ * @return true if the file has been properly scanned.
*/
- private boolean scanFile(Cursor cursor, int arrayPos) {
- DownloadInfo info = mDownloads.get(arrayPos);
+ private boolean scanFile(DownloadInfo info, boolean updateDatabase) {
synchronized (this) {
- if (mMediaScannerService != null) {
- try {
- if (Constants.LOGV) {
- Log.v(Constants.TAG, "Scanning file " + info.mFileName);
- }
- mMediaScannerService.scanFile(info.mFileName, info.mMimeType);
- if (cursor != null) {
- ContentValues values = new ContentValues();
- values.put(Constants.MEDIA_SCANNED, 1);
- getContentResolver().update(info.getAllDownloadsUri(), values, null, null);
- }
- return true;
- } catch (RemoteException e) {
- Log.d(Constants.TAG, "Failed to scan file " + info.mFileName);
+ if (mMediaScannerService == null) {
+ return false;
+ }
+ try {
+ if (Constants.LOGV) {
+ Log.v(Constants.TAG, "Scanning file " + info.mFileName);
+ }
+ mMediaScannerService.scanFile(info.mFileName, info.mMimeType);
+ if (updateDatabase) {
+ ContentValues values = new ContentValues();
+ values.put(Constants.MEDIA_SCANNED, 1);
+ getContentResolver().update(info.getAllDownloadsUri(), values, null, null);
}
+ return true;
+ } catch (RemoteException e) {
+ Log.d(Constants.TAG, "Failed to scan file " + info.mFileName);
+ return false;
}
}
- return false;
}
}