summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/downloads/DownloadInfo.java
diff options
context:
space:
mode:
authorSteve Howard <showard@google.com>2010-09-15 12:29:50 -0700
committerSteve Howard <showard@google.com>2010-09-20 11:34:54 -0700
commit3398db8f3b195959faa2a7cf09918f364432ac28 (patch)
treeb274d3f30d22bb3d56100cb18e3ade5a83c91b71 /src/com/android/providers/downloads/DownloadInfo.java
parent4bebe75b3e2361d7fb0aa966598c41c45ad9317f (diff)
downloadandroid_packages_providers_DownloadProvider-3398db8f3b195959faa2a7cf09918f364432ac28.tar.gz
android_packages_providers_DownloadProvider-3398db8f3b195959faa2a7cf09918f364432ac28.tar.bz2
android_packages_providers_DownloadProvider-3398db8f3b195959faa2a7cf09918f364432ac28.zip
Fix notification bugs, cleanup DownloadService + DownloadReceiver
This change started out just fixing a few regressions related to notifications: * Browser downloads weren't picking up a title from the determined filename. This was due to my change to default the title field to "" instead of null. * Notification click/hide events weren't being handled properly. This was due to previous change to the URI structure of DownloadProvider. DownloadReceiver needed to be changed to perform queries through /all_downloads URIs, like all other parts of the download manager code. I did some general refactoring of the DownloadReceiver code while I was there. * The code in DownloadNotification wasn't picking up some updates to downloads properly. This was due to my change to make DownloadNotification use the DownloadInfo objects rather than querying the database directly, so that it could make use of info provided by the DownloadThread that didn't go into the DB. Fixing this didn't turn out to be all that complicated, but along the way to figuring this out I made some substantial refactoring in DownloadService which made it much cleaner anyway and eliminated a lot of duplication. That's something that had to happen eventually, so I'm leaving it all in. Change-Id: I847ccf80e3d928c84e36bc24791b33204104e1b2
Diffstat (limited to 'src/com/android/providers/downloads/DownloadInfo.java')
-rw-r--r--src/com/android/providers/downloads/DownloadInfo.java264
1 files changed, 188 insertions, 76 deletions
diff --git a/src/com/android/providers/downloads/DownloadInfo.java b/src/com/android/providers/downloads/DownloadInfo.java
index 0cf025b8..eb9ac4bd 100644
--- a/src/com/android/providers/downloads/DownloadInfo.java
+++ b/src/com/android/providers/downloads/DownloadInfo.java
@@ -16,11 +16,14 @@
package com.android.providers.downloads;
+import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.database.CharArrayBuffer;
import android.database.Cursor;
+import android.drm.mobile1.DrmRawContent;
import android.net.ConnectivityManager;
import android.net.DownloadManager;
import android.net.Uri;
@@ -36,7 +39,127 @@ import java.util.Map;
* Stores information about an individual download.
*/
public class DownloadInfo {
- public int mId;
+ public static class Reader {
+ private ContentResolver mResolver;
+ private Cursor mCursor;
+ private CharArrayBuffer mOldChars;
+ private CharArrayBuffer mNewChars;
+
+ public Reader(ContentResolver resolver, Cursor cursor) {
+ mResolver = resolver;
+ mCursor = cursor;
+ }
+
+ public DownloadInfo newDownloadInfo(Context context, SystemFacade systemFacade) {
+ DownloadInfo info = new DownloadInfo(context, systemFacade);
+ updateFromDatabase(info);
+ readRequestHeaders(info);
+ return info;
+ }
+
+ public void updateFromDatabase(DownloadInfo info) {
+ info.mId = getLong(Downloads.Impl._ID);
+ info.mUri = getString(info.mUri, Downloads.Impl.COLUMN_URI);
+ info.mNoIntegrity = getInt(Downloads.Impl.COLUMN_NO_INTEGRITY) == 1;
+ info.mHint = getString(info.mHint, Downloads.Impl.COLUMN_FILE_NAME_HINT);
+ info.mFileName = getString(info.mFileName, Downloads.Impl._DATA);
+ info.mMimeType = getString(info.mMimeType, Downloads.Impl.COLUMN_MIME_TYPE);
+ info.mDestination = getInt(Downloads.Impl.COLUMN_DESTINATION);
+ info.mVisibility = getInt(Downloads.Impl.COLUMN_VISIBILITY);
+ info.mStatus = getInt(Downloads.Impl.COLUMN_STATUS);
+ info.mNumFailed = getInt(Constants.FAILED_CONNECTIONS);
+ int retryRedirect = getInt(Constants.RETRY_AFTER_X_REDIRECT_COUNT);
+ info.mRetryAfter = retryRedirect & 0xfffffff;
+ info.mRedirectCount = retryRedirect >> 28;
+ info.mLastMod = getLong(Downloads.Impl.COLUMN_LAST_MODIFICATION);
+ info.mPackage = getString(info.mPackage, Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE);
+ info.mClass = getString(info.mClass, Downloads.Impl.COLUMN_NOTIFICATION_CLASS);
+ info.mExtras = getString(info.mExtras, Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS);
+ info.mCookies = getString(info.mCookies, Downloads.Impl.COLUMN_COOKIE_DATA);
+ info.mUserAgent = getString(info.mUserAgent, Downloads.Impl.COLUMN_USER_AGENT);
+ info.mReferer = getString(info.mReferer, Downloads.Impl.COLUMN_REFERER);
+ info.mTotalBytes = getLong(Downloads.Impl.COLUMN_TOTAL_BYTES);
+ info.mCurrentBytes = getLong(Downloads.Impl.COLUMN_CURRENT_BYTES);
+ info.mETag = getString(info.mETag, Constants.ETAG);
+ info.mMediaScanned = getInt(Constants.MEDIA_SCANNED) == 1;
+ info.mIsPublicApi = getInt(Downloads.Impl.COLUMN_IS_PUBLIC_API) != 0;
+ info.mAllowedNetworkTypes = getInt(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES);
+ info.mAllowRoaming = getInt(Downloads.Impl.COLUMN_ALLOW_ROAMING) != 0;
+ info.mTitle = getString(info.mTitle, Downloads.Impl.COLUMN_TITLE);
+ info.mDescription = getString(info.mDescription, Downloads.Impl.COLUMN_DESCRIPTION);
+
+ synchronized (this) {
+ info.mControl = getInt(Downloads.Impl.COLUMN_CONTROL);
+ }
+ }
+
+ private void readRequestHeaders(DownloadInfo info) {
+ info.mRequestHeaders.clear();
+ Uri headerUri = Uri.withAppendedPath(
+ info.getAllDownloadsUri(), Downloads.Impl.RequestHeaders.URI_SEGMENT);
+ Cursor cursor = mResolver.query(headerUri, null, null, null, null);
+ try {
+ int headerIndex =
+ cursor.getColumnIndexOrThrow(Downloads.Impl.RequestHeaders.COLUMN_HEADER);
+ int valueIndex =
+ cursor.getColumnIndexOrThrow(Downloads.Impl.RequestHeaders.COLUMN_VALUE);
+ for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+ info.mRequestHeaders.put(
+ cursor.getString(headerIndex), cursor.getString(valueIndex));
+ }
+ } finally {
+ cursor.close();
+ }
+
+ if (info.mCookies != null) {
+ info.mRequestHeaders.put("Cookie", info.mCookies);
+ }
+ if (info.mReferer != null) {
+ info.mRequestHeaders.put("Referer", info.mReferer);
+ }
+ }
+
+ /**
+ * Returns a String that holds the current value of the column, optimizing for the case
+ * where the value hasn't changed.
+ */
+ private String getString(String old, String column) {
+ int index = mCursor.getColumnIndexOrThrow(column);
+ if (old == null) {
+ return mCursor.getString(index);
+ }
+ if (mNewChars == null) {
+ mNewChars = new CharArrayBuffer(128);
+ }
+ mCursor.copyStringToBuffer(index, mNewChars);
+ int length = mNewChars.sizeCopied;
+ if (length != old.length()) {
+ return new String(mNewChars.data, 0, length);
+ }
+ if (mOldChars == null || mOldChars.sizeCopied < length) {
+ mOldChars = new CharArrayBuffer(length);
+ }
+ char[] oldArray = mOldChars.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;
+ }
+
+ private Integer getInt(String column) {
+ return mCursor.getInt(mCursor.getColumnIndexOrThrow(column));
+ }
+
+ private Long getLong(String column) {
+ return mCursor.getLong(mCursor.getColumnIndexOrThrow(column));
+ }
+ }
+
+ public long mId;
public String mUri;
public boolean mNoIntegrity;
public String mHint;
@@ -75,83 +198,10 @@ public class DownloadInfo {
private SystemFacade mSystemFacade;
private Context mContext;
- public DownloadInfo(Context context, SystemFacade systemFacade, Cursor cursor) {
+ private DownloadInfo(Context context, SystemFacade systemFacade) {
mContext = context;
mSystemFacade = systemFacade;
-
- int retryRedirect =
- cursor.getInt(cursor.getColumnIndexOrThrow(Constants.RETRY_AFTER_X_REDIRECT_COUNT));
- mId = cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl._ID));
- mUri = cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_URI));
- mNoIntegrity = cursor.getInt(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_NO_INTEGRITY)) == 1;
- mHint = cursor.getString(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_FILE_NAME_HINT));
- mFileName = cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl._DATA));
- mMimeType = cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_MIME_TYPE));
- mDestination =
- cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_DESTINATION));
- mVisibility = cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_VISIBILITY));
- mControl = cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_CONTROL));
- mStatus = cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS));
- mNumFailed = cursor.getInt(cursor.getColumnIndexOrThrow(Constants.FAILED_CONNECTIONS));
- mRetryAfter = retryRedirect & 0xfffffff;
- mRedirectCount = retryRedirect >> 28;
- mLastMod = cursor.getLong(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_LAST_MODIFICATION));
- mPackage = cursor.getString(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE));
- mClass = cursor.getString(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_NOTIFICATION_CLASS));
- mExtras = cursor.getString(cursor.getColumnIndexOrThrow(
- Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS));
- mCookies =
- cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_COOKIE_DATA));
- mUserAgent =
- cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_USER_AGENT));
- mReferer = cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_REFERER));
- mTotalBytes =
- cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_TOTAL_BYTES));
- mCurrentBytes =
- cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_CURRENT_BYTES));
- mETag = cursor.getString(cursor.getColumnIndexOrThrow(Constants.ETAG));
- mMediaScanned = cursor.getInt(cursor.getColumnIndexOrThrow(Constants.MEDIA_SCANNED)) == 1;
- mIsPublicApi = cursor.getInt(
- cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_IS_PUBLIC_API)) != 0;
- mAllowedNetworkTypes = cursor.getInt(
- cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES));
- mAllowRoaming = cursor.getInt(
- cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_ALLOW_ROAMING)) != 0;
- mTitle = cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_TITLE));
- mDescription =
- cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_DESCRIPTION));
mFuzz = Helpers.sRandom.nextInt(1001);
-
- readRequestHeaders(mId);
- }
-
- private void readRequestHeaders(long downloadId) {
- Uri headerUri = Uri.withAppendedPath(
- getAllDownloadsUri(), Downloads.Impl.RequestHeaders.URI_SEGMENT);
- Cursor cursor = mContext.getContentResolver().query(headerUri, null, null, null, null);
- try {
- int headerIndex =
- cursor.getColumnIndexOrThrow(Downloads.Impl.RequestHeaders.COLUMN_HEADER);
- int valueIndex =
- cursor.getColumnIndexOrThrow(Downloads.Impl.RequestHeaders.COLUMN_VALUE);
- for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
- mRequestHeaders.put(cursor.getString(headerIndex), cursor.getString(valueIndex));
- }
- } finally {
- cursor.close();
- }
-
- if (mCookies != null) {
- mRequestHeaders.put("Cookie", mCookies);
- }
- if (mReferer != null) {
- mRequestHeaders.put("Referer", mReferer);
- }
}
public Map<String, String> getHeaders() {
@@ -167,7 +217,7 @@ public class DownloadInfo {
if (mIsPublicApi) {
intent = new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
intent.setPackage(mPackage);
- intent.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, (long) mId);
+ intent.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, mId);
} else { // legacy behavior
if (mClass == null) {
return;
@@ -393,4 +443,66 @@ public class DownloadInfo {
public Uri getAllDownloadsUri() {
return ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, mId);
}
+
+
+ public void logVerboseInfo() {
+ Log.v(Constants.TAG, "Service adding new entry");
+ Log.v(Constants.TAG, "ID : " + mId);
+ Log.v(Constants.TAG, "URI : " + ((mUri != null) ? "yes" : "no"));
+ Log.v(Constants.TAG, "NO_INTEG: " + mNoIntegrity);
+ Log.v(Constants.TAG, "HINT : " + mHint);
+ Log.v(Constants.TAG, "FILENAME: " + mFileName);
+ Log.v(Constants.TAG, "MIMETYPE: " + mMimeType);
+ Log.v(Constants.TAG, "DESTINAT: " + mDestination);
+ Log.v(Constants.TAG, "VISIBILI: " + mVisibility);
+ Log.v(Constants.TAG, "CONTROL : " + mControl);
+ Log.v(Constants.TAG, "STATUS : " + mStatus);
+ Log.v(Constants.TAG, "FAILED_C: " + mNumFailed);
+ Log.v(Constants.TAG, "RETRY_AF: " + mRetryAfter);
+ Log.v(Constants.TAG, "REDIRECT: " + mRedirectCount);
+ Log.v(Constants.TAG, "LAST_MOD: " + mLastMod);
+ Log.v(Constants.TAG, "PACKAGE : " + mPackage);
+ Log.v(Constants.TAG, "CLASS : " + mClass);
+ Log.v(Constants.TAG, "COOKIES : " + ((mCookies != null) ? "yes" : "no"));
+ Log.v(Constants.TAG, "AGENT : " + mUserAgent);
+ Log.v(Constants.TAG, "REFERER : " + ((mReferer != null) ? "yes" : "no"));
+ Log.v(Constants.TAG, "TOTAL : " + mTotalBytes);
+ Log.v(Constants.TAG, "CURRENT : " + mCurrentBytes);
+ Log.v(Constants.TAG, "ETAG : " + mETag);
+ Log.v(Constants.TAG, "SCANNED : " + mMediaScanned);
+ }
+
+ /**
+ * 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"
+ */
+ long nextAction(long now) {
+ if (Downloads.Impl.isStatusCompleted(mStatus)) {
+ return -1;
+ }
+ if (mStatus != Downloads.Impl.STATUS_RUNNING_PAUSED) {
+ return 0;
+ }
+ if (mNumFailed == 0) {
+ return 0;
+ }
+ long when = restartTime();
+ if (when <= now) {
+ return 0;
+ }
+ return when - now;
+ }
+
+ /**
+ * Returns whether a file should be scanned
+ */
+ boolean shouldScanFile() {
+ return !mMediaScanned
+ && mDestination == Downloads.Impl.DESTINATION_EXTERNAL
+ && Downloads.Impl.isStatusSuccess(mStatus)
+ && !DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(mMimeType);
+ }
}