diff options
Diffstat (limited to 'src/com/android/providers')
7 files changed, 443 insertions, 362 deletions
diff --git a/src/com/android/providers/downloads/DownloadInfo.java b/src/com/android/providers/downloads/DownloadInfo.java index 88cdede2..81895439 100644 --- a/src/com/android/providers/downloads/DownloadInfo.java +++ b/src/com/android/providers/downloads/DownloadInfo.java @@ -90,10 +90,10 @@ public class DownloadInfo { public void sendIntentIfRequested(Uri contentUri, Context context) { if (mPackage != null && mClass != null) { - Intent intent = new Intent(Downloads.ACTION_DOWNLOAD_COMPLETED); + Intent intent = new Intent(Downloads.Impl.ACTION_DOWNLOAD_COMPLETED); intent.setClassName(mPackage, mClass); if (mExtras != null) { - intent.putExtra(Downloads.COLUMN_NOTIFICATION_EXTRAS, mExtras); + intent.putExtra(Downloads.Impl.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 @@ -121,7 +121,7 @@ public class DownloadInfo { * should be started. */ public boolean isReadyToStart(long now) { - if (mControl == Downloads.CONTROL_PAUSED) { + if (mControl == Downloads.Impl.CONTROL_PAUSED) { // the download is paused, so it's not going to start return false; } @@ -129,16 +129,16 @@ public class DownloadInfo { // status hasn't been initialized yet, this is a new download return true; } - if (mStatus == Downloads.STATUS_PENDING) { + if (mStatus == Downloads.Impl.STATUS_PENDING) { // download is explicit marked as ready to start return true; } - if (mStatus == Downloads.STATUS_RUNNING) { + if (mStatus == Downloads.Impl.STATUS_RUNNING) { // download was interrupted (process killed, loss of power) while it was running, // without a chance to update the database return true; } - if (mStatus == Downloads.STATUS_RUNNING_PAUSED) { + if (mStatus == Downloads.Impl.STATUS_RUNNING_PAUSED) { if (mNumFailed == 0) { // download is waiting for network connectivity to return before it can resume return true; @@ -160,7 +160,7 @@ public class DownloadInfo { * by checking the status. */ public boolean isReadyToRestart(long now) { - if (mControl == Downloads.CONTROL_PAUSED) { + if (mControl == Downloads.Impl.CONTROL_PAUSED) { // the download is paused, so it's not going to restart return false; } @@ -168,11 +168,11 @@ public class DownloadInfo { // download hadn't been initialized yet return true; } - if (mStatus == Downloads.STATUS_PENDING) { + if (mStatus == Downloads.Impl.STATUS_PENDING) { // download is explicit marked as ready to start return true; } - if (mStatus == Downloads.STATUS_RUNNING_PAUSED) { + if (mStatus == Downloads.Impl.STATUS_RUNNING_PAUSED) { if (mNumFailed == 0) { // download is waiting for network connectivity to return before it can resume return true; @@ -190,10 +190,10 @@ public class DownloadInfo { * completion. */ public boolean hasCompletionNotification() { - if (!Downloads.isStatusCompleted(mStatus)) { + if (!Downloads.Impl.isStatusCompleted(mStatus)) { return false; } - if (mVisibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) { + if (mVisibility == Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) { return true; } return false; @@ -206,7 +206,7 @@ public class DownloadInfo { if (!available) { return false; } - if (mDestination == Downloads.DESTINATION_CACHE_PARTITION_NOROAMING) { + if (mDestination == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING) { return !roaming; } else { return true; diff --git a/src/com/android/providers/downloads/DownloadNotification.java b/src/com/android/providers/downloads/DownloadNotification.java index f7c10073..e9c0d4e6 100644 --- a/src/com/android/providers/downloads/DownloadNotification.java +++ b/src/com/android/providers/downloads/DownloadNotification.java @@ -43,15 +43,16 @@ class DownloadNotification { static final String LOGTAG = "DownloadNotification"; static final String WHERE_RUNNING = - "(" + 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 + "')"; + "(" + Downloads.Impl.COLUMN_STATUS + " >= '100') AND (" + + Downloads.Impl.COLUMN_STATUS + " <= '199') AND (" + + Downloads.Impl.COLUMN_VISIBILITY + " IS NULL OR " + + Downloads.Impl.COLUMN_VISIBILITY + " == '" + Downloads.Impl.VISIBILITY_VISIBLE + "' OR " + + Downloads.Impl.COLUMN_VISIBILITY + + " == '" + Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "')"; static final String WHERE_COMPLETED = - Downloads.COLUMN_STATUS + " >= '200' AND " + - Downloads.COLUMN_VISIBILITY + " == '" + Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "'"; + Downloads.Impl.COLUMN_STATUS + " >= '200' AND " + + Downloads.Impl.COLUMN_VISIBILITY + + " == '" + Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + "'"; /** @@ -110,17 +111,17 @@ class DownloadNotification { private void updateActiveNotification() { // Active downloads Cursor c = mContext.getContentResolver().query( - Downloads.CONTENT_URI, new String [] { - 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.Impl.CONTENT_URI, new String [] { + Downloads.Impl._ID, + Downloads.Impl.COLUMN_TITLE, + Downloads.Impl.COLUMN_DESCRIPTION, + Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, + Downloads.Impl.COLUMN_NOTIFICATION_CLASS, + Downloads.Impl.COLUMN_CURRENT_BYTES, + Downloads.Impl.COLUMN_TOTAL_BYTES, + Downloads.Impl.COLUMN_STATUS }, - WHERE_RUNNING, null, Downloads._ID); + WHERE_RUNNING, null, Downloads.Impl._ID); if (c == null) { return; @@ -135,7 +136,6 @@ class DownloadNotification { final int currentBytesColumn = 5; final int totalBytesColumn = 6; final int statusColumn = 7; - final int filenameColumnId = 8; // Collate the notifications mNotifications.clear(); @@ -143,6 +143,7 @@ class DownloadNotification { String packageName = c.getString(ownerColumn); int max = c.getInt(totalBytesColumn); int progress = c.getInt(currentBytesColumn); + long id = c.getLong(idColumn); String title = c.getString(titleColumn); if (title == null || title.length() == 0) { title = mContext.getResources().getString( @@ -152,7 +153,7 @@ class DownloadNotification { mNotifications.get(packageName).addItem(title, progress, max); } else { NotificationItem item = new NotificationItem(); - item.mId = c.getInt(idColumn); + item.mId = (int) id; item.mPackageName = packageName; item.mDescription = c.getString(descColumn); String className = c.getString(classOwnerColumn); @@ -202,7 +203,7 @@ 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.mId)); + intent.setData(Uri.parse(Downloads.Impl.CONTENT_URI + "/" + item.mId)); intent.putExtra("multiple", item.mTitleCount > 1); n.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); @@ -215,20 +216,19 @@ class DownloadNotification { private void updateCompletedNotification() { // Completed downloads Cursor c = mContext.getContentResolver().query( - Downloads.CONTENT_URI, new String [] { - 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 + Downloads.Impl.CONTENT_URI, new String [] { + Downloads.Impl._ID, + Downloads.Impl.COLUMN_TITLE, + Downloads.Impl.COLUMN_DESCRIPTION, + Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, + Downloads.Impl.COLUMN_NOTIFICATION_CLASS, + Downloads.Impl.COLUMN_CURRENT_BYTES, + Downloads.Impl.COLUMN_TOTAL_BYTES, + Downloads.Impl.COLUMN_STATUS, + Downloads.Impl.COLUMN_LAST_MODIFICATION, + Downloads.Impl.COLUMN_DESTINATION }, - WHERE_COMPLETED, null, Downloads._ID); + WHERE_COMPLETED, null, Downloads.Impl._ID); if (c == null) { return; @@ -243,31 +243,31 @@ class DownloadNotification { final int currentBytesColumn = 5; final int totalBytesColumn = 6; final int statusColumn = 7; - final int filenameColumnId = 8; - final int lastModColumnId = 9; - final int destinationColumnId = 10; + final int lastModColumnId = 8; + final int destinationColumnId = 9; for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) { // Add the notifications Notification n = new Notification(); n.icon = android.R.drawable.stat_sys_download_done; + long id = c.getLong(idColumn); String title = c.getString(titleColumn); if (title == null || title.length() == 0) { title = mContext.getResources().getString( R.string.download_unknown_title); } - Uri contentUri = Uri.parse(Downloads.CONTENT_URI + "/" + c.getInt(idColumn)); + Uri contentUri = Uri.parse(Downloads.Impl.CONTENT_URI + "/" + id); String caption; Intent intent; - if (Downloads.isStatusError(c.getInt(statusColumn))) { + if (Downloads.Impl.isStatusError(c.getInt(statusColumn))) { caption = mContext.getResources() .getString(R.string.notification_download_failed); intent = new Intent(Constants.ACTION_LIST); } else { caption = mContext.getResources() .getString(R.string.notification_download_complete); - if (c.getInt(destinationColumnId) == Downloads.DESTINATION_EXTERNAL) { + if (c.getInt(destinationColumnId) == Downloads.Impl.DESTINATION_EXTERNAL) { intent = new Intent(Constants.ACTION_OPEN); } else { intent = new Intent(Constants.ACTION_LIST); @@ -276,6 +276,7 @@ class DownloadNotification { intent.setClassName("com.android.providers.downloads", DownloadReceiver.class.getName()); intent.setData(contentUri); + n.when = c.getLong(lastModColumnId); n.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(mContext, 0, intent, 0)); diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java index f0190fd1..d7c24f9a 100644 --- a/src/com/android/providers/downloads/DownloadProvider.java +++ b/src/com/android/providers/downloads/DownloadProvider.java @@ -21,7 +21,9 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.UriMatcher; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.database.CrossProcessCursor; import android.database.Cursor; import android.database.CursorWindow; @@ -76,21 +78,21 @@ public final class DownloadProvider extends ContentProvider { } private static final String[] sAppReadableColumnsArray = new String[] { - Downloads._ID, - Downloads.COLUMN_APP_DATA, - Downloads._DATA, - 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 + Downloads.Impl._ID, + Downloads.Impl.COLUMN_APP_DATA, + Downloads.Impl._DATA, + Downloads.Impl.COLUMN_MIME_TYPE, + Downloads.Impl.COLUMN_VISIBILITY, + Downloads.Impl.COLUMN_DESTINATION, + Downloads.Impl.COLUMN_CONTROL, + Downloads.Impl.COLUMN_STATUS, + Downloads.Impl.COLUMN_LAST_MODIFICATION, + Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, + Downloads.Impl.COLUMN_NOTIFICATION_CLASS, + Downloads.Impl.COLUMN_TOTAL_BYTES, + Downloads.Impl.COLUMN_CURRENT_BYTES, + Downloads.Impl.COLUMN_TITLE, + Downloads.Impl.COLUMN_DESCRIPTION }; private static HashSet<String> sAppReadableColumnsSet; @@ -104,6 +106,10 @@ public final class DownloadProvider extends ContentProvider { /** The database that lies underneath this content provider */ private SQLiteOpenHelper mOpenHelper = null; + /** List of uids that can access the downloads */ + private int mSystemUid = -1; + private int mDefContainerUid = -1; + /** * Creates and updated database on demand when opening it. * Helper class to create database the first time the provider is @@ -167,6 +173,21 @@ public final class DownloadProvider extends ContentProvider { @Override public boolean onCreate() { mOpenHelper = new DatabaseHelper(getContext()); + // Initialize the system uid + mSystemUid = Process.SYSTEM_UID; + // Initialize the default container uid. Package name hardcoded + // for now. + ApplicationInfo appInfo = null; + try { + appInfo = getContext().getPackageManager(). + getApplicationInfo("com.android.defcontainer", 0); + } catch (NameNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if (appInfo != null) { + mDefContainerUid = appInfo.uid; + } return true; } @@ -199,35 +220,35 @@ public final class DownloadProvider extends ContentProvider { private void createTable(SQLiteDatabase db) { try { db.execSQL("CREATE TABLE " + DB_TABLE + "(" + - Downloads._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + - Downloads.COLUMN_URI + " TEXT, " + + Downloads.Impl._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + Downloads.Impl.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, " + + Downloads.Impl.COLUMN_APP_DATA + " TEXT, " + + Downloads.Impl.COLUMN_NO_INTEGRITY + " BOOLEAN, " + + Downloads.Impl.COLUMN_FILE_NAME_HINT + " TEXT, " + Constants.OTA_UPDATE + " BOOLEAN, " + - Downloads._DATA + " TEXT, " + - Downloads.COLUMN_MIME_TYPE + " TEXT, " + - Downloads.COLUMN_DESTINATION + " INTEGER, " + + Downloads.Impl._DATA + " TEXT, " + + Downloads.Impl.COLUMN_MIME_TYPE + " TEXT, " + + Downloads.Impl.COLUMN_DESTINATION + " INTEGER, " + Constants.NO_SYSTEM_FILES + " BOOLEAN, " + - Downloads.COLUMN_VISIBILITY + " INTEGER, " + - Downloads.COLUMN_CONTROL + " INTEGER, " + - Downloads.COLUMN_STATUS + " INTEGER, " + + Downloads.Impl.COLUMN_VISIBILITY + " INTEGER, " + + Downloads.Impl.COLUMN_CONTROL + " INTEGER, " + + Downloads.Impl.COLUMN_STATUS + " INTEGER, " + Constants.FAILED_CONNECTIONS + " 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, " + + Downloads.Impl.COLUMN_LAST_MODIFICATION + " BIGINT, " + + Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE + " TEXT, " + + Downloads.Impl.COLUMN_NOTIFICATION_CLASS + " TEXT, " + + Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS + " TEXT, " + + Downloads.Impl.COLUMN_COOKIE_DATA + " TEXT, " + + Downloads.Impl.COLUMN_USER_AGENT + " TEXT, " + + Downloads.Impl.COLUMN_REFERER + " TEXT, " + + Downloads.Impl.COLUMN_TOTAL_BYTES + " INTEGER, " + + Downloads.Impl.COLUMN_CURRENT_BYTES + " INTEGER, " + Constants.ETAG + " TEXT, " + Constants.UID + " INTEGER, " + - Downloads.COLUMN_OTHER_UID + " INTEGER, " + - Downloads.COLUMN_TITLE + " TEXT, " + - Downloads.COLUMN_DESCRIPTION + " TEXT, " + + Downloads.Impl.COLUMN_OTHER_UID + " INTEGER, " + + Downloads.Impl.COLUMN_TITLE + " TEXT, " + + Downloads.Impl.COLUMN_DESCRIPTION + " TEXT, " + Constants.MEDIA_SCANNED + " BOOLEAN);"); } catch (SQLException ex) { Log.e(Constants.TAG, "couldn't create table in downloads database"); @@ -263,70 +284,71 @@ public final class DownloadProvider extends ContentProvider { ContentValues filteredValues = new ContentValues(); - 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); + copyString(Downloads.Impl.COLUMN_URI, values, filteredValues); + copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues); + copyBoolean(Downloads.Impl.COLUMN_NO_INTEGRITY, values, filteredValues); + copyString(Downloads.Impl.COLUMN_FILE_NAME_HINT, values, filteredValues); + copyString(Downloads.Impl.COLUMN_MIME_TYPE, values, filteredValues); + Integer dest = values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION); if (dest != null) { - if (getContext().checkCallingPermission(Downloads.PERMISSION_ACCESS_ADVANCED) + if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED) != PackageManager.PERMISSION_GRANTED - && dest != Downloads.DESTINATION_EXTERNAL - && dest != Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE) { + && dest != Downloads.Impl.DESTINATION_EXTERNAL + && dest != Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE) { throw new SecurityException("unauthorized destination code"); } - filteredValues.put(Downloads.COLUMN_DESTINATION, dest); + filteredValues.put(Downloads.Impl.COLUMN_DESTINATION, dest); } - Integer vis = values.getAsInteger(Downloads.COLUMN_VISIBILITY); + Integer vis = values.getAsInteger(Downloads.Impl.COLUMN_VISIBILITY); if (vis == null) { - if (dest == Downloads.DESTINATION_EXTERNAL) { - filteredValues.put(Downloads.COLUMN_VISIBILITY, - Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + if (dest == Downloads.Impl.DESTINATION_EXTERNAL) { + filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, + Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); } else { - filteredValues.put(Downloads.COLUMN_VISIBILITY, Downloads.VISIBILITY_HIDDEN); + filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, + Downloads.Impl.VISIBILITY_HIDDEN); } } else { - filteredValues.put(Downloads.COLUMN_VISIBILITY, vis); + filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, vis); } - 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); + copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues); + filteredValues.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING); + filteredValues.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, System.currentTimeMillis()); + String pckg = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE); + String clazz = values.getAsString(Downloads.Impl.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.COLUMN_NOTIFICATION_PACKAGE, pckg); - filteredValues.put(Downloads.COLUMN_NOTIFICATION_CLASS, clazz); + filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, pckg); + filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_CLASS, clazz); } } catch (PackageManager.NameNotFoundException ex) { /* ignored for now */ } } - 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) + copyString(Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS, values, filteredValues); + copyString(Downloads.Impl.COLUMN_COOKIE_DATA, values, filteredValues); + copyString(Downloads.Impl.COLUMN_USER_AGENT, values, filteredValues); + copyString(Downloads.Impl.COLUMN_REFERER, values, filteredValues); + if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED) == PackageManager.PERMISSION_GRANTED) { - copyInteger(Downloads.COLUMN_OTHER_UID, values, filteredValues); + copyInteger(Downloads.Impl.COLUMN_OTHER_UID, values, filteredValues); } filteredValues.put(Constants.UID, Binder.getCallingUid()); if (Binder.getCallingUid() == 0) { copyInteger(Constants.UID, values, filteredValues); } - copyString(Downloads.COLUMN_TITLE, values, filteredValues); - copyString(Downloads.COLUMN_DESCRIPTION, values, filteredValues); + copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues); + copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues); if (Constants.LOGVV) { Log.v(Constants.TAG, "initiating download with UID " + filteredValues.getAsInteger(Constants.UID)); - if (filteredValues.containsKey(Downloads.COLUMN_OTHER_UID)) { + if (filteredValues.containsKey(Downloads.Impl.COLUMN_OTHER_UID)) { Log.v(Constants.TAG, "other UID " + - filteredValues.getAsInteger(Downloads.COLUMN_OTHER_UID)); + filteredValues.getAsInteger(Downloads.Impl.COLUMN_OTHER_UID)); } } @@ -339,7 +361,7 @@ public final class DownloadProvider extends ContentProvider { if (rowID != -1) { context.startService(new Intent(context, DownloadService.class)); - ret = Uri.parse(Downloads.CONTENT_URI + "/" + rowID); + ret = Uri.parse(Downloads.Impl.CONTENT_URI + "/" + rowID); context.getContentResolver().notifyChange(uri, null); } else { if (Config.LOGD) { @@ -373,7 +395,7 @@ public final class DownloadProvider extends ContentProvider { } case DOWNLOADS_ID: { qb.setTables(DB_TABLE); - qb.appendWhere(Downloads._ID + "="); + qb.appendWhere(Downloads.Impl._ID + "="); qb.appendWhere(uri.getPathSegments().get(1)); emptyWhere = false; break; @@ -386,25 +408,45 @@ public final class DownloadProvider extends ContentProvider { } } - if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0 && + int callingUid = Binder.getCallingUid(); + if (Binder.getCallingPid() != Process.myPid() && + callingUid != mSystemUid && + callingUid != mDefContainerUid && Process.supportsProcesses()) { - if (!emptyWhere) { - qb.appendWhere(" AND "); - } - qb.appendWhere("( " + Constants.UID + "=" + Binder.getCallingUid() + " OR " - + Downloads.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )"); - emptyWhere = false; - + boolean canSeeAllExternal; if (projection == null) { projection = sAppReadableColumnsArray; + // sAppReadableColumnsArray includes _DATA, which is not allowed + // to be seen except by the initiating application + canSeeAllExternal = false; } else { + canSeeAllExternal = getContext().checkCallingPermission( + Downloads.Impl.PERMISSION_SEE_ALL_EXTERNAL) + == PackageManager.PERMISSION_GRANTED; for (int i = 0; i < projection.length; ++i) { if (!sAppReadableColumnsSet.contains(projection[i])) { throw new IllegalArgumentException( "column " + projection[i] + " is not allowed in queries"); } + canSeeAllExternal = canSeeAllExternal + && !projection[i].equals(Downloads.Impl._DATA); } } + if (!emptyWhere) { + qb.appendWhere(" AND "); + emptyWhere = false; + } + String validUid = "( " + Constants.UID + "=" + + Binder.getCallingUid() + " OR " + + Downloads.Impl.COLUMN_OTHER_UID + "=" + + Binder.getCallingUid() + " )"; + if (canSeeAllExternal) { + qb.appendWhere("( " + validUid + " OR " + + Downloads.Impl.DESTINATION_EXTERNAL + " = " + + Downloads.Impl.COLUMN_DESTINATION + " )"); + } else { + qb.appendWhere(validUid); + } } if (Constants.LOGVV) { @@ -489,18 +531,28 @@ public final class DownloadProvider extends ContentProvider { ContentValues filteredValues; if (Binder.getCallingPid() != Process.myPid()) { filteredValues = new ContentValues(); - copyString(Downloads.COLUMN_APP_DATA, values, filteredValues); - copyInteger(Downloads.COLUMN_VISIBILITY, values, filteredValues); - Integer i = values.getAsInteger(Downloads.COLUMN_CONTROL); + copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues); + copyInteger(Downloads.Impl.COLUMN_VISIBILITY, values, filteredValues); + Integer i = values.getAsInteger(Downloads.Impl.COLUMN_CONTROL); if (i != null) { - filteredValues.put(Downloads.COLUMN_CONTROL, i); + filteredValues.put(Downloads.Impl.COLUMN_CONTROL, i); startService = true; } - copyInteger(Downloads.COLUMN_CONTROL, values, filteredValues); - copyString(Downloads.COLUMN_TITLE, values, filteredValues); - copyString(Downloads.COLUMN_DESCRIPTION, values, filteredValues); + copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues); + copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues); + copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues); } else { filteredValues = values; + String filename = values.getAsString(Downloads.Impl._DATA); + if (filename != null) { + Cursor c = query(uri, new String[] + { Downloads.Impl.COLUMN_TITLE }, null, null, null); + if (!c.moveToFirst() || c.getString(0) == null) { + values.put(Downloads.Impl.COLUMN_TITLE, + new File(filename).getName()); + } + c.close(); + } } int match = sURIMatcher.match(uri); switch (match) { @@ -519,11 +571,14 @@ public final class DownloadProvider extends ContentProvider { if (match == DOWNLOADS_ID) { String segment = uri.getPathSegments().get(1); rowId = Long.parseLong(segment); - myWhere += " ( " + Downloads._ID + " = " + rowId + " ) "; + myWhere += " ( " + Downloads.Impl._ID + " = " + rowId + " ) "; } - if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0) { + int callingUid = Binder.getCallingUid(); + if (Binder.getCallingPid() != Process.myPid() && + callingUid != mSystemUid && + callingUid != mDefContainerUid) { myWhere += " AND ( " + Constants.UID + "=" + Binder.getCallingUid() + " OR " - + Downloads.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )"; + + Downloads.Impl.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )"; } if (filteredValues.size() > 0) { count = db.update(DB_TABLE, filteredValues, myWhere, whereArgs); @@ -575,11 +630,15 @@ public final class DownloadProvider extends ContentProvider { if (match == DOWNLOADS_ID) { String segment = uri.getPathSegments().get(1); long rowId = Long.parseLong(segment); - myWhere += " ( " + Downloads._ID + " = " + rowId + " ) "; + myWhere += " ( " + Downloads.Impl._ID + " = " + rowId + " ) "; } - if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0) { + int callingUid = Binder.getCallingUid(); + if (Binder.getCallingPid() != Process.myPid() && + callingUid != mSystemUid && + callingUid != mDefContainerUid) { myWhere += " AND ( " + Constants.UID + "=" + Binder.getCallingUid() + " OR " - + Downloads.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )"; + + Downloads.Impl.COLUMN_OTHER_UID + "=" + + Binder.getCallingUid() + " )"; } count = db.delete(DB_TABLE, myWhere, whereArgs); break; @@ -604,7 +663,8 @@ public final class DownloadProvider extends ContentProvider { if (Constants.LOGVV) { Log.v(Constants.TAG, "openFile uri: " + uri + ", mode: " + mode + ", uid: " + Binder.getCallingUid()); - Cursor cursor = query(Downloads.CONTENT_URI, new String[] { "_id" }, null, null, "_id"); + Cursor cursor = query(Downloads.Impl.CONTENT_URI, + new String[] { "_id" }, null, null, "_id"); if (cursor == null) { Log.v(Constants.TAG, "null cursor in openFile"); } else { @@ -673,7 +733,7 @@ public final class DownloadProvider extends ContentProvider { throw new FileNotFoundException("couldn't open file"); } else { ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_LAST_MODIFICATION, System.currentTimeMillis()); + values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, System.currentTimeMillis()); update(uri, values, null, null); } return ret; diff --git a/src/com/android/providers/downloads/DownloadReceiver.java b/src/com/android/providers/downloads/DownloadReceiver.java index 2065c649..e8f10e7d 100644 --- a/src/com/android/providers/downloads/DownloadReceiver.java +++ b/src/com/android/providers/downloads/DownloadReceiver.java @@ -86,22 +86,23 @@ public class DownloadReceiver extends BroadcastReceiver { intent.getData(), null, null, null, null); if (cursor != null) { if (cursor.moveToFirst()) { - int statusColumn = cursor.getColumnIndexOrThrow(Downloads.COLUMN_STATUS); + int statusColumn = cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS); int status = cursor.getInt(statusColumn); int visibilityColumn = - cursor.getColumnIndexOrThrow(Downloads.COLUMN_VISIBILITY); + cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_VISIBILITY); int visibility = cursor.getInt(visibilityColumn); - if (Downloads.isStatusCompleted(status) - && visibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) { + if (Downloads.Impl.isStatusCompleted(status) + && visibility == Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) { ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_VISIBILITY, Downloads.VISIBILITY_VISIBLE); + values.put(Downloads.Impl.COLUMN_VISIBILITY, + Downloads.Impl.VISIBILITY_VISIBLE); context.getContentResolver().update(intent.getData(), values, null, null); } if (intent.getAction().equals(Constants.ACTION_OPEN)) { - int filenameColumn = cursor.getColumnIndexOrThrow(Downloads._DATA); + int filenameColumn = cursor.getColumnIndexOrThrow(Downloads.Impl._DATA); int mimetypeColumn = - cursor.getColumnIndexOrThrow(Downloads.COLUMN_MIME_TYPE); + cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_MIME_TYPE); String filename = cursor.getString(filenameColumn); String mimetype = cursor.getString(mimetypeColumn); Uri path = Uri.parse(filename); @@ -122,17 +123,18 @@ public class DownloadReceiver extends BroadcastReceiver { // swallow the exception entirely } } else { - int packageColumn = - cursor.getColumnIndexOrThrow(Downloads.COLUMN_NOTIFICATION_PACKAGE); - int classColumn = - cursor.getColumnIndexOrThrow(Downloads.COLUMN_NOTIFICATION_CLASS); + int packageColumn = cursor.getColumnIndexOrThrow( + Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE); + int classColumn = cursor.getColumnIndexOrThrow( + Downloads.Impl.COLUMN_NOTIFICATION_CLASS); String pckg = cursor.getString(packageColumn); String clazz = cursor.getString(classColumn); if (pckg != null && clazz != null) { - Intent appIntent = new Intent(Downloads.ACTION_NOTIFICATION_CLICKED); + Intent appIntent = + new Intent(Downloads.Impl.ACTION_NOTIFICATION_CLICKED); appIntent.setClassName(pckg, clazz); if (intent.getBooleanExtra("multiple", true)) { - appIntent.setData(Downloads.CONTENT_URI); + appIntent.setData(Downloads.Impl.CONTENT_URI); } else { appIntent.setData(intent.getData()); } @@ -155,15 +157,16 @@ public class DownloadReceiver extends BroadcastReceiver { intent.getData(), null, null, null, null); if (cursor != null) { if (cursor.moveToFirst()) { - int statusColumn = cursor.getColumnIndexOrThrow(Downloads.COLUMN_STATUS); + int statusColumn = cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS); int status = cursor.getInt(statusColumn); int visibilityColumn = - cursor.getColumnIndexOrThrow(Downloads.COLUMN_VISIBILITY); + cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_VISIBILITY); int visibility = cursor.getInt(visibilityColumn); - if (Downloads.isStatusCompleted(status) - && visibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) { + if (Downloads.Impl.isStatusCompleted(status) + && visibility == Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) { ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_VISIBILITY, Downloads.VISIBILITY_VISIBLE); + values.put(Downloads.Impl.COLUMN_VISIBILITY, + Downloads.Impl.VISIBILITY_VISIBLE); context.getContentResolver().update(intent.getData(), values, null, null); } } diff --git a/src/com/android/providers/downloads/DownloadService.java b/src/com/android/providers/downloads/DownloadService.java index a246d29f..9e890ea0 100644 --- a/src/com/android/providers/downloads/DownloadService.java +++ b/src/com/android/providers/downloads/DownloadService.java @@ -203,7 +203,7 @@ public class DownloadService extends Service { mDownloads = Lists.newArrayList(); mObserver = new DownloadManagerContentObserver(); - getContentResolver().registerContentObserver(Downloads.CONTENT_URI, + getContentResolver().registerContentObserver(Downloads.Impl.CONTENT_URI, true, mObserver); mMediaScannerService = null; @@ -307,8 +307,8 @@ public class DownloadService extends Service { boolean networkRoaming = Helpers.isNetworkRoaming(DownloadService.this); long now = System.currentTimeMillis(); - Cursor cursor = getContentResolver().query(Downloads.CONTENT_URI, - null, null, null, Downloads._ID); + Cursor cursor = getContentResolver().query(Downloads.Impl.CONTENT_URI, + null, null, null, Downloads.Impl._ID); if (cursor == null) { // TODO: this doesn't look right, it'd leave the loop in an inconsistent state @@ -325,7 +325,7 @@ public class DownloadService extends Service { boolean isAfterLast = cursor.isAfterLast(); - int idColumn = cursor.getColumnIndexOrThrow(Downloads._ID); + int idColumn = cursor.getColumnIndexOrThrow(Downloads.Impl._ID); /* * Walk the cursor and the local array to keep them in sync. The key @@ -491,8 +491,8 @@ public class DownloadService extends Service { fileSet.add(files[i].getPath()); } - Cursor cursor = getContentResolver().query(Downloads.CONTENT_URI, - new String[] { Downloads._DATA }, null, null, null); + Cursor cursor = getContentResolver().query(Downloads.Impl.CONTENT_URI, + new String[] { Downloads.Impl._DATA }, null, null, null); if (cursor != null) { if (cursor.moveToFirst()) { do { @@ -515,10 +515,10 @@ public class DownloadService extends Service { * Drops old rows from the database to prevent it from growing too large */ private void trimDatabase() { - Cursor cursor = getContentResolver().query(Downloads.CONTENT_URI, - new String[] { Downloads._ID }, - Downloads.COLUMN_STATUS + " >= '200'", null, - Downloads.COLUMN_LAST_MODIFICATION); + Cursor cursor = getContentResolver().query(Downloads.Impl.CONTENT_URI, + new String[] { Downloads.Impl._ID }, + Downloads.Impl.COLUMN_STATUS + " >= '200'", null, + Downloads.Impl.COLUMN_LAST_MODIFICATION); if (cursor == null) { // This isn't good - if we can't do basic queries in our database, nothing's gonna work Log.e(Constants.TAG, "null cursor in trimDatabase"); @@ -526,11 +526,11 @@ public class DownloadService extends Service { } if (cursor.moveToFirst()) { int numDelete = cursor.getCount() - Constants.MAX_DOWNLOADS; - int columnId = cursor.getColumnIndexOrThrow(Downloads._ID); + int columnId = cursor.getColumnIndexOrThrow(Downloads.Impl._ID); while (numDelete > 0) { getContentResolver().delete( - ContentUris.withAppendedId(Downloads.CONTENT_URI, cursor.getLong(columnId)), - null, null); + ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, + cursor.getLong(columnId)), null, null); if (!cursor.moveToNext()) { break; } @@ -547,35 +547,39 @@ public class DownloadService extends Service { private void insertDownload( Cursor cursor, int arrayPos, boolean networkAvailable, boolean networkRoaming, long now) { - int statusColumn = cursor.getColumnIndexOrThrow(Downloads.COLUMN_STATUS); + int statusColumn = cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS); int failedColumn = cursor.getColumnIndexOrThrow(Constants.FAILED_CONNECTIONS); int retryRedirect = cursor.getInt(cursor.getColumnIndexOrThrow(Constants.RETRY_AFTER_X_REDIRECT_COUNT)); DownloadInfo info = new DownloadInfo( - cursor.getInt(cursor.getColumnIndexOrThrow(Downloads._ID)), - cursor.getString(cursor.getColumnIndexOrThrow(Downloads.COLUMN_URI)), - cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.COLUMN_NO_INTEGRITY)) == 1, - cursor.getString(cursor.getColumnIndexOrThrow(Downloads.COLUMN_FILE_NAME_HINT)), - cursor.getString(cursor.getColumnIndexOrThrow(Downloads._DATA)), - cursor.getString(cursor.getColumnIndexOrThrow(Downloads.COLUMN_MIME_TYPE)), - cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.COLUMN_DESTINATION)), - cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.COLUMN_VISIBILITY)), - cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.COLUMN_CONTROL)), + cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl._ID)), + cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_URI)), + cursor.getInt(cursor.getColumnIndexOrThrow( + Downloads.Impl.COLUMN_NO_INTEGRITY)) == 1, + cursor.getString(cursor.getColumnIndexOrThrow( + Downloads.Impl.COLUMN_FILE_NAME_HINT)), + cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl._DATA)), + cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_MIME_TYPE)), + cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_DESTINATION)), + cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_VISIBILITY)), + cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_CONTROL)), cursor.getInt(statusColumn), cursor.getInt(failedColumn), retryRedirect & 0xfffffff, retryRedirect >> 28, - cursor.getLong(cursor.getColumnIndexOrThrow(Downloads.COLUMN_LAST_MODIFICATION)), + cursor.getLong(cursor.getColumnIndexOrThrow( + Downloads.Impl.COLUMN_LAST_MODIFICATION)), + cursor.getString(cursor.getColumnIndexOrThrow( + Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE)), cursor.getString(cursor.getColumnIndexOrThrow( - Downloads.COLUMN_NOTIFICATION_PACKAGE)), - cursor.getString(cursor.getColumnIndexOrThrow(Downloads.COLUMN_NOTIFICATION_CLASS)), + Downloads.Impl.COLUMN_NOTIFICATION_CLASS)), cursor.getString(cursor.getColumnIndexOrThrow( - Downloads.COLUMN_NOTIFICATION_EXTRAS)), - cursor.getString(cursor.getColumnIndexOrThrow(Downloads.COLUMN_COOKIE_DATA)), - cursor.getString(cursor.getColumnIndexOrThrow(Downloads.COLUMN_USER_AGENT)), - cursor.getString(cursor.getColumnIndexOrThrow(Downloads.COLUMN_REFERER)), - cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.COLUMN_TOTAL_BYTES)), - cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.COLUMN_CURRENT_BYTES)), + Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS)), + cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_COOKIE_DATA)), + cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_USER_AGENT)), + cursor.getString(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_REFERER)), + cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_TOTAL_BYTES)), + cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_CURRENT_BYTES)), cursor.getString(cursor.getColumnIndexOrThrow(Constants.ETAG)), cursor.getInt(cursor.getColumnIndexOrThrow(Constants.MEDIA_SCANNED)) == 1); @@ -609,36 +613,36 @@ public class DownloadService extends Service { mDownloads.add(arrayPos, info); if (info.mStatus == 0 - && (info.mDestination == Downloads.DESTINATION_EXTERNAL - || info.mDestination == Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE) + && (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) { if (Config.LOGD) { Log.d(Constants.TAG, "no application to handle MIME type " + info.mMimeType); } - info.mStatus = Downloads.STATUS_NOT_ACCEPTABLE; + info.mStatus = Downloads.Impl.STATUS_NOT_ACCEPTABLE; - Uri uri = ContentUris.withAppendedId(Downloads.CONTENT_URI, info.mId); + Uri uri = ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, info.mId); ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_STATUS, Downloads.STATUS_NOT_ACCEPTABLE); + values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_NOT_ACCEPTABLE); getContentResolver().update(uri, values, null, null); info.sendIntentIfRequested(uri, this); return; @@ -654,12 +658,12 @@ public class DownloadService extends Service { if (info.mHasActiveThread) { throw new IllegalStateException("Multiple threads on same download on insert"); } - if (info.mStatus != Downloads.STATUS_RUNNING) { - info.mStatus = Downloads.STATUS_RUNNING; + if (info.mStatus != Downloads.Impl.STATUS_RUNNING) { + info.mStatus = Downloads.Impl.STATUS_RUNNING; ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_STATUS, info.mStatus); + values.put(Downloads.Impl.COLUMN_STATUS, info.mStatus); getContentResolver().update( - ContentUris.withAppendedId(Downloads.CONTENT_URI, info.mId), + ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, info.mId), values, null, null); } DownloadThread downloader = new DownloadThread(this, info); @@ -668,12 +672,12 @@ public class DownloadService extends Service { } } else { if (info.mStatus == 0 - || info.mStatus == Downloads.STATUS_PENDING - || info.mStatus == Downloads.STATUS_RUNNING) { - info.mStatus = Downloads.STATUS_RUNNING_PAUSED; - Uri uri = ContentUris.withAppendedId(Downloads.CONTENT_URI, info.mId); + || info.mStatus == Downloads.Impl.STATUS_PENDING + || info.mStatus == Downloads.Impl.STATUS_RUNNING) { + info.mStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; + Uri uri = ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, info.mId); ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_STATUS, Downloads.STATUS_RUNNING_PAUSED); + values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_RUNNING_PAUSED); getContentResolver().update(uri, values, null, null); } } @@ -686,30 +690,32 @@ public class DownloadService extends Service { Cursor cursor, int arrayPos, boolean networkAvailable, boolean networkRoaming, long now) { DownloadInfo info = (DownloadInfo) mDownloads.get(arrayPos); - int statusColumn = cursor.getColumnIndexOrThrow(Downloads.COLUMN_STATUS); + int statusColumn = cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS); int failedColumn = cursor.getColumnIndexOrThrow(Constants.FAILED_CONNECTIONS); - info.mId = cursor.getInt(cursor.getColumnIndexOrThrow(Downloads._ID)); - info.mUri = stringFromCursor(info.mUri, cursor, Downloads.COLUMN_URI); - info.mNoIntegrity = - cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.COLUMN_NO_INTEGRITY)) == 1; - info.mHint = stringFromCursor(info.mHint, cursor, Downloads.COLUMN_FILE_NAME_HINT); - info.mFileName = stringFromCursor(info.mFileName, cursor, Downloads._DATA); - info.mMimeType = stringFromCursor(info.mMimeType, cursor, Downloads.COLUMN_MIME_TYPE); + 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.COLUMN_DESTINATION)); + Downloads.Impl.COLUMN_DESTINATION)); int newVisibility = cursor.getInt(cursor.getColumnIndexOrThrow( - Downloads.COLUMN_VISIBILITY)); - if (info.mVisibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED - && newVisibility != Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED - && Downloads.isStatusCompleted(info.mStatus)) { + 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)) { mNotifier.mNotificationMgr.cancel(info.mId); } info.mVisibility = newVisibility; synchronized (info) { - info.mControl = cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.COLUMN_CONTROL)); + info.mControl = cursor.getInt(cursor.getColumnIndexOrThrow( + Downloads.Impl.COLUMN_CONTROL)); } int newStatus = cursor.getInt(statusColumn); - if (!Downloads.isStatusCompleted(info.mStatus) && Downloads.isStatusCompleted(newStatus)) { + if (!Downloads.Impl.isStatusCompleted(info.mStatus) && + Downloads.Impl.isStatusCompleted(newStatus)) { mNotifier.mNotificationMgr.cancel(info.mId); } info.mStatus = newStatus; @@ -719,17 +725,19 @@ public class DownloadService extends Service { info.mRetryAfter = retryRedirect & 0xfffffff; info.mRedirectCount = retryRedirect >> 28; info.mLastMod = cursor.getLong(cursor.getColumnIndexOrThrow( - Downloads.COLUMN_LAST_MODIFICATION)); + Downloads.Impl.COLUMN_LAST_MODIFICATION)); info.mPackage = stringFromCursor( - info.mPackage, cursor, Downloads.COLUMN_NOTIFICATION_PACKAGE); - info.mClass = stringFromCursor(info.mClass, cursor, Downloads.COLUMN_NOTIFICATION_CLASS); - info.mCookies = stringFromCursor(info.mCookies, cursor, Downloads.COLUMN_COOKIE_DATA); - info.mUserAgent = stringFromCursor(info.mUserAgent, cursor, Downloads.COLUMN_USER_AGENT); - info.mReferer = stringFromCursor(info.mReferer, cursor, Downloads.COLUMN_REFERER); + 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.COLUMN_TOTAL_BYTES)); + Downloads.Impl.COLUMN_TOTAL_BYTES)); info.mCurrentBytes = cursor.getInt(cursor.getColumnIndexOrThrow( - Downloads.COLUMN_CURRENT_BYTES)); + Downloads.Impl.COLUMN_CURRENT_BYTES)); info.mETag = stringFromCursor(info.mETag, cursor, Constants.ETAG); info.mMediaScanned = cursor.getInt(cursor.getColumnIndexOrThrow(Constants.MEDIA_SCANNED)) == 1; @@ -743,11 +751,11 @@ public class DownloadService extends Service { if (info.mHasActiveThread) { throw new IllegalStateException("Multiple threads on same download on update"); } - info.mStatus = Downloads.STATUS_RUNNING; + info.mStatus = Downloads.Impl.STATUS_RUNNING; ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_STATUS, info.mStatus); + values.put(Downloads.Impl.COLUMN_STATUS, info.mStatus); getContentResolver().update( - ContentUris.withAppendedId(Downloads.CONTENT_URI, info.mId), + ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, info.mId), values, null, null); DownloadThread downloader = new DownloadThread(this, info); info.mHasActiveThread = true; @@ -792,9 +800,10 @@ public class DownloadService extends Service { */ private void deleteDownload(int arrayPos) { DownloadInfo info = (DownloadInfo) mDownloads.get(arrayPos); - if (info.mStatus == Downloads.STATUS_RUNNING) { - info.mStatus = Downloads.STATUS_CANCELED; - } else if (info.mDestination != Downloads.DESTINATION_EXTERNAL && info.mFileName != null) { + if (info.mStatus == Downloads.Impl.STATUS_RUNNING) { + info.mStatus = Downloads.Impl.STATUS_CANCELED; + } else if (info.mDestination != Downloads.Impl.DESTINATION_EXTERNAL + && info.mFileName != null) { new File(info.mFileName).delete(); } mNotifier.mNotificationMgr.cancel(info.mId); @@ -811,10 +820,10 @@ public class DownloadService extends Service { */ private long nextAction(int arrayPos, long now) { DownloadInfo info = (DownloadInfo) mDownloads.get(arrayPos); - if (Downloads.isStatusCompleted(info.mStatus)) { + if (Downloads.Impl.isStatusCompleted(info.mStatus)) { return -1; } - if (info.mStatus != Downloads.STATUS_RUNNING_PAUSED) { + if (info.mStatus != Downloads.Impl.STATUS_RUNNING_PAUSED) { return 0; } if (info.mNumFailed == 0) { @@ -841,8 +850,8 @@ public class DownloadService extends Service { private boolean shouldScanFile(int arrayPos) { DownloadInfo info = (DownloadInfo) mDownloads.get(arrayPos); return !info.mMediaScanned - && info.mDestination == Downloads.DESTINATION_EXTERNAL - && Downloads.isStatusSuccess(info.mStatus) + && info.mDestination == Downloads.Impl.DESTINATION_EXTERNAL + && Downloads.Impl.isStatusSuccess(info.mStatus) && !DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(info.mMimeType); } @@ -869,9 +878,9 @@ public class DownloadService extends Service { if (cursor != null) { ContentValues values = new ContentValues(); values.put(Constants.MEDIA_SCANNED, 1); - getContentResolver().update( - ContentUris.withAppendedId(Downloads.CONTENT_URI, - cursor.getLong(cursor.getColumnIndexOrThrow(Downloads._ID))), + getContentResolver().update(ContentUris.withAppendedId( + Downloads.Impl.CONTENT_URI, cursor.getLong( + cursor.getColumnIndexOrThrow(Downloads.Impl._ID))), values, null, null); } return true; diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java index 1ad1d4f9..d2bd3220 100644 --- a/src/com/android/providers/downloads/DownloadThread.java +++ b/src/com/android/providers/downloads/DownloadThread.java @@ -37,6 +37,7 @@ import android.provider.DrmStore; import android.util.Config; import android.util.Log; + import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; @@ -80,7 +81,7 @@ public class DownloadThread extends Thread { public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - int finalStatus = Downloads.STATUS_UNKNOWN_ERROR; + int finalStatus = Downloads.Impl.STATUS_UNKNOWN_ERROR; boolean countRetry = false; int retryAfter = 0; int redirectCount = mInfo.mRedirectCount; @@ -91,7 +92,7 @@ public class DownloadThread extends Thread { FileOutputStream stream = null; AndroidHttpClient client = null; PowerManager.WakeLock wakeLock = null; - Uri contentUri = Uri.parse(Downloads.CONTENT_URI + "/" + mInfo.mId); + Uri contentUri = Uri.parse(Downloads.Impl.CONTENT_URI + "/" + mInfo.mId); try { boolean continuingDownload = false; @@ -113,7 +114,7 @@ public class DownloadThread extends Thread { filename = mInfo.mFileName; if (filename != null) { if (!Helpers.isFilenameValid(filename)) { - finalStatus = Downloads.STATUS_FILE_ERROR; + finalStatus = Downloads.Impl.STATUS_FILE_ERROR; notifyDownloadCompleted( finalStatus, false, 0, 0, false, filename, null, mInfo.mMimeType); return; @@ -133,7 +134,7 @@ public class DownloadThread extends Thread { "can't resume interrupted non-resumable download"); } f.delete(); - finalStatus = Downloads.STATUS_PRECONDITION_FAILED; + finalStatus = Downloads.Impl.STATUS_PRECONDITION_FAILED; notifyDownloadCompleted( finalStatus, false, 0, 0, false, filename, null, mInfo.mMimeType); return; @@ -155,9 +156,9 @@ public class DownloadThread extends Thread { // progress to the database long timeLastNotification = 0; - client = AndroidHttpClient.newInstance(userAgent()); + client = AndroidHttpClient.newInstance(userAgent(), mContext); - if (stream != null && mInfo.mDestination == Downloads.DESTINATION_EXTERNAL + if (stream != null && mInfo.mDestination == Downloads.Impl.DESTINATION_EXTERNAL && !DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING .equalsIgnoreCase(mimeType)) { try { @@ -210,7 +211,7 @@ http_request_loop: Log.d(Constants.TAG, "Arg exception trying to execute request for " + mInfo.mId + " : " + ex); } - finalStatus = Downloads.STATUS_BAD_REQUEST; + finalStatus = Downloads.Impl.STATUS_BAD_REQUEST; request.abort(); break http_request_loop; } catch (IOException ex) { @@ -222,9 +223,9 @@ http_request_loop: } } if (!Helpers.isNetworkAvailable(mContext)) { - finalStatus = Downloads.STATUS_RUNNING_PAUSED; + finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; } else if (mInfo.mNumFailed < Constants.MAX_RETRIES) { - finalStatus = Downloads.STATUS_RUNNING_PAUSED; + finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; countRetry = true; } else { if (Constants.LOGV) { @@ -234,7 +235,7 @@ http_request_loop: Log.d(Constants.TAG, "IOException trying to execute request for " + mInfo.mId + " : " + ex); } - finalStatus = Downloads.STATUS_HTTP_DATA_ERROR; + finalStatus = Downloads.Impl.STATUS_HTTP_DATA_ERROR; } request.abort(); break http_request_loop; @@ -245,7 +246,7 @@ http_request_loop: if (Constants.LOGVV) { Log.v(Constants.TAG, "got HTTP response code 503"); } - finalStatus = Downloads.STATUS_RUNNING_PAUSED; + finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; countRetry = true; Header header = response.getFirstHeader("Retry-After"); if (header != null) { @@ -286,7 +287,7 @@ http_request_loop: } else if (Config.LOGD) { Log.d(Constants.TAG, "too many redirects for download " + mInfo.mId); } - finalStatus = Downloads.STATUS_TOO_MANY_REDIRECTS; + finalStatus = Downloads.Impl.STATUS_TOO_MANY_REDIRECTS; request.abort(); break http_request_loop; } @@ -311,17 +312,17 @@ http_request_loop: "Couldn't resolve redirect URI for download " + mInfo.mId); } - finalStatus = Downloads.STATUS_BAD_REQUEST; + finalStatus = Downloads.Impl.STATUS_BAD_REQUEST; request.abort(); break http_request_loop; } ++redirectCount; - finalStatus = Downloads.STATUS_RUNNING_PAUSED; + finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; request.abort(); break http_request_loop; } } - if ((!continuingDownload && statusCode != Downloads.STATUS_SUCCESS) + if ((!continuingDownload && statusCode != Downloads.Impl.STATUS_SUCCESS) || (continuingDownload && statusCode != 206)) { if (Constants.LOGV) { Log.d(Constants.TAG, "http error " + statusCode + " for " + mInfo.mUri); @@ -329,14 +330,14 @@ http_request_loop: Log.d(Constants.TAG, "http error " + statusCode + " for download " + mInfo.mId); } - if (Downloads.isStatusError(statusCode)) { + if (Downloads.Impl.isStatusError(statusCode)) { finalStatus = statusCode; } else if (statusCode >= 300 && statusCode < 400) { - finalStatus = Downloads.STATUS_UNHANDLED_REDIRECT; - } else if (continuingDownload && statusCode == Downloads.STATUS_SUCCESS) { - finalStatus = Downloads.STATUS_PRECONDITION_FAILED; + finalStatus = Downloads.Impl.STATUS_UNHANDLED_REDIRECT; + } else if (continuingDownload && statusCode == Downloads.Impl.STATUS_SUCCESS) { + finalStatus = Downloads.Impl.STATUS_PRECONDITION_FAILED; } else { - finalStatus = Downloads.STATUS_UNHANDLED_HTTP_CODE; + finalStatus = Downloads.Impl.STATUS_UNHANDLED_HTTP_CODE; } request.abort(); break http_request_loop; @@ -403,7 +404,7 @@ http_request_loop: if (Config.LOGD) { Log.d(Constants.TAG, "can't know size of download, giving up"); } - finalStatus = Downloads.STATUS_LENGTH_REQUIRED; + finalStatus = Downloads.Impl.STATUS_LENGTH_REQUIRED; request.abort(); break http_request_loop; } @@ -430,18 +431,18 @@ http_request_loop: } ContentValues values = new ContentValues(); - values.put(Downloads._DATA, filename); + values.put(Downloads.Impl._DATA, filename); if (headerETag != null) { values.put(Constants.ETAG, headerETag); } if (mimeType != null) { - values.put(Downloads.COLUMN_MIME_TYPE, mimeType); + values.put(Downloads.Impl.COLUMN_MIME_TYPE, mimeType); } int contentLength = -1; if (headerContentLength != null) { contentLength = Integer.parseInt(headerContentLength); } - values.put(Downloads.COLUMN_TOTAL_BYTES, contentLength); + values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, contentLength); mContext.getContentResolver().update(contentUri, values, null, null); } @@ -457,9 +458,9 @@ http_request_loop: } } if (!Helpers.isNetworkAvailable(mContext)) { - finalStatus = Downloads.STATUS_RUNNING_PAUSED; + finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; } else if (mInfo.mNumFailed < Constants.MAX_RETRIES) { - finalStatus = Downloads.STATUS_RUNNING_PAUSED; + finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; countRetry = true; } else { if (Constants.LOGV) { @@ -472,7 +473,7 @@ http_request_loop: Log.d(Constants.TAG, "IOException getting entity for download " + mInfo.mId + " : " + ex); } - finalStatus = Downloads.STATUS_HTTP_DATA_ERROR; + finalStatus = Downloads.Impl.STATUS_HTTP_DATA_ERROR; } request.abort(); break http_request_loop; @@ -490,7 +491,7 @@ http_request_loop: } } ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_CURRENT_BYTES, bytesSoFar); + values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, bytesSoFar); mContext.getContentResolver().update(contentUri, values, null, null); if (!mInfo.mNoIntegrity && headerETag == null) { if (Constants.LOGV) { @@ -504,11 +505,11 @@ http_request_loop: Log.d(Constants.TAG, "can't resume interrupted download with no ETag"); } - finalStatus = Downloads.STATUS_PRECONDITION_FAILED; + finalStatus = Downloads.Impl.STATUS_PRECONDITION_FAILED; } else if (!Helpers.isNetworkAvailable(mContext)) { - finalStatus = Downloads.STATUS_RUNNING_PAUSED; + finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; } else if (mInfo.mNumFailed < Constants.MAX_RETRIES) { - finalStatus = Downloads.STATUS_RUNNING_PAUSED; + finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; countRetry = true; } else { if (Constants.LOGV) { @@ -518,16 +519,16 @@ http_request_loop: Log.d(Constants.TAG, "download IOException for download " + mInfo.mId + " : " + ex); } - finalStatus = Downloads.STATUS_HTTP_DATA_ERROR; + finalStatus = Downloads.Impl.STATUS_HTTP_DATA_ERROR; } request.abort(); break http_request_loop; } if (bytesRead == -1) { // success ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_CURRENT_BYTES, bytesSoFar); + values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, bytesSoFar); if (headerContentLength == null) { - values.put(Downloads.COLUMN_TOTAL_BYTES, bytesSoFar); + values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, bytesSoFar); } mContext.getContentResolver().update(contentUri, values, null, null); if ((headerContentLength != null) @@ -541,11 +542,11 @@ http_request_loop: Log.d(Constants.TAG, "mismatched content length for " + mInfo.mId); } - finalStatus = Downloads.STATUS_LENGTH_REQUIRED; + finalStatus = Downloads.Impl.STATUS_LENGTH_REQUIRED; } else if (!Helpers.isNetworkAvailable(mContext)) { - finalStatus = Downloads.STATUS_RUNNING_PAUSED; + finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; } else if (mInfo.mNumFailed < Constants.MAX_RETRIES) { - finalStatus = Downloads.STATUS_RUNNING_PAUSED; + finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; countRetry = true; } else { if (Constants.LOGV) { @@ -554,7 +555,7 @@ http_request_loop: Log.d(Constants.TAG, "closed socket for download " + mInfo.mId); } - finalStatus = Downloads.STATUS_HTTP_DATA_ERROR; + finalStatus = Downloads.Impl.STATUS_HTTP_DATA_ERROR; } break http_request_loop; } @@ -567,7 +568,7 @@ http_request_loop: stream = new FileOutputStream(filename, true); } stream.write(data, 0, bytesRead); - if (mInfo.mDestination == Downloads.DESTINATION_EXTERNAL + if (mInfo.mDestination == Downloads.Impl.DESTINATION_EXTERNAL && !DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING .equalsIgnoreCase(mimeType)) { try { @@ -586,7 +587,7 @@ http_request_loop: } catch (IOException ex) { if (!Helpers.discardPurgeableFiles( mContext, Constants.BUFFER_SIZE)) { - finalStatus = Downloads.STATUS_FILE_ERROR; + finalStatus = Downloads.Impl.STATUS_FILE_ERROR; break http_request_loop; } } @@ -597,7 +598,7 @@ http_request_loop: && now - timeLastNotification > Constants.MIN_PROGRESS_TIME) { ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_CURRENT_BYTES, bytesSoFar); + values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, bytesSoFar); mContext.getContentResolver().update( contentUri, values, null, null); bytesNotified = bytesSoFar; @@ -608,29 +609,29 @@ http_request_loop: Log.v(Constants.TAG, "downloaded " + bytesSoFar + " for " + mInfo.mUri); } synchronized (mInfo) { - if (mInfo.mControl == Downloads.CONTROL_PAUSED) { + if (mInfo.mControl == Downloads.Impl.CONTROL_PAUSED) { if (Constants.LOGV) { Log.v(Constants.TAG, "paused " + mInfo.mUri); } - finalStatus = Downloads.STATUS_RUNNING_PAUSED; + finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED; request.abort(); break http_request_loop; } } - if (mInfo.mStatus == Downloads.STATUS_CANCELED) { + if (mInfo.mStatus == Downloads.Impl.STATUS_CANCELED) { if (Constants.LOGV) { Log.d(Constants.TAG, "canceled " + mInfo.mUri); } else if (Config.LOGD) { // Log.d(Constants.TAG, "canceled id " + mInfo.mId); } - finalStatus = Downloads.STATUS_CANCELED; + finalStatus = Downloads.Impl.STATUS_CANCELED; break http_request_loop; } } if (Constants.LOGV) { Log.v(Constants.TAG, "download completed for " + mInfo.mUri); } - finalStatus = Downloads.STATUS_SUCCESS; + finalStatus = Downloads.Impl.STATUS_SUCCESS; } break; } @@ -638,7 +639,7 @@ http_request_loop: if (Config.LOGD) { Log.d(Constants.TAG, "FileNotFoundException for " + filename + " : " + ex); } - finalStatus = Downloads.STATUS_FILE_ERROR; + finalStatus = Downloads.Impl.STATUS_FILE_ERROR; // falls through to the code that reports an error } catch (RuntimeException ex) { //sometimes the socket code throws unchecked exceptions if (Constants.LOGV) { @@ -646,7 +647,7 @@ http_request_loop: } else if (Config.LOGD) { Log.d(Constants.TAG, "Exception for id " + mInfo.mId, ex); } - finalStatus = Downloads.STATUS_UNKNOWN_ERROR; + finalStatus = Downloads.Impl.STATUS_UNKNOWN_ERROR; // falls through to the code that reports an error } finally { mInfo.mHasActiveThread = false; @@ -671,10 +672,10 @@ http_request_loop: } if (filename != null) { // if the download wasn't successful, delete the file - if (Downloads.isStatusError(finalStatus)) { + if (Downloads.Impl.isStatusError(finalStatus)) { new File(filename).delete(); filename = null; - } else if (Downloads.isStatusSuccess(finalStatus) && + } else if (Downloads.Impl.isStatusSuccess(finalStatus) && DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING .equalsIgnoreCase(mimeType)) { // transfer the file to the DRM content provider @@ -682,14 +683,14 @@ http_request_loop: Intent item = DrmStore.addDrmFile(mContext.getContentResolver(), file, null); if (item == null) { Log.w(Constants.TAG, "unable to add file " + filename + " to DrmProvider"); - finalStatus = Downloads.STATUS_UNKNOWN_ERROR; + finalStatus = Downloads.Impl.STATUS_UNKNOWN_ERROR; } else { filename = item.getDataString(); mimeType = item.getType(); } file.delete(); - } else if (Downloads.isStatusSuccess(finalStatus)) { + } else if (Downloads.Impl.isStatusSuccess(finalStatus)) { // make sure the file is readable FileUtils.setPermissions(filename, 0644, -1, -1); @@ -732,7 +733,7 @@ http_request_loop: String filename, String uri, String mimeType) { notifyThroughDatabase( status, countRetry, retryAfter, redirectCount, gotData, filename, uri, mimeType); - if (Downloads.isStatusCompleted(status)) { + if (Downloads.Impl.isStatusCompleted(status)) { notifyThroughIntent(); } } @@ -741,13 +742,13 @@ http_request_loop: int status, boolean countRetry, int retryAfter, int redirectCount, boolean gotData, String filename, String uri, String mimeType) { ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_STATUS, status); - values.put(Downloads._DATA, filename); + values.put(Downloads.Impl.COLUMN_STATUS, status); + values.put(Downloads.Impl._DATA, filename); if (uri != null) { - values.put(Downloads.COLUMN_URI, uri); + values.put(Downloads.Impl.COLUMN_URI, uri); } - values.put(Downloads.COLUMN_MIME_TYPE, mimeType); - values.put(Downloads.COLUMN_LAST_MODIFICATION, System.currentTimeMillis()); + values.put(Downloads.Impl.COLUMN_MIME_TYPE, mimeType); + values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, System.currentTimeMillis()); values.put(Constants.RETRY_AFTER_X_REDIRECT_COUNT, retryAfter + (redirectCount << 28)); if (!countRetry) { values.put(Constants.FAILED_CONNECTIONS, 0); @@ -757,8 +758,8 @@ http_request_loop: values.put(Constants.FAILED_CONNECTIONS, mInfo.mNumFailed + 1); } - mContext.getContentResolver().update( - ContentUris.withAppendedId(Downloads.CONTENT_URI, mInfo.mId), values, null, null); + mContext.getContentResolver().update(ContentUris.withAppendedId( + Downloads.Impl.CONTENT_URI, mInfo.mId), values, null, null); } /** @@ -766,7 +767,7 @@ http_request_loop: * download completed even if it's not actively watching the cursor. */ private void notifyThroughIntent() { - Uri uri = Uri.parse(Downloads.CONTENT_URI + "/" + mInfo.mId); + Uri uri = Uri.parse(Downloads.Impl.CONTENT_URI + "/" + mInfo.mId); mInfo.sendIntentIfRequested(uri, mContext); } diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java index d8f262c7..1e07d421 100644 --- a/src/com/android/providers/downloads/Helpers.java +++ b/src/com/android/providers/downloads/Helpers.java @@ -91,26 +91,26 @@ public class Helpers { /* * Don't download files that we won't be able to handle */ - if (destination == Downloads.DESTINATION_EXTERNAL - || destination == Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE) { + if (destination == Downloads.Impl.DESTINATION_EXTERNAL + || destination == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE) { if (mimeType == null) { if (Config.LOGD) { Log.d(Constants.TAG, "external download with no mime type not allowed"); } - return new DownloadFileInfo(null, null, Downloads.STATUS_NOT_ACCEPTABLE); + return new DownloadFileInfo(null, null, Downloads.Impl.STATUS_NOT_ACCEPTABLE); } if (!DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(mimeType)) { // 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 intent = 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 + // nothing PackageManager pm = context.getPackageManager(); intent.setDataAndType(Uri.fromParts("file", "", null), mimeType); @@ -121,7 +121,7 @@ public class Helpers { if (Config.LOGD) { Log.d(Constants.TAG, "no handler found for type " + mimeType); } - return new DownloadFileInfo(null, null, Downloads.STATUS_NOT_ACCEPTABLE); + return new DownloadFileInfo(null, null, Downloads.Impl.STATUS_NOT_ACCEPTABLE); } } } @@ -148,10 +148,11 @@ public class Helpers { StatFs stat = null; // DRM messages should be temporarily stored internally and then passed to // the DRM content provider - if (destination == Downloads.DESTINATION_CACHE_PARTITION - || destination == Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE - || destination == Downloads.DESTINATION_CACHE_PARTITION_NOROAMING + if (destination == Downloads.Impl.DESTINATION_CACHE_PARTITION + || destination == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE + || destination == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING || DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(mimeType)) { + // Saving to internal storage. base = Environment.getDownloadCacheDirectory(); stat = new StatFs(base.getPath()); @@ -160,52 +161,58 @@ public class Helpers { * Put a bit of margin (in case creating the file grows the system by a few blocks). */ int blockSize = stat.getBlockSize(); - for (;;) { - int availableBlocks = stat.getAvailableBlocks(); - if (blockSize * ((long) availableBlocks - 4) >= contentLength) { - break; - } - if (!discardPurgeableFiles(context, - contentLength - blockSize * ((long) availableBlocks - 4))) { + long bytesAvailable = blockSize * ((long) stat.getAvailableBlocks() - 4); + while (bytesAvailable < contentLength) { + // Insufficient space; try discarding purgeable files. + if (!discardPurgeableFiles(context, contentLength - bytesAvailable)) { + // No files to purge, give up. if (Config.LOGD) { Log.d(Constants.TAG, "download aborted - not enough free space in internal storage"); } - return new DownloadFileInfo(null, null, Downloads.STATUS_FILE_ERROR); - } - stat.restat(base.getPath()); - } - - } else { - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - String root = Environment.getExternalStorageDirectory().getPath(); - base = new File(root + Constants.DEFAULT_DL_SUBDIR); - if (!base.isDirectory() && !base.mkdir()) { - if (Config.LOGD) { - Log.d(Constants.TAG, "download aborted - can't create base directory " - + base.getPath()); - } - return new DownloadFileInfo(null, null, Downloads.STATUS_FILE_ERROR); - } - stat = new StatFs(base.getPath()); - } else { - if (Config.LOGD) { - Log.d(Constants.TAG, "download aborted - no external storage"); + return new DownloadFileInfo(null, null, + Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR); + } else { + // Recalculate available space and try again. + stat.restat(base.getPath()); + bytesAvailable = blockSize * ((long) stat.getAvailableBlocks() - 4); } - return new DownloadFileInfo(null, null, Downloads.STATUS_FILE_ERROR); } + } else if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + // Saving to external storage (SD card). + String root = Environment.getExternalStorageDirectory().getPath(); + stat = new StatFs(root); /* * Check whether there's enough space on the target filesystem to save the file. * Put a bit of margin (in case creating the file grows the system by a few blocks). */ if (stat.getBlockSize() * ((long) stat.getAvailableBlocks() - 4) < contentLength) { + // Insufficient space. if (Config.LOGD) { Log.d(Constants.TAG, "download aborted - not enough free space"); } - return new DownloadFileInfo(null, null, Downloads.STATUS_FILE_ERROR); + return new DownloadFileInfo(null, null, + Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR); } + base = new File(root + Constants.DEFAULT_DL_SUBDIR); + if (!base.isDirectory() && !base.mkdir()) { + // Can't create download directory, e.g. because a file called "download" + // already exists at the root level, or the SD card filesystem is read-only. + if (Config.LOGD) { + Log.d(Constants.TAG, "download aborted - can't create base directory " + + base.getPath()); + } + return new DownloadFileInfo(null, null, Downloads.Impl.STATUS_FILE_ERROR); + } + } else { + // No SD card found. + if (Config.LOGD) { + Log.d(Constants.TAG, "download aborted - no external storage"); + } + return new DownloadFileInfo(null, null, + Downloads.Impl.STATUS_DEVICE_NOT_FOUND_ERROR); } boolean recoveryDir = Constants.RECOVERY_DIRECTORY.equalsIgnoreCase(filename + extension); @@ -224,7 +231,7 @@ public class Helpers { if (fullFilename != null) { return new DownloadFileInfo(fullFilename, new FileOutputStream(fullFilename), 0); } else { - return new DownloadFileInfo(null, null, Downloads.STATUS_FILE_ERROR); + return new DownloadFileInfo(null, null, Downloads.Impl.STATUS_FILE_ERROR); } } @@ -380,9 +387,9 @@ public class Helpers { String fullFilename = filename + extension; if (!new File(fullFilename).exists() && (!recoveryDir || - (destination != Downloads.DESTINATION_CACHE_PARTITION && - destination != Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE && - destination != Downloads.DESTINATION_CACHE_PARTITION_NOROAMING))) { + (destination != Downloads.Impl.DESTINATION_CACHE_PARTITION && + destination != Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE && + destination != Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING))) { return fullFilename; } filename = filename + Constants.FILENAME_SEQUENCE_SEPARATOR; @@ -423,14 +430,14 @@ public class Helpers { */ public static final boolean discardPurgeableFiles(Context context, long targetBytes) { Cursor cursor = context.getContentResolver().query( - Downloads.CONTENT_URI, + Downloads.Impl.CONTENT_URI, null, "( " + - Downloads.COLUMN_STATUS + " = '" + Downloads.STATUS_SUCCESS + "' AND " + - Downloads.COLUMN_DESTINATION + - " = '" + Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE + "' )", + Downloads.Impl.COLUMN_STATUS + " = '" + Downloads.Impl.STATUS_SUCCESS + "' AND " + + Downloads.Impl.COLUMN_DESTINATION + + " = '" + Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE + "' )", null, - Downloads.COLUMN_LAST_MODIFICATION); + Downloads.Impl.COLUMN_LAST_MODIFICATION); if (cursor == null) { return false; } @@ -438,16 +445,16 @@ public class Helpers { try { cursor.moveToFirst(); while (!cursor.isAfterLast() && totalFreed < targetBytes) { - File file = new File(cursor.getString(cursor.getColumnIndex(Downloads._DATA))); + File file = new File(cursor.getString(cursor.getColumnIndex(Downloads.Impl._DATA))); if (Constants.LOGVV) { Log.v(Constants.TAG, "purging " + file.getAbsolutePath() + " for " + file.length() + " bytes"); } totalFreed += file.length(); file.delete(); - long id = cursor.getLong(cursor.getColumnIndex(Downloads._ID)); + long id = cursor.getLong(cursor.getColumnIndex(Downloads.Impl._ID)); context.getContentResolver().delete( - ContentUris.withAppendedId(Downloads.CONTENT_URI, id), null, null); + ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, id), null, null); cursor.moveToNext(); } } finally { |