summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2020-08-27 10:16:59 -0700
committerXin Li <delphij@google.com>2020-08-27 10:16:59 -0700
commit6cac9e854d1ef119ebece53ce4669422b53e6ea9 (patch)
tree6795f53bbf55736fbb50314dc904d7ffb2b063fa
parentb82ed64e09ef725b0c675f3fc30296c4844befae (diff)
parent56462add52c101b18bd0a4eb4e89b3f1c6963681 (diff)
downloadUniversalMediaPlayer-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.java2
-rw-r--r--java/com/android/pump/db/AudioStore.java16
-rw-r--r--java/com/android/pump/db/VideoStore.java41
-rw-r--r--java/com/android/pump/util/ImageLoader.java66
-rw-r--r--java/com/android/pump/util/IoUtils.java12
-rw-r--r--java/com/android/pump/util/Scheme.java5
-rw-r--r--java/com/android/pump/widget/UriImageView.java3
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 {