summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/downloads/DownloadProvider.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/providers/downloads/DownloadProvider.java')
-rw-r--r--src/com/android/providers/downloads/DownloadProvider.java133
1 files changed, 84 insertions, 49 deletions
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
index e79aff5f..d30018f7 100644
--- a/src/com/android/providers/downloads/DownloadProvider.java
+++ b/src/com/android/providers/downloads/DownloadProvider.java
@@ -16,9 +16,18 @@
package com.android.providers.downloads;
+import static android.provider.BaseColumns._ID;
+import static android.provider.Downloads.Impl.COLUMN_DESTINATION;
+import static android.provider.Downloads.Impl.COLUMN_MEDIAPROVIDER_URI;
+import static android.provider.Downloads.Impl.COLUMN_MEDIA_SCANNED;
+import static android.provider.Downloads.Impl.COLUMN_MIME_TYPE;
+import static android.provider.Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD;
+import static android.provider.Downloads.Impl._DATA;
+
import android.app.AppOpsManager;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
+import android.app.job.JobScheduler;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -35,8 +44,6 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.os.Binder;
-import android.os.Handler;
-import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.OnCloseListener;
import android.os.Process;
@@ -47,9 +54,10 @@ import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
+import com.android.internal.util.IndentingPrintWriter;
+
import libcore.io.IoUtils;
-import com.android.internal.util.IndentingPrintWriter;
import com.google.android.collect.Maps;
import com.google.common.annotations.VisibleForTesting;
@@ -73,7 +81,7 @@ public final class DownloadProvider extends ContentProvider {
/** Database filename */
private static final String DB_NAME = "downloads.db";
/** Current database version */
- private static final int DB_VERSION = 109;
+ private static final int DB_VERSION = 110;
/** Name of table in the database */
private static final String DB_TABLE = "downloads";
@@ -170,7 +178,8 @@ public final class DownloadProvider extends ContentProvider {
private static final List<String> downloadManagerColumnsList =
Arrays.asList(DownloadManager.UNDERLYING_COLUMNS);
- private Handler mHandler;
+ @VisibleForTesting
+ SystemFacade mSystemFacade;
/** The database that lies underneath this content provider */
private SQLiteOpenHelper mOpenHelper = null;
@@ -179,9 +188,6 @@ public final class DownloadProvider extends ContentProvider {
private int mSystemUid = -1;
private int mDefContainerUid = -1;
- @VisibleForTesting
- SystemFacade mSystemFacade;
-
/**
* This class encapsulates a SQL where clause and its parameters. It makes it possible for
* shared methods (like {@link DownloadProvider#getWhereClause(Uri, String, String[], int)})
@@ -329,6 +335,11 @@ public final class DownloadProvider extends ContentProvider {
"BOOLEAN NOT NULL DEFAULT 0");
break;
+ case 110:
+ addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_FLAGS,
+ "INTEGER NOT NULL DEFAULT 0");
+ break;
+
default:
throw new IllegalStateException("Don't know how to upgrade to " + version);
}
@@ -442,11 +453,6 @@ public final class DownloadProvider extends ContentProvider {
mSystemFacade = new RealSystemFacade(getContext());
}
- HandlerThread handlerThread =
- new HandlerThread("DownloadProvider handler", Process.THREAD_PRIORITY_BACKGROUND);
- handlerThread.start();
- mHandler = new Handler(handlerThread.getLooper());
-
mOpenHelper = new DatabaseHelper(getContext());
// Initialize the system uid
mSystemUid = Process.SYSTEM_UID;
@@ -462,10 +468,6 @@ public final class DownloadProvider extends ContentProvider {
if (appInfo != null) {
mDefContainerUid = appInfo.uid;
}
- // start the DownloadService class. don't wait for the 1st download to be issued.
- // saves us by getting some initialization code in DownloadService out of the way.
- Context context = getContext();
- context.startService(new Intent(context, DownloadService.class));
return true;
}
@@ -669,6 +671,7 @@ public final class DownloadProvider extends ContentProvider {
copyInteger(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, values, filteredValues);
copyBoolean(Downloads.Impl.COLUMN_ALLOW_ROAMING, values, filteredValues);
copyBoolean(Downloads.Impl.COLUMN_ALLOW_METERED, values, filteredValues);
+ copyInteger(Downloads.Impl.COLUMN_FLAGS, values, filteredValues);
}
if (Constants.LOGVV) {
@@ -689,9 +692,18 @@ public final class DownloadProvider extends ContentProvider {
insertRequestHeaders(db, rowID, values);
notifyContentChanged(uri, match);
- // Always start service to handle notifications and/or scanning
- final Context context = getContext();
- context.startService(new Intent(context, DownloadService.class));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Helpers.scheduleJob(getContext(), rowID);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ if (values.getAsInteger(COLUMN_DESTINATION) == DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD
+ && values.getAsInteger(COLUMN_MEDIA_SCANNED) == 0) {
+ DownloadScanner.requestScanBlocking(getContext(), rowID, values.getAsString(_DATA),
+ values.getAsString(COLUMN_MIME_TYPE));
+ }
return ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, rowID);
}
@@ -806,6 +818,7 @@ public final class DownloadProvider extends ContentProvider {
values.remove(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES);
values.remove(Downloads.Impl.COLUMN_ALLOW_ROAMING);
values.remove(Downloads.Impl.COLUMN_ALLOW_METERED);
+ values.remove(Downloads.Impl.COLUMN_FLAGS);
values.remove(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI);
values.remove(Downloads.Impl.COLUMN_MEDIA_SCANNED);
values.remove(Downloads.Impl.COLUMN_ALLOW_WRITE);
@@ -1053,14 +1066,7 @@ public final class DownloadProvider extends ContentProvider {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
- boolean startService = false;
-
- if (values.containsKey(Downloads.Impl.COLUMN_DELETED)) {
- if (values.getAsInteger(Downloads.Impl.COLUMN_DELETED) == 1) {
- // some rows are to be 'deleted'. need to start DownloadService.
- startService = true;
- }
- }
+ boolean updateSchedule = false;
ContentValues filteredValues;
if (Binder.getCallingPid() != Process.myPid()) {
@@ -1070,7 +1076,7 @@ public final class DownloadProvider extends ContentProvider {
Integer i = values.getAsInteger(Downloads.Impl.COLUMN_CONTROL);
if (i != null) {
filteredValues.put(Downloads.Impl.COLUMN_CONTROL, i);
- startService = true;
+ updateSchedule = true;
}
copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues);
@@ -1099,7 +1105,7 @@ public final class DownloadProvider extends ContentProvider {
boolean isUserBypassingSizeLimit =
values.containsKey(Downloads.Impl.COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT);
if (isRestart || isUserBypassingSizeLimit) {
- startService = true;
+ updateSchedule = true;
}
}
@@ -1109,12 +1115,27 @@ public final class DownloadProvider extends ContentProvider {
case MY_DOWNLOADS_ID:
case ALL_DOWNLOADS:
case ALL_DOWNLOADS_ID:
- SqlSelection selection = getWhereClause(uri, where, whereArgs, match);
- if (filteredValues.size() > 0) {
- count = db.update(DB_TABLE, filteredValues, selection.getSelection(),
- selection.getParameters());
- } else {
+ if (filteredValues.size() == 0) {
count = 0;
+ break;
+ }
+
+ final SqlSelection selection = getWhereClause(uri, where, whereArgs, match);
+ count = db.update(DB_TABLE, filteredValues, selection.getSelection(),
+ selection.getParameters());
+ if (updateSchedule) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ try (Cursor cursor = db.query(DB_TABLE, new String[] { _ID },
+ selection.getSelection(), selection.getParameters(),
+ null, null, null)) {
+ while (cursor.moveToNext()) {
+ Helpers.scheduleJob(getContext(), cursor.getInt(0));
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
break;
@@ -1124,10 +1145,6 @@ public final class DownloadProvider extends ContentProvider {
}
notifyContentChanged(uri, match);
- if (startService) {
- Context context = getContext();
- context.startService(new Intent(context, DownloadService.class));
- }
return count;
}
@@ -1176,7 +1193,8 @@ public final class DownloadProvider extends ContentProvider {
Helpers.validateSelection(where, sAppReadableColumnsSet);
}
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ final JobScheduler scheduler = getContext().getSystemService(JobScheduler.class);
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
int match = sURIMatcher.match(uri);
switch (match) {
@@ -1184,15 +1202,16 @@ public final class DownloadProvider extends ContentProvider {
case MY_DOWNLOADS_ID:
case ALL_DOWNLOADS:
case ALL_DOWNLOADS_ID:
- SqlSelection selection = getWhereClause(uri, where, whereArgs, match);
+ final SqlSelection selection = getWhereClause(uri, where, whereArgs, match);
deleteRequestHeaders(db, selection.getSelection(), selection.getParameters());
- final Cursor cursor = db.query(DB_TABLE, new String[] {
- Downloads.Impl._ID, Downloads.Impl._DATA
- }, selection.getSelection(), selection.getParameters(), null, null, null);
- try {
+ try (Cursor cursor = db.query(DB_TABLE, new String[] {
+ _ID, _DATA, COLUMN_MEDIAPROVIDER_URI
+ }, selection.getSelection(), selection.getParameters(), null, null, null)) {
while (cursor.moveToNext()) {
final long id = cursor.getLong(0);
+ scheduler.cancel((int) id);
+
DownloadStorageProvider.onDownloadProviderDelete(getContext(), id);
final String path = cursor.getString(1);
@@ -1207,9 +1226,18 @@ public final class DownloadProvider extends ContentProvider {
} catch (IOException ignored) {
}
}
+
+ final String mediaUri = cursor.getString(2);
+ if (!TextUtils.isEmpty(mediaUri)) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ getContext().getContentResolver().delete(Uri.parse(mediaUri), null,
+ null);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
}
- } finally {
- IoUtils.closeQuietly(cursor);
}
count = db.delete(DB_TABLE, selection.getSelection(), selection.getParameters());
@@ -1270,7 +1298,13 @@ public final class DownloadProvider extends ContentProvider {
throw new FileNotFoundException("No filename found.");
}
- final File file = new File(path);
+ final File file;
+ try {
+ file = new File(path).getCanonicalFile();
+ } catch (IOException e) {
+ throw new FileNotFoundException(e.getMessage());
+ }
+
if (!Helpers.isFilenameValid(getContext(), file)) {
throw new FileNotFoundException("Invalid file: " + file);
}
@@ -1281,7 +1315,8 @@ public final class DownloadProvider extends ContentProvider {
} else {
try {
// When finished writing, update size and timestamp
- return ParcelFileDescriptor.open(file, pfdMode, mHandler, new OnCloseListener() {
+ return ParcelFileDescriptor.open(file, pfdMode, Helpers.getAsyncHandler(),
+ new OnCloseListener() {
@Override
public void onClose(IOException e) {
final ContentValues values = new ContentValues();