import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseArray;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
private final Handler mHandler = new Handler();
private final ArrayMap<Uri,Subscription> mSubscriptions =
new ArrayMap<Uri, MediaBrowser.Subscription>();
- private final ArrayMap<ThumbnailRequest, HashSet<ThumbnailCallback>> mThumbnailCallbacks =
- new ArrayMap<ThumbnailRequest, HashSet<ThumbnailCallback>>();
+ private final SparseArray<ThumbnailRequest> mThumbnailRequests =
+ new SparseArray<ThumbnailRequest>();
private int mState = CONNECT_STATE_DISCONNECTED;
private MediaServiceConnection mServiceConnection;
private Uri mRootUri;
private MediaSession.Token mMediaSessionToken;
private Bundle mExtras;
+ private int mNextSeq;
/**
* Creates a media browser for the specified media browse service.
mHandler.post(new Runnable() {
@Override
public void run() {
- HashSet<ThumbnailCallback> callbackSet;
- ThumbnailRequest request = new ThumbnailRequest(uri, width, height);
- callbackSet = mThumbnailCallbacks.get(request);
- if (callbackSet != null) {
- callbackSet.add(callback);
- mThumbnailCallbacks.put(request, callbackSet);
- // same request has been sent. we will wait for the callback.
- return;
+ for (int i = 0; i < mThumbnailRequests.size(); i++) {
+ ThumbnailRequest existingRequest = mThumbnailRequests.valueAt(i);
+ if (existingRequest.isSameRequest(uri, width, height)) {
+ existingRequest.addCallback(callback);
+ return;
+ }
}
- callbackSet = new HashSet<ThumbnailCallback>();
- callbackSet.add(callback);
- mThumbnailCallbacks.put(request, callbackSet);
+ final int seq = mNextSeq++;
+ ThumbnailRequest request = new ThumbnailRequest(seq, uri, width, height);
+ request.addCallback(callback);
+ mThumbnailRequests.put(seq, request);
if (mState == CONNECT_STATE_CONNECTED) {
try {
- mServiceBinder.loadThumbnail(uri, width, height, mServiceCallbacks);
+ mServiceBinder.loadThumbnail(seq, uri, width, height, mServiceCallbacks);
} catch (RemoteException e) {
// Process is crashing. We will disconnect, and upon reconnect we will
// automatically reload the thumbnails. So nothing to do here.
}
}
- for (ThumbnailRequest request : mThumbnailCallbacks.keySet()) {
+ for (int i = 0; i < mThumbnailRequests.size(); i++) {
+ ThumbnailRequest request = mThumbnailRequests.valueAt(i);
try {
- mServiceBinder.loadThumbnail(request.uri, request.width, request.height,
- mServiceCallbacks);
+ mServiceBinder.loadThumbnail(request.mSeq, request.mUri,
+ request.mWidth, request.mHeight, mServiceCallbacks);
} catch (RemoteException e) {
// Process is crashing. We will disconnect, and upon reconnect we will
// automatically reload. So nothing to do here.
- Log.d(TAG, "loadThumbnail failed with RemoteException uri=" + request.uri);
+ Log.d(TAG, "loadThumbnail failed with RemoteException request=" + request);
}
}
-
}
});
}
}
private final void onLoadThumbnail(final IMediaBrowserServiceCallbacks callback,
- final ThumbnailRequest request, final Bitmap bitmap) {
+ final int seqNum, final Bitmap bitmap) {
mHandler.post(new Runnable() {
@Override
public void run() {
return;
}
- Set<ThumbnailCallback> callbackSet = mThumbnailCallbacks.get(request);
- if (callbackSet == null) {
- Log.d(TAG, "onLoadThumbnail called for request=" + request +
- " but the callback is not registered");
+ ThumbnailRequest request = mThumbnailRequests.get(seqNum);
+ if (request == null) {
+ Log.d(TAG, "onLoadThumbnail called for seqNum=" + seqNum + " request="
+ + request + " but the request is not registered");
return;
}
- for (ThumbnailCallback thumbnailCallback : callbackSet) {
- thumbnailCallback.onThumbnailLoaded(request.uri, bitmap);
+ mThumbnailRequests.delete(seqNum);
+ for (ThumbnailCallback thumbnailCallback : request.getCallbacks()) {
+ thumbnailCallback.onThumbnailLoaded(request.mUri, bitmap);
}
- mThumbnailCallbacks.remove(request);
}
});
}
}
private static class ThumbnailRequest {
- Uri uri;
- int width;
- int height;
- ThumbnailRequest(@NonNull Uri uri, int width, int height) {
+ final int mSeq;
+ final Uri mUri;
+ final int mWidth;
+ final int mHeight;
+ final List<ThumbnailCallback> mCallbacks;
+
+ /**
+ * Constructs a thumbnail request.
+ * @param seq The unique sequence number assigned to the request by the media browser.
+ * @param uri The Uri for the thumbnail.
+ * @param width The width for the thumbnail.
+ * @param height The height for the thumbnail.
+ */
+ ThumbnailRequest(int seq, @NonNull Uri uri, int width, int height) {
if (uri == null) {
throw new IllegalArgumentException("thumbnail uri cannot be null");
}
- this.uri = uri;
- this.width = width;
- this.height = height;
+ this.mSeq = seq;
+ this.mUri = uri;
+ this.mWidth = width;
+ this.mHeight = height;
+ mCallbacks = new ArrayList<ThumbnailCallback>();
}
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof ThumbnailRequest)) return false;
-
- ThumbnailRequest that = (ThumbnailRequest) o;
-
- if (height != that.height) return false;
- if (width != that.width) return false;
- if (!uri.equals(that.uri)) return false;
-
- return true;
+ /**
+ * Adds a callback to the thumbnail request.
+ * If the callback already exists, it will not be added again.
+ */
+ public void addCallback(@NonNull ThumbnailCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("callback cannot be null in ThumbnailRequest");
+ }
+ if (!mCallbacks.contains(callback)) {
+ mCallbacks.add(callback);
+ }
}
- @Override
- public int hashCode() {
- int result = uri.hashCode();
- result = 31 * result + width;
- result = 31 * result + height;
- return result;
+ /**
+ * Checks if the thumbnail request has the same uri, width, and height as the given values.
+ */
+ public boolean isSameRequest(@Nullable Uri uri, int width, int height) {
+ return Objects.equals(mUri, uri) && mWidth == width && mHeight == height;
}
@Override
public String toString() {
- return "ThumbnailRequest{" +
- "uri=" + uri +
- ", width=" + width +
- ", height=" + height +
- '}';
+ final StringBuilder sb = new StringBuilder("ThumbnailRequest{");
+ sb.append("uri=").append(mUri);
+ sb.append(", width=").append(mWidth);
+ sb.append(", height=").append(mHeight);
+ sb.append(", seq=").append(mSeq);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ /**
+ * Gets an unmodifiable view of the list of callbacks associated with the request.
+ */
+ public List<ThumbnailCallback> getCallbacks() {
+ return Collections.unmodifiableList(mCallbacks);
}
}
}
@Override
- public void onLoadThumbnail(final Uri uri, int width, int height, final Bitmap bitmap) {
+ public void onLoadThumbnail(final int seqNum, final Bitmap bitmap) {
MediaBrowser mediaBrowser = mMediaBrowser.get();
if (mediaBrowser != null) {
- ThumbnailRequest request = new ThumbnailRequest(uri, width, height);
- mediaBrowser.onLoadThumbnail(this, request, bitmap);
+ mediaBrowser.onLoadThumbnail(this, seqNum, bitmap);
}
}
}