summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Merger (Role) <noreply-android-build-merger@google.com>2018-03-13 03:57:33 +0000
committerAndroid Build Merger (Role) <noreply-android-build-merger@google.com>2018-03-13 03:57:33 +0000
commit7d2d26d85ef8b4ad6f65e0a6a4891c10cd5467de (patch)
tree05f755188623204aa0ad8aac53b7dccc05db112f
parent45beb672fd3cd3d032cf33c419cb7dce3c4ba968 (diff)
parenta7a1b17882b75598383a620ebd36cfec41fd40c8 (diff)
downloadMediaProvider-7d2d26d85ef8b4ad6f65e0a6a4891c10cd5467de.tar.gz
[automerger] Rework thumbnail cleanup am: f6b8f04d49 am: 490368eee9 am: 1579365b16 am: a7a1b17882
Change-Id: I40c5920eb081b22dba3b1c0cfd86a568c45301d5
-rw-r--r--src/com/android/providers/media/MediaProvider.java183
1 files changed, 178 insertions, 5 deletions
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 31e23aa73..4a87e33f3 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -106,6 +106,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -2087,7 +2088,7 @@ public class MediaProvider extends ContentProvider {
}
/**
- * This method blocks until thumbnail is ready.
+ * This method requests a thumbnail and blocks until thumbnail is ready.
*
* @param thumbUri
* @return
@@ -2300,7 +2301,7 @@ public class MediaProvider extends ContentProvider {
int table = URI_MATCHER.match(uri);
List<String> prependArgs = new ArrayList<String>();
- // Log.v(TAG, "query: uri="+uri+", selection="+selection);
+ //Log.v(TAG, "query: uri="+uri+", selection="+selection);
// handle MEDIA_SCANNER before calling getDatabaseForUri()
if (table == MEDIA_SCANNER) {
if (mMediaScannerVolume == null) {
@@ -3714,6 +3715,31 @@ public class MediaProvider extends ContentProvider {
MediaScanner.clearMediaPathCache(true /* media */, false /* nomedia */);
File nomedia = new File(path);
String hiddenroot = nomedia.isDirectory() ? path : nomedia.getParent();
+
+ // query for images and videos that will be affected
+ Cursor c = db.query("files",
+ new String[] {"_id", "media_type"},
+ "_data >= ? AND _data < ? AND (media_type=1 OR media_type=3)"
+ + " AND mini_thumb_magic IS NOT NULL",
+ new String[] { hiddenroot + "/", hiddenroot + "0"},
+ null /* groupBy */, null /* having */, null /* orderBy */);
+ if(c != null) {
+ if (c.getCount() != 0) {
+ Uri imagesUri = Uri.parse("content://media/external/images/media");
+ Uri videosUri = Uri.parse("content://media/external/videos/media");
+ while (c.moveToNext()) {
+ // remove thumbnail for image/video
+ long id = c.getLong(0);
+ long mediaType = c.getLong(1);
+ Log.i(TAG, "hiding image " + id + ", removing thumbnail");
+ removeThumbnailFor(mediaType == FileColumns.MEDIA_TYPE_IMAGE ?
+ imagesUri : videosUri, db, id);
+ }
+ }
+ IoUtils.closeQuietly(c);
+ }
+
+ // set the media type of the affected entries to 0
ContentValues mediatype = new ContentValues();
mediatype.put("media_type", 0);
int numrows = db.update("files", mediatype,
@@ -4040,6 +4066,7 @@ public class MediaProvider extends ContentProvider {
logToDb(database.getWritableDatabase(), msg);
}
mMediaScannerVolume = null;
+ pruneThumbnails();
return 1;
}
@@ -4061,6 +4088,7 @@ public class MediaProvider extends ContentProvider {
}
} else {
final String volumeName = getVolumeName(uri);
+ final boolean isExternal = "external".equals(volumeName);
DatabaseHelper database = getDatabaseForUri(uri);
if (database == null) {
@@ -4078,9 +4106,12 @@ public class MediaProvider extends ContentProvider {
database.mNumQueries++;
Cursor c = db.query(sGetTableAndWhereParam.table,
sMediaTypeDataId,
- sGetTableAndWhereParam.where, whereArgs, null, null, null);
+ sGetTableAndWhereParam.where, whereArgs,
+ null /* groupBy */, null /* having */, null /* orderBy */);
String [] idvalue = new String[] { "" };
String [] playlistvalues = new String[] { "", "" };
+ MiniThumbFile imageMicroThumbs = null;
+ MiniThumbFile videoMicroThumbs = null;
try {
while (c.moveToNext()) {
final int mediaType = c.getInt(0);
@@ -4095,7 +4126,9 @@ public class MediaProvider extends ContentProvider {
idvalue[0] = String.valueOf(id);
database.mNumQueries++;
Cursor cc = db.query("thumbnails", sDataOnlyColumn,
- "image_id=?", idvalue, null, null, null);
+ "image_id=?", idvalue,
+ null /* groupBy */, null /* having */,
+ null /* orderBy */);
try {
while (cc.moveToNext()) {
deleteIfAllowed(uri, cc.getString(0));
@@ -4105,11 +4138,38 @@ public class MediaProvider extends ContentProvider {
} finally {
IoUtils.closeQuietly(cc);
}
+ if (isExternal) {
+ if (imageMicroThumbs == null) {
+ imageMicroThumbs = MiniThumbFile.instance(
+ Images.Media.EXTERNAL_CONTENT_URI);
+ }
+ imageMicroThumbs.eraseMiniThumb(id);
+ }
} else if (mediaType == FileColumns.MEDIA_TYPE_VIDEO) {
deleteIfAllowed(uri, data);
MediaDocumentsProvider.onMediaStoreDelete(getContext(),
volumeName, FileColumns.MEDIA_TYPE_VIDEO, id);
+ idvalue[0] = String.valueOf(id);
+ database.mNumQueries++;
+ Cursor cc = db.query("videothumbnails", sDataOnlyColumn,
+ "video_id=?", idvalue, null, null, null);
+ try {
+ while (cc.moveToNext()) {
+ deleteIfAllowed(uri, cc.getString(0));
+ }
+ database.mNumDeletes++;
+ db.delete("videothumbnails", "video_id=?", idvalue);
+ } finally {
+ IoUtils.closeQuietly(cc);
+ }
+ if (isExternal) {
+ if (videoMicroThumbs == null) {
+ videoMicroThumbs = MiniThumbFile.instance(
+ Video.Media.EXTERNAL_CONTENT_URI);
+ }
+ videoMicroThumbs.eraseMiniThumb(id);
+ }
} else if (mediaType == FileColumns.MEDIA_TYPE_AUDIO) {
if (!database.mInternal) {
MediaDocumentsProvider.onMediaStoreDelete(getContext(),
@@ -4145,6 +4205,12 @@ public class MediaProvider extends ContentProvider {
}
} finally {
IoUtils.closeQuietly(c);
+ if (imageMicroThumbs != null) {
+ imageMicroThumbs.deactivate();
+ }
+ if (videoMicroThumbs != null) {
+ videoMicroThumbs.deactivate();
+ }
}
}
}
@@ -4217,12 +4283,92 @@ public class MediaProvider extends ContentProvider {
throw new UnsupportedOperationException("Unsupported call: " + method);
}
+
+ /*
+ * Clean up all thumbnail files for which the source image or video no longer exists.
+ * This is called at the end of a media scan.
+ */
+ private void pruneThumbnails() {
+ Log.v(TAG, "pruneThumbnails ");
+
+ final Uri thumbsUri = Images.Thumbnails.getContentUri("external");
+
+ // Remove orphan entries in the thumbnails tables
+ DatabaseHelper helper = getDatabaseForUri(thumbsUri);
+ SQLiteDatabase db = helper.getWritableDatabase();
+ db.execSQL("delete from thumbnails where image_id not in (select _id from images)");
+ db.execSQL("delete from videothumbnails where video_id not in (select _id from video)");
+
+ // Remove cached thumbnails that are no longer referenced by the thumbnails tables
+ HashSet<String> existingFiles = new HashSet<String>();
+ try {
+ String directory = "/sdcard/DCIM/.thumbnails";
+ File dirFile = new File(directory).getCanonicalFile();
+ String[] files = dirFile.list();
+ if (files == null)
+ files = new String[0];
+
+ String dirPath = dirFile.getPath();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].endsWith(".jpg")) {
+ String fullPathString = dirPath + "/" + files[i];
+ existingFiles.add(fullPathString);
+ }
+ }
+ } catch (IOException e) {
+ return;
+ }
+
+ for (String table : new String[] {"thumbnails", "videothumbnails"}) {
+ Cursor c = db.query(table, new String [] { "_data" },
+ null, null, null, null, null); // where clause/args, groupby, having, orderby
+ if (c != null && c.moveToFirst()) {
+ do {
+ String fullPathString = c.getString(0);
+ existingFiles.remove(fullPathString);
+ } while (c.moveToNext());
+ }
+ IoUtils.closeQuietly(c);
+ }
+
+ for (String fileToDelete : existingFiles) {
+ if (LOCAL_LOGV)
+ Log.v(TAG, "fileToDelete is " + fileToDelete);
+ try {
+ (new File(fileToDelete)).delete();
+ } catch (SecurityException ex) {
+ }
+ }
+
+ Log.v(TAG, "/pruneDeadThumbnailFiles... ");
+ }
+
+ private void removeThumbnailFor(Uri uri, SQLiteDatabase db, long id) {
+ Cursor c = db.rawQuery("select _data from thumbnails where image_id=" + id
+ + " union all select _data from videothumbnails where video_id=" + id,
+ null /* selectionArgs */);
+ if (c != null) {
+ while (c.moveToNext()) {
+ String path = c.getString(0);
+ deleteIfAllowed(uri, path);
+ }
+ IoUtils.closeQuietly(c);
+ db.execSQL("delete from thumbnails where image_id=" + id);
+ db.execSQL("delete from videothumbnails where video_id=" + id);
+ }
+ MiniThumbFile microThumbs = MiniThumbFile.instance(uri);
+ microThumbs.eraseMiniThumb(id);
+ microThumbs.deactivate();
+ }
+
@Override
public int update(Uri uri, ContentValues initialValues, String userWhere,
String[] whereArgs) {
uri = safeUncanonicalize(uri);
int count;
- // Log.v(TAG, "update for uri="+uri+", initValues="+initialValues);
+ //Log.v(TAG, "update for uri=" + uri + ", initValues=" + initialValues +
+ // ", where=" + userWhere + ", args=" + Arrays.toString(whereArgs) + " caller:" +
+ // Binder.getCallingPid());
int match = URI_MATCHER.match(uri);
DatabaseHelper helper = getDatabaseForUri(uri);
if (helper == null) {
@@ -4242,6 +4388,33 @@ public class MediaProvider extends ContentProvider {
synchronized (sGetTableAndWhereParam) {
getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam);
+ // if the media type is being changed, check if it's being changed from image or video
+ // to something else
+ if (initialValues.containsKey(FileColumns.MEDIA_TYPE)) {
+ long newMediaType = initialValues.getAsLong(FileColumns.MEDIA_TYPE);
+ helper.mNumQueries++;
+ Cursor cursor = db.query(sGetTableAndWhereParam.table, sMediaTableColumns,
+ sGetTableAndWhereParam.where, whereArgs, null, null, null);
+ try {
+ while (cursor != null && cursor.moveToNext()) {
+ long curMediaType = cursor.getLong(1);
+ if (curMediaType == FileColumns.MEDIA_TYPE_IMAGE &&
+ newMediaType != FileColumns.MEDIA_TYPE_IMAGE) {
+ Log.i(TAG, "need to remove image thumbnail for id " + cursor.getString(0));
+ removeThumbnailFor(Images.Media.EXTERNAL_CONTENT_URI,
+ db, cursor.getLong(0));
+ } else if (curMediaType == FileColumns.MEDIA_TYPE_VIDEO &&
+ newMediaType != FileColumns.MEDIA_TYPE_VIDEO) {
+ Log.i(TAG, "need to remove video thumbnail for id " + cursor.getString(0));
+ removeThumbnailFor(Video.Media.EXTERNAL_CONTENT_URI,
+ db, cursor.getLong(0));
+ }
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+ }
+
// special case renaming directories via MTP.
// in this case we must update all paths in the database with
// the directory name as a prefix