Commit cf79a11f authored by Jean-Baptiste Queru's avatar Jean-Baptiste Queru
Browse files

eclair snapshot

parent 89d4bc91
......@@ -19,14 +19,14 @@
<string name="permlab_downloadManager" msgid="7779544811202855500">"存取下載管理員。"</string>
<string name="permdesc_downloadManager" msgid="4240298564918160337">"允許應用程式存取下載管理員,並使用它下載檔案。請注意:惡意程式可能使用此功能,影響下載並存取個人資料。"</string>
<string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"下載管理員進階功能。"</string>
<string name="permdesc_downloadManagerAdvanced" msgid="8761177317775872287">"允許應用程式存取下載管理員的進階功能。"\n" 請注意:惡意應用程式可能使用此功能讓下載發生錯誤並存取私人資訊。"\n</string>
<string name="permdesc_downloadManagerAdvanced" msgid="6985743912436565114">"允許應用程式存取下載管理員的進階功能 (惡意應用程式可能會利用此功能讓下載發生錯誤並存取私人資訊)。"</string>
<string name="permlab_cacheFilesystem" msgid="6987994626343144212">"使用系統快取。"</string>
<string name="permdesc_cacheFilesystem" msgid="7301787168569544726">"允許應用程式直接存取、修改與刪除系統快取。請注意:惡意程式可能使用此功能,嚴重影響下載與其他應用程式,並存取個人資料。"</string>
<string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"傳送下載通知。"</string>
<string name="permdesc_downloadCompletedIntent" msgid="8672701687104399228">"下載完成時,允許應用程式送出通知。請注意:惡意程式可能使用此功能干擾其他下載檔案的應用程式。"</string>
<string name="download_unknown_title" msgid="7015124071247271585">"&lt;未命名&gt;"</string>
<string name="notification_filename_separator" msgid="7147189522857807618">", "</string>
<string name="notification_filename_extras" msgid="4790181201453108165">" 還有 %d 項下載"</string>
<string name="notification_filename_extras" msgid="5549729917695688191">" 以及其他 <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_download_complete" msgid="840713937779273632">"完成下載"</string>
<string name="notification_download_failed" msgid="5343637375905111462">"下載失敗"</string>
</resources>
......@@ -14,7 +14,7 @@
limitations under the License.
-->
<resources>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- This is the name of the Download Manager application. -->
<string name="app_label">Download Manager</string>
......@@ -51,7 +51,7 @@
system applications but aren't necessary for regular applications
that just initiate plain downloads. -->
<string name="permdesc_downloadManagerAdvanced">Allows the application to
access the download manager's advanced functions.
access the download manager\'s advanced functions.
Malicious applications can use this to disrupt downloads and access
private information.</string>
......@@ -102,7 +102,7 @@
downloads beyond the first two, i.e. "[title], [title] and [n] more".
This is the " and [n] more" part, including the leading space, and it's
used regardless of the number of additional downloads. -->
<string name="notification_filename_extras">" and %d more"</string>
<string name="notification_filename_extras">" and <xliff:g id="number" example="27">%d</xliff:g> more"</string>
<!-- When a download completes, a notification is displayed, and this
string is used to indicate that the download successfully completed.
......
......@@ -29,7 +29,7 @@ public class Constants {
public static final String TAG = "DownloadManager";
/** The column that used to be used for the HTTP method of the request */
public static final String RETRY_AFTER___REDIRECT_COUNT = "method";
public static final String RETRY_AFTER_X_REDIRECT_COUNT = "method";
/** The column that used to be used for the magic OTA update filename */
public static final String OTA_UPDATE = "otaupdate";
......@@ -140,12 +140,15 @@ public class Constants {
*/
public static final int RETRY_FIRST_DELAY = 30;
/** Enable separate connectivity logging */
static final boolean LOGX = false;
/** Enable verbose logging - use with "setprop log.tag.DownloadManager VERBOSE" */
private static final boolean LOCAL_LOGV = true;
private static final boolean LOCAL_LOGV = false;
public static final boolean LOGV = Config.LOGV
|| (Config.LOGD && LOCAL_LOGV && Log.isLoggable(TAG, Log.VERBOSE));
/** Enable super-verbose logging */
private static final boolean LOCAL_LOGVV = true;
private static final boolean LOCAL_LOGVV = false;
public static final boolean LOGVV = LOCAL_LOGVV && LOGV;
}
......@@ -22,13 +22,13 @@ import java.io.FileOutputStream;
* Stores information about the file in which a download gets saved.
*/
public class DownloadFileInfo {
public DownloadFileInfo(String filename, FileOutputStream stream, int status) {
this.filename = filename;
this.stream = stream;
this.status = status;
}
String mFileName;
FileOutputStream mStream;
int mStatus;
String filename;
FileOutputStream stream;
int status;
public DownloadFileInfo(String fileName, FileOutputStream stream, int status) {
mFileName = fileName;
mStream = stream;
mStatus = status;
}
}
......@@ -16,81 +16,84 @@
package com.android.providers.downloads;
import android.net.Uri;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.Downloads;
/**
* Stores information about an individual download.
*/
public class DownloadInfo {
public int id;
public String uri;
public boolean noIntegrity;
public String hint;
public String filename;
public String mimetype;
public int destination;
public int visibility;
public int control;
public int status;
public int numFailed;
public int retryAfter;
public int redirectCount;
public long lastMod;
public String pckg;
public String clazz;
public String extras;
public String cookies;
public String userAgent;
public String referer;
public int totalBytes;
public int currentBytes;
public String etag;
public boolean mediaScanned;
public int mId;
public String mUri;
public boolean mNoIntegrity;
public String mHint;
public String mFileName;
public String mMimeType;
public int mDestination;
public int mVisibility;
public int mControl;
public int mStatus;
public int mNumFailed;
public int mRetryAfter;
public int mRedirectCount;
public long mLastMod;
public String mPackage;
public String mClass;
public String mExtras;
public String mCookies;
public String mUserAgent;
public String mReferer;
public int mTotalBytes;
public int mCurrentBytes;
public String mETag;
public boolean mMediaScanned;
public int mFuzz;
public volatile boolean hasActiveThread;
public volatile boolean mHasActiveThread;
public DownloadInfo(int id, String uri, boolean noIntegrity,
String hint, String filename,
String mimetype, int destination, int visibility, int control,
String hint, String fileName,
String mimeType, int destination, int visibility, int control,
int status, int numFailed, int retryAfter, int redirectCount, long lastMod,
String pckg, String clazz, String extras, String cookies,
String userAgent, String referer, int totalBytes, int currentBytes, String etag,
String userAgent, String referer, int totalBytes, int currentBytes, String eTag,
boolean mediaScanned) {
this.id = id;
this.uri = uri;
this.noIntegrity = noIntegrity;
this.hint = hint;
this.filename = filename;
this.mimetype = mimetype;
this.destination = destination;
this.visibility = visibility;
this.control = control;
this.status = status;
this.numFailed = numFailed;
this.retryAfter = retryAfter;
this.redirectCount = redirectCount;
this.lastMod = lastMod;
this.pckg = pckg;
this.clazz = clazz;
this.extras = extras;
this.cookies = cookies;
this.userAgent = userAgent;
this.referer = referer;
this.totalBytes = totalBytes;
this.currentBytes = currentBytes;
this.etag = etag;
this.mediaScanned = mediaScanned;
mId = id;
mUri = uri;
mNoIntegrity = noIntegrity;
mHint = hint;
mFileName = fileName;
mMimeType = mimeType;
mDestination = destination;
mVisibility = visibility;
mControl = control;
mStatus = status;
mNumFailed = numFailed;
mRetryAfter = retryAfter;
mRedirectCount = redirectCount;
mLastMod = lastMod;
mPackage = pckg;
mClass = clazz;
mExtras = extras;
mCookies = cookies;
mUserAgent = userAgent;
mReferer = referer;
mTotalBytes = totalBytes;
mCurrentBytes = currentBytes;
mETag = eTag;
mMediaScanned = mediaScanned;
mFuzz = Helpers.sRandom.nextInt(1001);
}
public void sendIntentIfRequested(Uri contentUri, Context context) {
if (pckg != null && clazz != null) {
Intent intent = new Intent(Downloads.DOWNLOAD_COMPLETED_ACTION);
intent.setClassName(pckg, clazz);
if (extras != null) {
intent.putExtra(Downloads.NOTIFICATION_EXTRAS, extras);
if (mPackage != null && mClass != null) {
Intent intent = new Intent(Downloads.ACTION_DOWNLOAD_COMPLETED);
intent.setClassName(mPackage, mClass);
if (mExtras != null) {
intent.putExtra(Downloads.COLUMN_NOTIFICATION_EXTRAS, mExtras);
}
// We only send the content: URI, for security reasons. Otherwise, malicious
// applications would have an easier time spoofing download results by
......@@ -105,12 +108,12 @@ public class DownloadInfo {
* be called when numFailed > 0.
*/
public long restartTime() {
if (retryAfter > 0) {
return lastMod + retryAfter;
if (mRetryAfter > 0) {
return mLastMod + mRetryAfter;
}
return lastMod +
return mLastMod +
Constants.RETRY_FIRST_DELAY *
(1000 + Helpers.rnd.nextInt(1001)) * (1 << (numFailed - 1));
(1000 + mFuzz) * (1 << (mNumFailed - 1));
}
/**
......@@ -118,25 +121,25 @@ public class DownloadInfo {
* should be started.
*/
public boolean isReadyToStart(long now) {
if (control == Downloads.CONTROL_PAUSED) {
if (mControl == Downloads.CONTROL_PAUSED) {
// the download is paused, so it's not going to start
return false;
}
if (status == 0) {
if (mStatus == 0) {
// status hasn't been initialized yet, this is a new download
return true;
}
if (status == Downloads.STATUS_PENDING) {
if (mStatus == Downloads.STATUS_PENDING) {
// download is explicit marked as ready to start
return true;
}
if (status == Downloads.STATUS_RUNNING) {
if (mStatus == Downloads.STATUS_RUNNING) {
// download was interrupted (process killed, loss of power) while it was running,
// without a chance to update the database
return true;
}
if (status == Downloads.STATUS_RUNNING_PAUSED) {
if (numFailed == 0) {
if (mStatus == Downloads.STATUS_RUNNING_PAUSED) {
if (mNumFailed == 0) {
// download is waiting for network connectivity to return before it can resume
return true;
}
......@@ -157,20 +160,20 @@ public class DownloadInfo {
* by checking the status.
*/
public boolean isReadyToRestart(long now) {
if (control == Downloads.CONTROL_PAUSED) {
if (mControl == Downloads.CONTROL_PAUSED) {
// the download is paused, so it's not going to restart
return false;
}
if (status == 0) {
if (mStatus == 0) {
// download hadn't been initialized yet
return true;
}
if (status == Downloads.STATUS_PENDING) {
if (mStatus == Downloads.STATUS_PENDING) {
// download is explicit marked as ready to start
return true;
}
if (status == Downloads.STATUS_RUNNING_PAUSED) {
if (numFailed == 0) {
if (mStatus == Downloads.STATUS_RUNNING_PAUSED) {
if (mNumFailed == 0) {
// download is waiting for network connectivity to return before it can resume
return true;
}
......@@ -187,10 +190,10 @@ public class DownloadInfo {
* completion.
*/
public boolean hasCompletionNotification() {
if (!Downloads.isStatusCompleted(status)) {
if (!Downloads.isStatusCompleted(mStatus)) {
return false;
}
if (visibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
if (mVisibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
return true;
}
return false;
......@@ -203,7 +206,7 @@ public class DownloadInfo {
if (!available) {
return false;
}
if (destination == Downloads.DESTINATION_CACHE_PARTITION_NOROAMING) {
if (mDestination == Downloads.DESTINATION_CACHE_PARTITION_NOROAMING) {
return !roaming;
} else {
return true;
......
......@@ -43,14 +43,15 @@ class DownloadNotification {
static final String LOGTAG = "DownloadNotification";
static final String WHERE_RUNNING =
"(" + Downloads.STATUS + " >= '100') AND (" +
Downloads.STATUS + " <= '199') AND (" +
Downloads.VISIBILITY + " IS NULL OR " +
Downloads.VISIBILITY + " == '" + Downloads.VISIBILITY_VISIBLE + "' OR " +
Downloads.VISIBILITY + " == '" + Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "')";
"(" + Downloads.COLUMN_STATUS + " >= '100') AND (" +
Downloads.COLUMN_STATUS + " <= '199') AND (" +
Downloads.COLUMN_VISIBILITY + " IS NULL OR " +
Downloads.COLUMN_VISIBILITY + " == '" + Downloads.VISIBILITY_VISIBLE + "' OR " +
Downloads.COLUMN_VISIBILITY +
" == '" + Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "')";
static final String WHERE_COMPLETED =
Downloads.STATUS + " >= '200' AND " +
Downloads.VISIBILITY + " == '" + Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "'";
Downloads.COLUMN_STATUS + " >= '200' AND " +
Downloads.COLUMN_VISIBILITY + " == '" + Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "'";
/**
......@@ -60,28 +61,28 @@ class DownloadNotification {
*
*/
static class NotificationItem {
int id; // This first db _id for the download for the app
int totalCurrent = 0;
int totalTotal = 0;
int titleCount = 0;
String packageName; // App package name
String description;
String[] titles = new String[2]; // download titles.
int mId; // This first db _id for the download for the app
int mTotalCurrent = 0;
int mTotalTotal = 0;
int mTitleCount = 0;
String mPackageName; // App package name
String mDescription;
String[] mTitles = new String[2]; // download titles.
/*
* Add a second download to this notification item.
*/
void addItem(String title, int currentBytes, int totalBytes) {
totalCurrent += currentBytes;
if (totalBytes <= 0 || totalTotal == -1) {
totalTotal = -1;
mTotalCurrent += currentBytes;
if (totalBytes <= 0 || mTotalTotal == -1) {
mTotalTotal = -1;
} else {
totalTotal += totalBytes;
mTotalTotal += totalBytes;
}
if (titleCount < 2) {
titles[titleCount] = title;
if (mTitleCount < 2) {
mTitles[mTitleCount] = title;
}
titleCount++;
mTitleCount++;
}
}
......@@ -110,11 +111,14 @@ class DownloadNotification {
// Active downloads
Cursor c = mContext.getContentResolver().query(
Downloads.CONTENT_URI, new String [] {
Downloads._ID, Downloads.TITLE, Downloads.DESCRIPTION,
Downloads.NOTIFICATION_PACKAGE,
Downloads.NOTIFICATION_CLASS,
Downloads.CURRENT_BYTES, Downloads.TOTAL_BYTES,
Downloads.STATUS, Downloads._DATA
Downloads._ID,
Downloads.COLUMN_TITLE,
Downloads.COLUMN_DESCRIPTION,
Downloads.COLUMN_NOTIFICATION_PACKAGE,
Downloads.COLUMN_NOTIFICATION_CLASS,
Downloads.COLUMN_CURRENT_BYTES,
Downloads.COLUMN_TOTAL_BYTES,
Downloads.COLUMN_STATUS, Downloads._DATA
},
WHERE_RUNNING, null, Downloads._ID);
......@@ -148,9 +152,9 @@ class DownloadNotification {
mNotifications.get(packageName).addItem(title, progress, max);
} else {
NotificationItem item = new NotificationItem();
item.id = c.getInt(idColumn);
item.packageName = packageName;
item.description = c.getString(descColumn);
item.mId = c.getInt(idColumn);
item.mPackageName = packageName;
item.mDescription = c.getString(descColumn);
String className = c.getString(classOwnerColumn);
item.addItem(title, progress, max);
mNotifications.put(packageName, item);
......@@ -171,26 +175,26 @@ class DownloadNotification {
RemoteViews expandedView = new RemoteViews(
"com.android.providers.downloads",
R.layout.status_bar_ongoing_event_progress_bar);
StringBuilder title = new StringBuilder(item.titles[0]);
if (item.titleCount > 1) {
StringBuilder title = new StringBuilder(item.mTitles[0]);
if (item.mTitleCount > 1) {
title.append(mContext.getString(R.string.notification_filename_separator));
title.append(item.titles[1]);
n.number = item.titleCount;
if (item.titleCount > 2) {
title.append(item.mTitles[1]);
n.number = item.mTitleCount;
if (item.mTitleCount > 2) {
title.append(mContext.getString(R.string.notification_filename_extras,
new Object[] { Integer.valueOf(item.titleCount - 2) }));
new Object[] { Integer.valueOf(item.mTitleCount - 2) }));
}
} else {
expandedView.setTextViewText(R.id.description,
item.description);
item.mDescription);
}
expandedView.setTextViewText(R.id.title, title);
expandedView.setProgressBar(R.id.progress_bar,
item.totalTotal,
item.totalCurrent,
item.totalTotal == -1);
item.mTotalTotal,
item.mTotalCurrent,
item.mTotalTotal == -1);
expandedView.setTextViewText(R.id.progress_text,
getDownloadingText(item.totalTotal, item.totalCurrent));
getDownloadingText(item.mTotalTotal, item.mTotalCurrent));
expandedView.setImageViewResource(R.id.appIcon,
android.R.drawable.stat_sys_download);
n.contentView = expandedView;
......@@ -198,12 +202,12 @@ class DownloadNotification {
Intent intent = new Intent(Constants.ACTION_LIST);
intent.setClassName("com.android.providers.downloads",
DownloadReceiver.class.getName());
intent.setData(Uri.parse(Downloads.CONTENT_URI + "/" + item.id));
intent.putExtra("multiple", item.titleCount > 1);
intent.setData(Uri.parse(Downloads.CONTENT_URI + "/" + item.mId));
intent.putExtra("multiple", item.mTitleCount > 1);
n.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
mNotificationMgr.notify(item.id, n);
mNotificationMgr.notify(item.mId, n);
}
}
......@@ -212,12 +216,17 @@ class DownloadNotification {
// Completed downloads
Cursor c = mContext.getContentResolver().query(
Downloads.CONTENT_URI, new String [] {
Downloads._ID, Downloads.TITLE, Downloads.DESCRIPTION,
Downloads.NOTIFICATION_PACKAGE,
Downloads.NOTIFICATION_CLASS,
Downloads.CURRENT_BYTES, Downloads.TOTAL_BYTES,
Downloads.STATUS, Downloads._DATA,
Downloads.LAST_MODIFICATION, Downloads.DESTINATION
Downloads._ID,
Downloads.COLUMN_TITLE,
Downloads.COLUMN_DESCRIPTION,
Downloads.COLUMN_NOTIFICATION_PACKAGE,
Downloads.COLUMN_NOTIFICATION_CLASS,
Downloads.COLUMN_CURRENT_BYTES,
Downloads.COLUMN_TOTAL_BYTES,
Downloads.COLUMN_STATUS,
Downloads._DATA,
Downloads.COLUMN_LAST_MODIFICATION,
Downloads.COLUMN_DESTINATION
},
WHERE_COMPLETED, null, Downloads._ID);
......
......@@ -26,10 +26,10 @@ import android.database.CrossProcessCursor;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.CursorWrapper;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.database.SQLException;
import android.net.Uri;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
......@@ -40,7 +40,6 @@ import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashSet;
......@@ -78,20 +77,20 @@ public final class DownloadProvider extends ContentProvider {
private static final String[] sAppReadableColumnsArray = new String[] {
Downloads._ID,
Downloads.APP_DATA,
Downloads.COLUMN_APP_DATA,
Downloads._DATA,
Downloads.MIMETYPE,
Downloads.VISIBILITY,
Downloads.DESTINATION,
Downloads.CONTROL,
Downloads.STATUS,
Downloads.LAST_MODIFICATION,
Downloads.NOTIFICATION_PACKAGE,
Downloads.NOTIFICATION_CLASS,
Downloads.TOTAL_BYTES,
Downloads.CURRENT_BYTES,
Downloads.TITLE,
Downloads.DESCRIPTION
Downloads.COLUMN_MIME_TYPE,
Downloads.COLUMN_VISIBILITY,
Downloads.COLUMN_DESTINATION,
Downloads.COLUMN_CONTROL,
Downloads.COLUMN_STATUS,
Downloads.COLUMN_LAST_MODIFICATION,
Downloads.COLUMN_NOTIFICATION_PACKAGE,
Downloads.COLUMN_NOTIFICATION_CLASS,
Downloads.COLUMN_TOTAL_BYTES,
Downloads.COLUMN_CURRENT_BYTES,
Downloads.COLUMN_TITLE,
Downloads.COLUMN_DESCRIPTION
};
private static HashSet<String> sAppReadableColumnsSet;
......@@ -201,34 +200,34 @@ public final class DownloadProvider extends ContentProvider {
try {
db.execSQL("CREATE TABLE " + DB_TABLE + "(" +
Downloads._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
Downloads.URI + " TEXT, " +
Constants.RETRY_AFTER___REDIRECT_COUNT + " INTEGER, " +
Downloads.APP_DATA + " TEXT, " +
Downloads.NO_INTEGRITY + " BOOLEAN, " +
Downloads.FILENAME_HINT + " TEXT, " +
Downloads.COLUMN_URI + " TEXT, " +
Constants.RETRY_AFTER_X_REDIRECT_COUNT + " INTEGER, " +
Downloads.COLUMN_APP_DATA + " TEXT, " +
Downloads.COLUMN_NO_INTEGRITY + " BOOLEAN, " +
Downloads.COLUMN_FILE_NAME_HINT + " TEXT, " +
Constants.OTA_UPDATE + " BOOLEAN, " +
Downloads._DATA + " TEXT, " +
Downloads.MIMETYPE + " TEXT, " +
Downloads.DESTINATION + " INTEGER, " +
Downloads.COLUMN_MIME_TYPE + " TEXT, " +
Downloads.COLUMN_DESTINATION + " INTEGER, " +
Constants.NO_SYSTEM_FILES + " BOOLEAN, " +
Downloads.VISIBILITY + " INTEGER, " +
Downloads.CONTROL + " INTEGER, " +
Downloads.STATUS + " INTEGER, " +
Downloads.COLUMN_VISIBILITY + " INTEGER, " +
Downloads.COLUMN_CONTROL + " INTEGER, " +
Downloads.COLUMN_STATUS + " INTEGER, " +
Constants.FAILED_CONNECTIONS + " INTEGER, " +
Downloads.LAST_MODIFICATION + " BIGINT, " +
Downloads.NOTIFICATION_PACKAGE + " TEXT, " +
Downloads.NOTIFICATION_CLASS + " TEXT, " +
Downloads.NOTIFICATION_EXTRAS + " TEXT, " +
Downloads.COOKIE_DATA + " TEXT, " +
Downloads.USER_AGENT + " TEXT, " +
Downloads.REFERER + " TEXT, " +
Downloads.TOTAL_BYTES + " INTEGER, " +
Downloads.CURRENT_BYTES + " INTEGER, " +
Downloads.COLUMN_LAST_MODIFICATION + " BIGINT, " +
Downloads.COLUMN_NOTIFICATION_PACKAGE + " TEXT, " +
Downloads.COLUMN_NOTIFICATION_CLASS + " TEXT, " +
Downloads.COLUMN_NOTIFICATION_EXTRAS + " TEXT, " +
Downloads.COLUMN_COOKIE_DATA + " TEXT, " +
Downloads.COLUMN_USER_AGENT + " TEXT, " +
Downloads.COLUMN_REFERER + " TEXT, " +
Downloads.COLUMN_TOTAL_BYTES + " INTEGER, " +
Downloads.COLUMN_CURRENT_BYTES + " INTEGER, " +
Constants.ETAG + " TEXT, " +
Constants.UID + " INTEGER, " +
Downloads.OTHER_UID + " INTEGER, " +
Downloads.TITLE + " TEXT, " +
Downloads.DESCRIPTION + " TEXT, " +
Downloads.COLUMN_OTHER_UID + " INTEGER, " +
Downloads.COLUMN_TITLE + " TEXT, " +
Downloads.COLUMN_DESCRIPTION + " TEXT, " +
Constants.MEDIA_SCANNED + " BOOLEAN);");
} catch (SQLException ex) {
Log.e(Constants.TAG, "couldn't create table in downloads database");
......@@ -264,12 +263,12 @@ public final class DownloadProvider extends ContentProvider {
ContentValues filteredValues = new ContentValues();
copyString(Downloads.URI, values, filteredValues);
copyString(Downloads.APP_DATA, values, filteredValues);
copyBoolean(Downloads.NO_INTEGRITY, values, filteredValues);
copyString(Downloads.FILENAME_HINT, values, filteredValues);
copyString(Downloads.MIMETYPE, values, filteredValues);
Integer dest = values.getAsInteger(Downloads.DESTINATION);
copyString(Downloads.COLUMN_URI, values, filteredValues);
copyString(Downloads.COLUMN_APP_DATA, values, filteredValues);
copyBoolean(Downloads.COLUMN_NO_INTEGRITY, values, filteredValues);
copyString(Downloads.COLUMN_FILE_NAME_HINT, values, filteredValues);
copyString(Downloads.COLUMN_MIME_TYPE, values, filteredValues);
Integer dest = values.getAsInteger(Downloads.COLUMN_DESTINATION);
if (dest != null) {
if (getContext().checkCallingPermission(Downloads.PERMISSION_ACCESS_ADVANCED)
!= PackageManager.PERMISSION_GRANTED
......@@ -277,57 +276,57 @@ public final class DownloadProvider extends ContentProvider {
&& dest != Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE) {
throw new SecurityException("unauthorized destination code");
}
filteredValues.put(Downloads.DESTINATION, dest);
filteredValues.put(Downloads.COLUMN_DESTINATION, dest);
}
Integer vis = values.getAsInteger(Downloads.VISIBILITY);
Integer vis = values.getAsInteger(Downloads.COLUMN_VISIBILITY);
if (vis == null) {
if (dest == Downloads.DESTINATION_EXTERNAL) {
filteredValues.put(Downloads.VISIBILITY,
filteredValues.put(Downloads.COLUMN_VISIBILITY,
Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
} else {
filteredValues.put(Downloads.VISIBILITY, Downloads.VISIBILITY_HIDDEN);
filteredValues.put(Downloads.COLUMN_VISIBILITY, Downloads.VISIBILITY_HIDDEN);
}
} else {
filteredValues.put(Downloads.VISIBILITY, vis);
filteredValues.put(Downloads.COLUMN_VISIBILITY, vis);
}
copyInteger(Downloads.CONTROL, values, filteredValues);
filteredValues.put(Downloads.STATUS, Downloads.STATUS_PENDING);
filteredValues.put(Downloads.LAST_MODIFICATION, System.currentTimeMillis());
String pckg = values.getAsString(Downloads.NOTIFICATION_PACKAGE);
String clazz = values.getAsString(Downloads.NOTIFICATION_CLASS);
copyInteger(Downloads.COLUMN_CONTROL, values, filteredValues);
filteredValues.put(Downloads.COLUMN_STATUS, Downloads.STATUS_PENDING);
filteredValues.put(Downloads.COLUMN_LAST_MODIFICATION, System.currentTimeMillis());
String pckg = values.getAsString(Downloads.COLUMN_NOTIFICATION_PACKAGE);
String clazz = values.getAsString(Downloads.COLUMN_NOTIFICATION_CLASS);
if (pckg != null && clazz != null) {
int uid = Binder.getCallingUid();
try {
if (uid == 0 ||
getContext().getPackageManager().getApplicationInfo(pckg, 0).uid == uid) {
filteredValues.put(Downloads.NOTIFICATION_PACKAGE, pckg);
filteredValues.put(Downloads.NOTIFICATION_CLASS, clazz);
filteredValues.put(Downloads.COLUMN_NOTIFICATION_PACKAGE, pckg);
filteredValues.put(Downloads.COLUMN_NOTIFICATION_CLASS, clazz);
}
} catch (PackageManager.NameNotFoundException ex) {
/* ignored for now */
}
}
copyString(Downloads.NOTIFICATION_EXTRAS, values, filteredValues);
copyString(Downloads.COOKIE_DATA, values, filteredValues);
copyString(Downloads.USER_AGENT, values, filteredValues);
copyString(Downloads.REFERER, values, filteredValues);
copyString(Downloads.COLUMN_NOTIFICATION_EXTRAS, values, filteredValues);
copyString(Downloads.COLUMN_COOKIE_DATA, values, filteredValues);
copyString(Downloads.COLUMN_USER_AGENT, values, filteredValues);
copyString(Downloads.COLUMN_REFERER, values, filteredValues);
if (getContext().checkCallingPermission(Downloads.PERMISSION_ACCESS_ADVANCED)
== PackageManager.PERMISSION_GRANTED) {
copyInteger(Downloads.OTHER_UID, values, filteredValues);
copyInteger(Downloads.COLUMN_OTHER_UID, values, filteredValues);
}
filteredValues.put(Constants.UID, Binder.getCallingUid());
if (Binder.getCallingUid() == 0) {
copyInteger(Constants.UID, values, filteredValues);
}
copyString(Downloads.TITLE, values, filteredValues);
copyString(Downloads.DESCRIPTION, values, filteredValues);
copyString(Downloads.COLUMN_TITLE, values, filteredValues);
copyString(Downloads.COLUMN_DESCRIPTION, values, filteredValues);
if (Constants.LOGVV) {
Log.v(Constants.TAG, "initiating download with UID "
+ filteredValues.getAsInteger(Constants.UID));
if (filteredValues.containsKey(Downloads.OTHER_UID)) {
if (filteredValues.containsKey(Downloads.COLUMN_OTHER_UID)) {
Log.v(Constants.TAG, "other UID " +
filteredValues.getAsInteger(Downloads.OTHER_UID));
filteredValues.getAsInteger(Downloads.COLUMN_OTHER_UID));
}
}
......@@ -387,12 +386,13 @@ public final class DownloadProvider extends ContentProvider {
}
}
if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0) {
if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0 &&
Process.supportsProcesses()) {
if (!emptyWhere) {
qb.appendWhere(" AND ");
}
qb.appendWhere("( " + Constants.UID + "=" + Binder.getCallingUid() + " OR "
+ Downloads.OTHER_UID + "=" + Binder.getCallingUid() + " )");
+ Downloads.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )");
emptyWhere = false;
if (projection == null) {
......@@ -489,16 +489,16 @@ public final class DownloadProvider extends ContentProvider {
ContentValues filteredValues;
if (Binder.getCallingPid() != Process.myPid()) {
filteredValues = new ContentValues();
copyString(Downloads.APP_DATA, values, filteredValues);
copyInteger(Downloads.VISIBILITY, values, filteredValues);
Integer i = values.getAsInteger(Downloads.CONTROL);
copyString(Downloads.COLUMN_APP_DATA, values, filteredValues);
copyInteger(Downloads.COLUMN_VISIBILITY, values, filteredValues);
Integer i = values.getAsInteger(Downloads.COLUMN_CONTROL);
if (i != null) {
filteredValues.put(Downloads.CONTROL, i);
filteredValues.put(Downloads.COLUMN_CONTROL, i);
startService = true;
}
copyInteger(Downloads.CONTROL, values, filteredValues);
copyString(Downloads.TITLE, values, filteredValues);
copyString(Downloads.DESCRIPTION, values, filteredValues);
copyInteger(Downloads.COLUMN_CONTROL, values, filteredValues);
copyString(Downloads.COLUMN_TITLE, values, filteredValues);
copyString(Downloads.COLUMN_DESCRIPTION, values, filteredValues);
} else {
filteredValues = values;
}
......@@ -523,7 +523,7 @@ public final class DownloadProvider extends ContentProvider {
}
if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0) {
myWhere += " AND ( " + Constants.UID + "=" + Binder.getCallingUid() + " OR "
+ Downloads.OTHER_UID + "=" + Binder.getCallingUid() + " )";
+ Downloads.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )";
}
if (filteredValues.size() > 0) {
count = db.update(DB_TABLE, filteredValues, myWhere, whereArgs);
......@@ -579,7 +579,7 @@ public final class DownloadProvider extends ContentProvider {
}
if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0) {
myWhere += " AND ( " + Constants.UID + "=" + Binder.getCallingUid() + " OR "
+ Downloads.OTHER_UID + "=" + Binder.getCallingUid() + " )";
+ Downloads.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )";
}
count = db.delete(DB_TABLE, myWhere, whereArgs);
break;
......@@ -673,7 +673,7 @@ public final class DownloadProvider extends ContentProvider {
throw new FileNotFoundException("couldn't open file");
} else {
ContentValues values = new ContentValues();
values.put(Downloads.LAST_MODIFICATION, System.currentTimeMillis());
values.put(Downloads.COLUMN_LAST_MODIFICATION, System.currentTimeMillis());
update(uri, values, null, null);
}
return ret;
......
......@@ -23,18 +23,15 @@ import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.provider.Downloads;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.provider.Downloads;
import android.util.Config;
import android.util.Log;
import java.io.File;
import java.util.List;
/**
* Receives system broadcasts (boot, network connectivity)
......@@ -54,7 +51,22 @@ public class DownloadReceiver extends BroadcastReceiver {
NetworkInfo info = (NetworkInfo)
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (info != null && info.isConnected()) {
if (Constants.LOGX) {
if (Helpers.isNetworkAvailable(context)) {
Log.i(Constants.TAG, "Broadcast: Network Up");
} else {
Log.i(Constants.TAG, "Broadcast: Network Up, Actually Down");
}
}
context.startService(new Intent(context, DownloadService.class));
} else {
if (Constants.LOGX) {
if (Helpers.isNetworkAvailable(context)) {
Log.i(Constants.TAG, "Broadcast: Network Down, Actually Up");
} else {
Log.i(Constants.TAG, "Broadcast: Network Down");
}
}
}
} else if (intent.getAction().equals(Constants.ACTION_RETRY)) {
if (Constants.LOGVV) {
......@@ -74,20 +86,22 @@ public class DownloadReceiver extends BroadcastReceiver {
intent.getData(), null, null, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
int statusColumn = cursor.getColumnIndexOrThrow(Downloads.STATUS);
int statusColumn = cursor.getColumnIndexOrThrow(Downloads.COLUMN_STATUS);
int status = cursor.getInt(statusColumn);
int visibilityColumn = cursor.getColumnIndexOrThrow(Downloads.VISIBILITY);
int visibilityColumn =
cursor.getColumnIndexOrThrow(Downloads.COLUMN_VISIBILITY);
int visibility = cursor.getInt(visibilityColumn);
if (Downloads.isStatusCompleted(status)
&& visibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
ContentValues values = new ContentValues();
values.put(Downloads.VISIBILITY, Downloads.VISIBILITY_VISIBLE);
values.put(Downloads.COLUMN_VISIBILITY, Downloads.VISIBILITY_VISIBLE);
context.getContentResolver().update(intent.getData(), values, null, null);
}
if (intent.getAction().equals(Constants.ACTION_OPEN)) {
int filenameColumn = cursor.getColumnIndexOrThrow(Downloads._DATA);
int mimetypeColumn = cursor.getColumnIndexOrThrow(Downloads.MIMETYPE);
int mimetypeColumn =
cursor.getColumnIndexOrThrow(Downloads.COLUMN_MIME_TYPE);
String filename = cursor.getString(filenameColumn);
String mimetype = cursor.getString(mimetypeColumn);
Uri path = Uri.parse(filename);
......@@ -109,13 +123,13 @@ public class DownloadReceiver extends BroadcastReceiver {
}
} else {
int packageColumn =
cursor.getColumnIndexOrThrow(Downloads.NOTIFICATION_PACKAGE);
cursor.getColumnIndexOrThrow(Downloads.COLUMN_NOTIFICATION_PACKAGE);
int classColumn =
cursor.getColumnIndexOrThrow(Downloads.NOTIFICATION_CLASS);
cursor.getColumnIndexOrThrow(Downloads.COLUMN_NOTIFICATION_CLASS);
String pckg = cursor.getString(packageColumn);
String clazz = cursor.getString(classColumn);
if (pckg != null && clazz != null) {
Intent appIntent = new Intent(Downloads.NOTIFICATION_CLICKED_ACTION);
Intent appIntent = new Intent(Downloads.ACTION_NOTIFICATION_CLICKED);
appIntent.setClassName(pckg, clazz);
if (intent.getBooleanExtra("multiple", true)) {
appIntent.setData(Downloads.CONTENT_URI);
......@@ -141,14 +155,15 @@ public class DownloadReceiver extends BroadcastReceiver {
intent.getData(), null, null, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
int statusColumn = cursor.getColumnIndexOrThrow(Downloads.STATUS);
int statusColumn = cursor.getColumnIndexOrThrow(Downloads.COLUMN_STATUS);
int status = cursor.getInt(statusColumn);
int visibilityColumn = cursor.getColumnIndexOrThrow(Downloads.VISIBILITY);
int visibilityColumn =
cursor.getColumnIndexOrThrow(Downloads.COLUMN_VISIBILITY);
int visibility = cursor.getInt(visibilityColumn);
if (Downloads.isStatusCompleted(status)
&& visibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
ContentValues values = new ContentValues();
values.put(Downloads.VISIBILITY, Downloads.VISIBILITY_VISIBLE);
values.put(Downloads.COLUMN_VISIBILITY, Downloads.VISIBILITY_VISIBLE);
context.getContentResolver().update(intent.getData(), values, null, null);
}
}
......
......@@ -38,18 +38,17 @@ import android.webkit.MimeTypeMap;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Set;
/**
* Some helper functions for the download manager
*/
public class Helpers {
public static Random rnd = new Random(SystemClock.uptimeMillis());
public static Random sRandom = new Random(SystemClock.uptimeMillis());
/** Regex used to parse content-disposition headers */
private static final Pattern CONTENT_DISPOSITION_PATTERN =
......@@ -411,7 +410,7 @@ public class Helpers {
if (Constants.LOGVV) {
Log.v(Constants.TAG, "file with sequence number " + sequence + " exists");
}
sequence += rnd.nextInt(magnitude) + 1;
sequence += sRandom.nextInt(magnitude) + 1;
}
}
return null;
......@@ -427,11 +426,11 @@ public class Helpers {
Downloads.CONTENT_URI,
null,
"( " +
Downloads.STATUS + " = '" + Downloads.STATUS_SUCCESS + "' AND " +
Downloads.DESTINATION + " = '" + Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE
+ "' )",
Downloads.COLUMN_STATUS + " = '" + Downloads.STATUS_SUCCESS + "' AND " +
Downloads.COLUMN_DESTINATION +
" = '" + Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE + "' )",
null,
Downloads.LAST_MODIFICATION);
Downloads.COLUMN_LAST_MODIFICATION);
if (cursor == null) {
return false;
}
......@@ -755,7 +754,7 @@ public class Helpers {
// quoted strings
if (chars[mOffset] == '\'') {
++mOffset;
while(mOffset < chars.length) {
while (mOffset < chars.length) {
if (chars[mOffset] == '\'') {
if (mOffset + 1 < chars.length && chars[mOffset + 1] == '\'') {
++mOffset;
......
......@@ -88,7 +88,7 @@ public class DownloadProviderPermissionsTest extends AndroidTestCase {
public void testWriteDownloadProvider() throws IOException {
try {
ContentValues values = new ContentValues();
values.put(Downloads.DESTINATION, "foo");
values.put(Downloads.COLUMN_URI, "foo");
mContentResolver.insert(Downloads.CONTENT_URI, values);
fail("write to provider did not throw SecurityException as expected.");
} catch (SecurityException e) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment