Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1614)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaImageManager.java

Issue 2412483007: Download and show artwork in MediaMetdata in media notification (Closed)
Patch Set: Thanks to FindBugs, fixed some stupid bugs Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaImageManager.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaImageManager.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaImageManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..e298e01fc68777d14025e8154646b38aea580f9a
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaImageManager.java
@@ -0,0 +1,227 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.media.ui;
+
+import static org.chromium.content_public.common.MediaMetadata.MediaImage;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.text.TextUtils;
+
+import org.chromium.content_public.browser.ImageDownloadCallback;
+import org.chromium.content_public.browser.WebContents;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * A class for managing the MediaImage download process.
+ *
+ * The manager takes a list of {@link MediaMetadata.MediaImage} as input, and
+ * selects one of them based on scoring and start download through
+ * {@link WebContents} asynchronously. When the download successfully finishes,
+ * the manager runs the callback function to notify the completion and pass the
+ * downloaded Bitmap.
+ *
+ * The scoring works as follows:
+ * - A image score is computed by multiplying the type score with the size score.
+ * - The type score lies in [0, 1] and is based on the image MIME type/file extension.
+ * - PNG and JPEG are prefered than others.
+ * - If unspecified, use the default type score (0.6).
+ * - The size score lies in [0, 1] and is computed using |mMimumSize| and |mIdealSize|
+ * - If size < |mMinimumSize| (too small), the size score is 0.
+ * - If size > 4 * |mIdealSize| (too large), the size score lies is 0.
+ * - If |mMinimumSize| <= size <= |mIdealSize|, the score increases linearly from 0.2 to 1.
+ * - If |mIdealSize| < size <= 4 * |mIdealSize|, the score drops linearly from 1 to 0.6.
+ * - When the size is "any", the size score is 0.8.
+ * - If unspecified, use the default size score (0.4).
+ */
+public class MediaImageManager implements ImageDownloadCallback {
+ // The default score of unknown image size.
+ private static final double DEFAULT_IMAGE_SIZE_SCORE = 0.4;
+ // The scores for different image types. Keep them sorted by value.
+ private static final double TYPE_SCORE_DEFAULT = 0.6;
+ private static final double TYPE_SCORE_PNG = 1.0;
+ private static final double TYPE_SCORE_JPEG = 0.7;
+ private static final double TYPE_SCORE_BMP = 0.5;
+ private static final double TYPE_SCORE_XICON = 0.4;
+ private static final double TYPE_SCORE_GIF = 0.3;
+
+ private static final Object LOCK = new Object();
+
+ // Map from file extension to type score.
+ private static HashMap<String, Double> sFileExtentionScores;
+ // Map from MIME type to type score.
+ private static HashMap<String, Double> sMIMETypeScores;
+
+ private WebContents mWebContents;
+ // The minimum image size. Images that are smaller than |mMinimumSize| will be ignored.
+ final int mMinimumSize;
+ // The ideal image size. Images that are too large than |mIdealSize| will be ignored.
+ final int mIdealSize;
+ // The pending download image request id, which is set when calling
+ // {@link WebContents#downloadImage()}, and reset when image download completes or
+ // {@link #clearRequests()} is called.
+ private int mRequestId;
+ // The callback to be called when the pending download image request completes.
+ private MediaImageCallback mCallback;
+
+ /**
+ * MediaImageManager constructor.
+ * @param minimumSize The minimum size of images to download.
+ * @param idealSize The ideal size of images to download.
+ */
+ public MediaImageManager(int minimumSize, int idealSize) {
+ synchronized (LOCK) {
+ if (sFileExtentionScores == null) {
+ sFileExtentionScores = new HashMap<String, Double>();
+ sFileExtentionScores.put("bmp", TYPE_SCORE_BMP);
+ sFileExtentionScores.put("gif", TYPE_SCORE_GIF);
+ sFileExtentionScores.put("icon", TYPE_SCORE_XICON);
+ sFileExtentionScores.put("jpeg", TYPE_SCORE_JPEG);
+ sFileExtentionScores.put("jpg", TYPE_SCORE_JPEG);
+ sFileExtentionScores.put("png", TYPE_SCORE_PNG);
+ }
+ if (sMIMETypeScores == null) {
+ sMIMETypeScores = new HashMap<String, Double>();
+ sMIMETypeScores.put("image/bmp", TYPE_SCORE_BMP);
+ sMIMETypeScores.put("image/gif", TYPE_SCORE_GIF);
+ sMIMETypeScores.put("image/jpeg", TYPE_SCORE_JPEG);
+ sMIMETypeScores.put("image/png", TYPE_SCORE_PNG);
+ sMIMETypeScores.put("image/x-icon", TYPE_SCORE_XICON);
+ }
+ }
+
+ mMinimumSize = minimumSize;
+ mIdealSize = idealSize;
+ clearRequests();
+ }
+
+ /**
+ * Called when the WebContent changes.
+ * @param contents The new WebContents.
+ */
+ public void setWebContents(WebContents contents) {
+ mWebContents = contents;
+ clearRequests();
+ }
+
+ /**
+ * Select the best image from |images| and start download.
+ * @param images The list of images to choose from.
+ * @param callback The callback when image download completes.
+ */
+ public void downloadImage(List<MediaImage> images, MediaImageCallback callback) {
+ if (mWebContents == null) return;
+
+ mCallback = callback;
+ MediaImage image = selectImage(images);
+ if (image == null) return;
+
+ mRequestId = mWebContents.downloadImage(
+ image.getSrc(), false, 8 * mIdealSize, false, this);
+ }
+
+ /**
+ * Clear previous requests.
+ */
+ public void clearRequests() {
+ mRequestId = -1;
+ mCallback = null;
+ }
+
+ /**
+ * ImageDownloadCallback implementation. This method is called when an download image request is
+ * completed. The class will only keep the latest request. If some call to this method is
+ * corresponding to a previous request, it will be ignored.
+ */
+ @Override
+ public void onFinishDownloadImage(int id, int httpStatusCode, String imageUrl,
+ List<Bitmap> bitmaps, List<Rect> originalImageSizes) {
+ if (id != mRequestId) return;
+ if (httpStatusCode < 200 || httpStatusCode >= 300) return;
+
+ Iterator<Bitmap> iterBitmap = bitmaps.iterator();
+ Iterator<Rect> iterSize = originalImageSizes.iterator();
+
+ Bitmap bestBitmap = null;
+ double bestScore = 0;
+ while (iterBitmap.hasNext() && iterSize.hasNext()) {
+ Bitmap bitmap = iterBitmap.next();
+ Rect size = iterSize.next();
+ double newScore = getImageSizeScore(size);
+ if (bestScore < newScore) {
+ bestBitmap = bitmap;
+ bestScore = newScore;
+ }
+ }
+ if (bestBitmap != null) mCallback.onImageDownloaded(bestBitmap);
+ clearRequests();
+ }
+
+ /**
+ * Select the best image from the |images|.
+ * @param images The list of images to select from.
+ */
+ private MediaImage selectImage(List<MediaImage> images) {
+ MediaImage selectedImage = null;
+ double bestScore = 0;
+ for (MediaImage image : images) {
+ double newScore = getImageScore(image);
+ if (newScore > bestScore) {
+ bestScore = newScore;
+ selectedImage = image;
+ }
+ }
+ return selectedImage;
+ }
+
+ private double getImageScore(MediaImage image) {
+ if (image == null) return 0;
+ if (image.getSizes().isEmpty()) return DEFAULT_IMAGE_SIZE_SCORE;
+
+ double bestSizeScore = 0;
+ for (Rect size : image.getSizes()) {
+ bestSizeScore = Math.max(bestSizeScore, getImageSizeScore(size));
+ }
+ double typeScore = getImageTypeScore(image.getSrc(), image.getType());
+ return bestSizeScore * typeScore;
+ }
+
+ private double getImageSizeScore(Rect size) {
+ int dominantSize = Math.max(size.width(), size.height());
+
+ // When the size is "any".
+ if (dominantSize == 0) return 0.8;
+ // Ignore images that are too small.
+ if (dominantSize < mMinimumSize) return 0;
+ // Ignore images that are too large.
+ if (dominantSize > 4 * mIdealSize) return 0;
+
+ if (dominantSize <= mIdealSize) {
+ return 0.8 * (dominantSize - mMinimumSize) / (mIdealSize - mMinimumSize) + 0.2;
+ }
+ return 0.4 * (dominantSize - mIdealSize) / (3 * mIdealSize) + 0.6;
+ }
+
+ private double getImageTypeScore(String url, String type) {
+ String extension = getExtension(url);
+
+ if (sFileExtentionScores.containsKey(extension)) {
+ return sFileExtentionScores.get(extension);
+ }
+ if (sMIMETypeScores.containsKey(type)) return sMIMETypeScores.get(type);
+
+ return TYPE_SCORE_DEFAULT;
+ }
+
+ private String getExtension(String url) {
+ int index = TextUtils.lastIndexOf(url, '.');
+ if (index == -1) return "";
+ return url.substring(index + 1).toLowerCase(Locale.US);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698