diff options
author | Xin Li <delphij@google.com> | 2020-08-27 10:16:59 -0700 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2020-08-27 10:16:59 -0700 |
commit | 6cac9e854d1ef119ebece53ce4669422b53e6ea9 (patch) | |
tree | 6795f53bbf55736fbb50314dc904d7ffb2b063fa | |
parent | b82ed64e09ef725b0c675f3fc30296c4844befae (diff) | |
parent | 56462add52c101b18bd0a4eb4e89b3f1c6963681 (diff) | |
download | UniversalMediaPlayer-6cac9e854d1ef119ebece53ce4669422b53e6ea9.tar.gz |
Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)temp_sam_168057903
Bug: 166295507
Merged-In: I5a6abeeeab91e9f2ce7e6f49e863d76f21bd44d6
Change-Id: I5667593cf89e4432861a5033ea57281507ddce74
-rw-r--r-- | java/com/android/pump/app/GlobalsApplication.java | 2 | ||||
-rw-r--r-- | java/com/android/pump/db/AudioStore.java | 16 | ||||
-rw-r--r-- | java/com/android/pump/db/VideoStore.java | 41 | ||||
-rw-r--r-- | java/com/android/pump/util/ImageLoader.java | 66 | ||||
-rw-r--r-- | java/com/android/pump/util/IoUtils.java | 12 | ||||
-rw-r--r-- | java/com/android/pump/util/Scheme.java | 5 | ||||
-rw-r--r-- | java/com/android/pump/widget/UriImageView.java | 3 |
7 files changed, 94 insertions, 51 deletions
diff --git a/java/com/android/pump/app/GlobalsApplication.java b/java/com/android/pump/app/GlobalsApplication.java index dc30372..27e1e43 100644 --- a/java/com/android/pump/app/GlobalsApplication.java +++ b/java/com/android/pump/app/GlobalsApplication.java @@ -32,7 +32,7 @@ public abstract class GlobalsApplication extends Application implements Globals. @Override public @NonNull ImageLoader getImageLoader() { if (mImageLoader == null) { - mImageLoader = new ImageLoader(getExecutor()); + mImageLoader = new ImageLoader(getContentResolver(), getExecutor()); } return mImageLoader; } diff --git a/java/com/android/pump/db/AudioStore.java b/java/com/android/pump/db/AudioStore.java index 4cd569b..9058a20 100644 --- a/java/com/android/pump/db/AudioStore.java +++ b/java/com/android/pump/db/AudioStore.java @@ -31,7 +31,6 @@ import androidx.annotation.WorkerThread; import com.android.pump.util.Clog; import com.android.pump.util.Collections; -import java.io.File; import java.util.ArrayList; import java.util.Collection; @@ -317,7 +316,6 @@ class AudioStore extends ContentObserver { Uri contentUri = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI; String[] projection = { - MediaStore.Audio.Albums.ALBUM_ART, MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Media.ARTIST_ID // TODO MediaStore.Audio.Albums.ARTIST_ID }; @@ -327,8 +325,6 @@ class AudioStore extends ContentObserver { contentUri, projection, selection, selectionArgs, null); if (cursor != null) { try { - int albumArtColumn = cursor.getColumnIndexOrThrow( - MediaStore.Audio.Albums.ALBUM_ART); int albumColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM); int artistIdColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID); // TODO MediaStore.Audio.Albums.ARTIST_ID @@ -337,16 +333,20 @@ class AudioStore extends ContentObserver { String albumTitle = cursor.getString(albumColumn); updated |= album.setTitle(albumTitle); } - if (!cursor.isNull(albumArtColumn)) { - Uri albumArtUri = Uri.fromFile(new File(cursor.getString(albumArtColumn))); - updated |= album.setAlbumArtUri(albumArtUri); - } if (!cursor.isNull(artistIdColumn)) { long artistId = cursor.getLong(artistIdColumn); Artist artist = mMediaProvider.getArtistById(artistId); updated |= album.setArtist(artist); updated |= loadData(artist); // TODO(b/123707561) Load separate from album } + + // TODO(b/130363861) No need to store the URI -- generate when requested instead + Uri albumArtUri = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(MediaStore.AUTHORITY) + .appendPath("external").appendPath("audio").appendPath("albumart") + .appendPath(Long.toString(album.getId())).build(); + updated |= album.setAlbumArtUri(albumArtUri); } } finally { cursor.close(); diff --git a/java/com/android/pump/db/VideoStore.java b/java/com/android/pump/db/VideoStore.java index 657c0c1..4f00b2a 100644 --- a/java/com/android/pump/db/VideoStore.java +++ b/java/com/android/pump/db/VideoStore.java @@ -17,6 +17,7 @@ package com.android.pump.db; import android.content.ContentResolver; +import android.content.ContentUris; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; @@ -43,7 +44,7 @@ class VideoStore extends ContentObserver { private static final String RELATIVE_PATH = "relative_path"; // TODO Replace with Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q throughout the code. - private static boolean isRunningQ() { + private static boolean isAtLeastRunningQ() { return Build.VERSION.SDK_INT > Build.VERSION_CODES.P || (Build.VERSION.SDK_INT == Build.VERSION_CODES.P && Build.VERSION.PREVIEW_SDK_INT > 0); @@ -101,7 +102,7 @@ class VideoStore extends ContentObserver { { Uri contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; String[] projection; - if (isRunningQ()) { + if (isAtLeastRunningQ()) { projection = new String[] { MediaStore.Video.Media._ID, MediaStore.Video.Media.MIME_TYPE, @@ -126,7 +127,7 @@ class VideoStore extends ContentObserver { int mimeTypeColumn = cursor.getColumnIndexOrThrow( MediaStore.Video.Media.MIME_TYPE); - if (isRunningQ()) { + if (isAtLeastRunningQ()) { dataColumn = -1; relativePathColumn = cursor.getColumnIndexOrThrow(RELATIVE_PATH); displayNameColumn = cursor.getColumnIndexOrThrow( @@ -142,7 +143,7 @@ class VideoStore extends ContentObserver { String mimeType = cursor.getString(mimeTypeColumn); File file; - if (isRunningQ()) { + if (isAtLeastRunningQ()) { String relativePath = cursor.getString(relativePathColumn); String displayName = cursor.getString(displayNameColumn); file = new File(relativePath, displayName); @@ -276,35 +277,9 @@ class VideoStore extends ContentObserver { } private @Nullable Uri getThumbnailUri(long id) { - int thumbKind = MediaStore.Video.Thumbnails.MINI_KIND; - - // TODO(b/123707512) The following line is required to generate thumbnails -- is there a better way? - MediaStore.Video.Thumbnails.getThumbnail(mContentResolver, id, thumbKind, null); - - Uri thumbnailUri = null; - Uri contentUri = MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI; - String[] projection = { - MediaStore.Video.Thumbnails.DATA - }; - String selection = MediaStore.Video.Thumbnails.KIND + " = " + thumbKind + " AND " + - MediaStore.Video.Thumbnails.VIDEO_ID + " = ?"; - String[] selectionArgs = { Long.toString(id) }; - Cursor cursor = mContentResolver.query( - contentUri, projection, selection, selectionArgs, null); - if (cursor != null) { - try { - int dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Thumbnails.DATA); - - if (cursor.moveToFirst()) { - String data = cursor.getString(dataColumn); - - thumbnailUri = Uri.fromFile(new File(data)); - } - } finally { - cursor.close(); - } - } - return thumbnailUri; + // TODO(b/130363861) No need to store the URI -- generate when requested instead + return ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id) + .buildUpon().appendPath("thumbnail").build(); } @Override diff --git a/java/com/android/pump/util/ImageLoader.java b/java/com/android/pump/util/ImageLoader.java index ba9b89a..0a60e66 100644 --- a/java/com/android/pump/util/ImageLoader.java +++ b/java/com/android/pump/util/ImageLoader.java @@ -16,9 +16,14 @@ package com.android.pump.util; +import android.content.ContentResolver; +import android.content.UriMatcher; +import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; +import android.os.Build; +import android.provider.MediaStore; import androidx.annotation.AnyThread; import androidx.annotation.NonNull; @@ -29,6 +34,7 @@ import androidx.collection.ArraySet; import com.android.pump.concurrent.Executors; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.AbstractMap.SimpleEntry; import java.util.LinkedList; @@ -41,8 +47,22 @@ import java.util.concurrent.Executor; public class ImageLoader { private static final String TAG = Clog.tag(ImageLoader.class); + // TODO Replace with Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q throughout the code. + private static boolean isAtLeastRunningQ() { + return Build.VERSION.SDK_INT > Build.VERSION_CODES.P + || (Build.VERSION.SDK_INT == Build.VERSION_CODES.P + && Build.VERSION.PREVIEW_SDK_INT > 0); + } + + private static final UriMatcher VIDEO_THUMBNAIL_URI_MATCHER = + new UriMatcher(UriMatcher.NO_MATCH); + static { + VIDEO_THUMBNAIL_URI_MATCHER.addURI("media", "*/video/media/#/thumbnail", 0); + } + private final BitmapCache mBitmapCache = new BitmapCache(); private final OrientationCache mOrientationCache = new OrientationCache(); + private final ContentResolver mContentResolver; private final Executor mExecutor; private final Set<Map.Entry<Executor, Callback>> mCallbacks = new ArraySet<>(); private final Map<Uri, List<Map.Entry<Executor, Callback>>> mLoadCallbacks = new ArrayMap<>(); @@ -52,7 +72,8 @@ public class ImageLoader { void onImageLoaded(@NonNull Uri uri, @Nullable Bitmap bitmap); } - public ImageLoader(@NonNull Executor executor) { + public ImageLoader(@NonNull ContentResolver contentResolver, @NonNull Executor executor) { + mContentResolver = contentResolver; mExecutor = executor; } @@ -121,15 +142,26 @@ public class ImageLoader { @Override public void run() { try { - byte[] data; - if (Scheme.isFile(mUri)) { - data = IoUtils.readFromFile(new File(mUri.getPath())); - } else if (Scheme.isHttp(mUri) || Scheme.isHttps(mUri)) { - data = Http.get(mUri.toString()); + Bitmap bitmap; + if (isAtLeastRunningQ() || !isVideoThumbnailUri(mUri)) { + byte[] data; + if (Scheme.isContent(mUri)) { + data = readFromContent(mUri); + } else if (Scheme.isFile(mUri)) { + data = IoUtils.readFromFile(new File(mUri.getPath())); + } else if (Scheme.isHttp(mUri) || Scheme.isHttps(mUri)) { + data = Http.get(mUri.toString()); + } else { + throw new IllegalArgumentException( + "Unknown scheme '" + mUri.getScheme() + "'"); + } + bitmap = decodeBitmapFromByteArray(data); } else { - throw new IllegalArgumentException("Unknown scheme '" + mUri.getScheme() + "'"); + // TODO This will always return a bitmap which is inconsistent with Q. + bitmap = MediaStore.Video.Thumbnails.getThumbnail(mContentResolver, + Long.parseLong(mUri.getPathSegments().get(3)), + MediaStore.Video.Thumbnails.MINI_KIND, null); } - Bitmap bitmap = decodeBitmapFromByteArray(data); Set<Map.Entry<Executor, Callback>> callbacks; List<Map.Entry<Executor, Callback>> loadCallbacks; synchronized (ImageLoader.this) { // TODO(b/123708613) proper lock @@ -164,5 +196,23 @@ public class ImageLoader { options.inSampleSize = 1; // TODO(b/123708796) add scaling return BitmapFactory.decodeByteArray(data, 0, data.length, options); } + + private @NonNull byte[] readFromContent(@NonNull Uri uri) throws IOException { + // TODO(b/123708796) set EXTRA_SIZE in opts + AssetFileDescriptor assetFileDescriptor = + mContentResolver.openTypedAssetFileDescriptor(uri, "image/*", null); + if (assetFileDescriptor == null) { + throw new FileNotFoundException(uri.toString()); + } + try { + return IoUtils.readFromAssetFileDescriptor(assetFileDescriptor); + } finally { + IoUtils.close(assetFileDescriptor); + } + } + + private boolean isVideoThumbnailUri(@NonNull Uri uri) { + return VIDEO_THUMBNAIL_URI_MATCHER.match(uri) != UriMatcher.NO_MATCH; + } } } diff --git a/java/com/android/pump/util/IoUtils.java b/java/com/android/pump/util/IoUtils.java index c39fe35..aec3440 100644 --- a/java/com/android/pump/util/IoUtils.java +++ b/java/com/android/pump/util/IoUtils.java @@ -16,6 +16,8 @@ package com.android.pump.util; +import android.content.res.AssetFileDescriptor; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; @@ -43,6 +45,16 @@ public final class IoUtils { } } + public static @NonNull byte[] readFromAssetFileDescriptor( + @NonNull AssetFileDescriptor assetFileDescriptor) throws IOException { + InputStream inputStream = assetFileDescriptor.createInputStream(); + try { + return readFromStream(inputStream); + } finally { + close(inputStream); + } + } + public static @NonNull byte[] readFromStream(@NonNull InputStream inputStream) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); diff --git a/java/com/android/pump/util/Scheme.java b/java/com/android/pump/util/Scheme.java index ad544e3..7c52ec4 100644 --- a/java/com/android/pump/util/Scheme.java +++ b/java/com/android/pump/util/Scheme.java @@ -26,10 +26,15 @@ import androidx.annotation.NonNull; public final class Scheme { private Scheme() { } + private final static String CONTENT = ContentResolver.SCHEME_CONTENT; private final static String FILE = ContentResolver.SCHEME_FILE; private final static String HTTP = "http"; private final static String HTTPS = "https"; + public static boolean isContent(@NonNull Uri uri) { + return CONTENT.equals(uri.getScheme()); + } + public static boolean isFile(@NonNull Uri uri) { return FILE.equals(uri.getScheme()); } diff --git a/java/com/android/pump/widget/UriImageView.java b/java/com/android/pump/widget/UriImageView.java index 7381a8e..f10425e 100644 --- a/java/com/android/pump/widget/UriImageView.java +++ b/java/com/android/pump/widget/UriImageView.java @@ -73,7 +73,8 @@ public class UriImageView extends PlaceholderImageView { if (uri == null) { return; } - if (Scheme.isFile(uri) || Scheme.isHttp(uri) || Scheme.isHttps(uri)) { + if (Scheme.isContent(uri) || Scheme.isFile(uri) + || Scheme.isHttp(uri) || Scheme.isHttps(uri)) { mUri = uri; loadImage(); } else { |