summaryrefslogtreecommitdiffstats
path: root/media/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'media/java/android')
-rw-r--r--media/java/android/media/MediaCodec.java47
-rw-r--r--media/java/android/media/MediaCodecInfo.java2
-rw-r--r--media/java/android/media/SoundPool.java40
-rw-r--r--media/java/android/media/browse/MediaBrowser.java36
-rw-r--r--media/java/android/media/tv/TvInputInfo.java109
-rw-r--r--media/java/android/service/media/MediaBrowserService.java50
6 files changed, 183 insertions, 101 deletions
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index eec4960..a79dd04 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1455,15 +1455,6 @@ final public class MediaCodec {
@Retention(RetentionPolicy.SOURCE)
public @interface BufferFlag {}
- private static class FrameRenderedInfo {
- public long mPresentationTimeUs;
- public long mNanoTime;
- public FrameRenderedInfo(long presentationTimeUs, long nanoTime) {
- mPresentationTimeUs = presentationTimeUs;
- mNanoTime = nanoTime;
- }
- }
-
private EventHandler mEventHandler;
private EventHandler mOnFrameRenderedHandler;
private EventHandler mCallbackHandler;
@@ -1503,10 +1494,16 @@ final public class MediaCodec {
}
case EVENT_FRAME_RENDERED:
synchronized (mListenerLock) {
- FrameRenderedInfo info = (FrameRenderedInfo)msg.obj;
- if (mOnFrameRenderedListener != null) {
+ Map<String, Object> map = (Map<String, Object>)msg.obj;
+ for (int i = 0; ; ++i) {
+ Object mediaTimeUs = map.get(i + "-media-time-us");
+ Object systemNano = map.get(i + "-system-nano");
+ if (mediaTimeUs == null || systemNano == null
+ || mOnFrameRenderedListener == null) {
+ break;
+ }
mOnFrameRenderedListener.onFrameRendered(
- mCodec, info.mPresentationTimeUs, info.mNanoTime);
+ mCodec, (long)mediaTimeUs, (long)systemNano);
}
break;
}
@@ -2362,26 +2359,9 @@ final public class MediaCodec {
info = mDequeuedOutputInfos.remove(index);
}
}
- // TODO
- // until codec and libgui supports callback, assume frame is rendered within 50 ms
- postRenderedCallback(render, info, 50 /* delayMs */);
releaseOutputBuffer(index, render, false /* updatePTS */, 0 /* dummy */);
}
- private void postRenderedCallback(boolean render, @Nullable BufferInfo info, long delayMs) {
- if (render && info != null) {
- synchronized (mListenerLock) {
- if (mOnFrameRenderedListener != null) {
- FrameRenderedInfo obj = new FrameRenderedInfo(
- info.presentationTimeUs, System.nanoTime() + delayMs * 1000000);
- Message msg = mOnFrameRenderedHandler.obtainMessage(
- EVENT_FRAME_RENDERED, obj);
- mOnFrameRenderedHandler.sendMessageDelayed(msg, delayMs);
- }
- }
- }
- }
-
/**
* If you are done with a buffer, use this call to update its surface timestamp
* and return it to the codec to render it on the output surface. If you
@@ -2440,12 +2420,6 @@ final public class MediaCodec {
info = mDequeuedOutputInfos.remove(index);
}
}
- // TODO
- // until codec and libgui supports callback, assume frame is rendered at the
- // render time or 16 ms from now, whichever is later.
- postRenderedCallback(
- true /* render */, info,
- Math.max(renderTimestampNs - System.nanoTime(), 16666666) / 1000000);
releaseOutputBuffer(
index, true /* render */, true /* updatePTS */, renderTimestampNs);
}
@@ -3049,9 +3023,12 @@ final public class MediaCodec {
} else if (mOnFrameRenderedHandler != null) {
mOnFrameRenderedHandler.removeMessages(EVENT_FRAME_RENDERED);
}
+ native_enableOnFrameRenderedListener(listener != null);
}
}
+ private native void native_enableOnFrameRenderedListener(boolean enable);
+
private EventHandler getEventHandlerOn(
@Nullable Handler handler, @NonNull EventHandler lastHandler) {
if (handler == null) {
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 89d419a..6c26220 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1382,7 +1382,7 @@ public final class MediaCodecInfo {
// upper limit.
// for now we are keeping the profile specific "width/height
// in macroblocks" limits.
- if (Integer.valueOf(1).equals(map.get("feature-can-swap-width-height"))) {
+ if (map.containsKey("feature-can-swap-width-height")) {
if (widths != null) {
mSmallerDimensionUpperLimit =
Math.min(widths.getUpper(), heights.getUpper());
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 64863c2..1355635 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -35,6 +35,7 @@ import android.os.ServiceManager;
import android.util.AndroidRuntimeException;
import android.util.Log;
+import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
@@ -125,10 +126,12 @@ public class SoundPool {
private EventHandler mEventHandler;
private SoundPool.OnLoadCompleteListener mOnLoadCompleteListener;
+ private boolean mHasAppOpsPlayAudio;
private final Object mLock;
private final AudioAttributes mAttributes;
private final IAppOpsService mAppOps;
+ private final IAppOpsCallback mAppOpsCallback;
/**
* Constructor. Constructs a SoundPool object with the following
@@ -159,6 +162,24 @@ public class SoundPool {
mAttributes = attributes;
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
mAppOps = IAppOpsService.Stub.asInterface(b);
+ // initialize mHasAppOpsPlayAudio
+ updateAppOpsPlayAudio();
+ // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
+ mAppOpsCallback = new IAppOpsCallback.Stub() {
+ public void opChanged(int op, String packageName) {
+ synchronized (mLock) {
+ if (op == AppOpsManager.OP_PLAY_AUDIO) {
+ updateAppOpsPlayAudio();
+ }
+ }
+ }
+ };
+ try {
+ mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO,
+ ActivityThread.currentPackageName(), mAppOpsCallback);
+ } catch (RemoteException e) {
+ mHasAppOpsPlayAudio = false;
+ }
}
/**
@@ -168,7 +189,16 @@ public class SoundPool {
* object. The SoundPool can no longer be used and the reference
* should be set to null.
*/
- public native final void release();
+ public final void release() {
+ try {
+ mAppOps.stopWatchingMode(mAppOpsCallback);
+ } catch (RemoteException e) {
+ // nothing to do here, the SoundPool is being released anyway
+ }
+ native_release();
+ }
+
+ private native final void native_release();
protected void finalize() { release(); }
@@ -466,13 +496,17 @@ public class SoundPool {
if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
return false;
}
+ return !mHasAppOpsPlayAudio;
+ }
+
+ private void updateAppOpsPlayAudio() {
try {
final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
mAttributes.getUsage(),
Process.myUid(), ActivityThread.currentPackageName());
- return mode != AppOpsManager.MODE_ALLOWED;
+ mHasAppOpsPlayAudio = (mode == AppOpsManager.MODE_ALLOWED);
} catch (RemoteException e) {
- return false;
+ mHasAppOpsPlayAudio = false;
}
}
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index ef8d169..ba867e1 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -375,7 +375,7 @@ public final class MediaBrowser {
* @param mediaId The id of the item to retrieve.
* @param cb The callback to receive the result on.
*/
- public void getMediaItem(@NonNull String mediaId, @NonNull final MediaItemCallback cb) {
+ public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
if (TextUtils.isEmpty(mediaId)) {
throw new IllegalArgumentException("mediaId is empty.");
}
@@ -387,7 +387,7 @@ public final class MediaBrowser {
mHandler.post(new Runnable() {
@Override
public void run() {
- cb.onError();
+ cb.onError(mediaId);
}
});
return;
@@ -397,15 +397,15 @@ public final class MediaBrowser {
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode != 0 || resultData == null
|| !resultData.containsKey(MediaBrowserService.KEY_MEDIA_ITEM)) {
- cb.onError();
+ cb.onError(mediaId);
return;
}
Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
if (!(item instanceof MediaItem)) {
- cb.onError();
+ cb.onError(mediaId);
+ return;
}
- cb.onMediaItemLoaded((MediaItem) resultData.getParcelable(
- MediaBrowserService.KEY_MEDIA_ITEM));
+ cb.onItemLoaded((MediaItem)item);
}
};
try {
@@ -415,7 +415,7 @@ public final class MediaBrowser {
mHandler.post(new Runnable() {
@Override
public void run() {
- cb.onError();
+ cb.onError(mediaId);
}
});
}
@@ -728,6 +728,9 @@ public final class MediaBrowser {
public static abstract class SubscriptionCallback {
/**
* Called when the list of children is loaded or updated.
+ *
+ * @param parentId The media id of the parent media item.
+ * @param children The children which were loaded.
*/
public void onChildrenLoaded(@NonNull String parentId,
@NonNull List<MediaItem> children) {
@@ -739,29 +742,32 @@ public final class MediaBrowser {
* If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
* called, because some errors may heal themselves.
* </p>
+ *
+ * @param parentId The media id of the parent media item whose children could
+ * not be loaded.
*/
- public void onError(@NonNull String id) {
+ public void onError(@NonNull String parentId) {
}
}
/**
- * Callback for receiving the result of {@link #getMediaItem}.
+ * Callback for receiving the result of {@link #getItem}.
*/
- public static abstract class MediaItemCallback {
-
+ public static abstract class ItemCallback {
/**
* Called when the item has been returned by the browser service.
*
* @param item The item that was returned or null if it doesn't exist.
*/
- public void onMediaItemLoaded(MediaItem item) {
+ public void onItemLoaded(MediaItem item) {
}
/**
- * Called when the id doesn't exist or there was an error retrieving the
- * item.
+ * Called when the item doesn't exist or there was an error retrieving it.
+ *
+ * @param itemId The media id of the media item which could not be loaded.
*/
- public void onError() {
+ public void onError(@NonNull String itemId) {
}
}
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index c537dd6..5d1aa14 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -29,6 +29,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.net.Uri;
import android.os.Parcel;
@@ -125,7 +126,9 @@ public final class TvInputInfo implements Parcelable {
private String mSettingsActivity;
private HdmiDeviceInfo mHdmiDeviceInfo;
+ private int mLabelRes;
private String mLabel;
+ private Icon mIcon;
private Uri mIconUri;
private boolean mIsConnectedToHdmiSwitch;
@@ -155,7 +158,7 @@ public final class TvInputInfo implements Parcelable {
throws XmlPullParserException, IOException {
return createTvInputInfo(context, service, generateInputIdForComponentName(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name)),
- null, TYPE_TUNER, false, null, null, false);
+ null, TYPE_TUNER, false, 0, null, null, null, false);
}
/**
@@ -165,11 +168,11 @@ public final class TvInputInfo implements Parcelable {
* @param service The ResolveInfo returned from the package manager about this TV input service.
* @param hdmiDeviceInfo The HdmiDeviceInfo for a HDMI CEC logical device.
* @param parentId The ID of this TV input's parent input. {@code null} if none exists.
+ * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
+ * label will be loaded.
* @param iconUri The {@link android.net.Uri} to load the icon image. See
* {@link android.content.ContentResolver#openInputStream}. If it is {@code null},
* the application icon of {@code service} will be loaded.
- * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
- * label will be loaded.
* @hide
*/
@SystemApi
@@ -179,7 +182,34 @@ public final class TvInputInfo implements Parcelable {
boolean isConnectedToHdmiSwitch = (hdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
TvInputInfo input = createTvInputInfo(context, service, generateInputIdForHdmiDevice(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
- hdmiDeviceInfo), parentId, TYPE_HDMI, true, label, iconUri, isConnectedToHdmiSwitch);
+ hdmiDeviceInfo), parentId, TYPE_HDMI, true, 0, label, null, iconUri,
+ isConnectedToHdmiSwitch);
+ input.mHdmiDeviceInfo = hdmiDeviceInfo;
+ return input;
+ }
+
+ /**
+ * Create a new instance of the TvInputInfo class, instantiating it from the given Context,
+ * ResolveInfo, and HdmiDeviceInfo.
+ *
+ * @param service The ResolveInfo returned from the package manager about this TV input service.
+ * @param hdmiDeviceInfo The HdmiDeviceInfo for a HDMI CEC logical device.
+ * @param parentId The ID of this TV input's parent input. {@code null} if none exists.
+ * @param labelRes The label resource ID of this TvInputInfo. If it is {@code 0},
+ * {@code service} label will be loaded.
+ * @param icon The {@link android.graphics.drawable.Icon} to load the icon image. If it is
+ * {@code null}, the application icon of {@code service} will be loaded.
+ * @hide
+ */
+ @SystemApi
+ public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
+ HdmiDeviceInfo hdmiDeviceInfo, String parentId, int labelRes, Icon icon)
+ throws XmlPullParserException, IOException {
+ boolean isConnectedToHdmiSwitch = (hdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
+ TvInputInfo input = createTvInputInfo(context, service, generateInputIdForHdmiDevice(
+ new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
+ hdmiDeviceInfo), parentId, TYPE_HDMI, true, labelRes, null, icon, null,
+ isConnectedToHdmiSwitch);
input.mHdmiDeviceInfo = hdmiDeviceInfo;
return input;
}
@@ -190,11 +220,11 @@ public final class TvInputInfo implements Parcelable {
*
* @param service The ResolveInfo returned from the package manager about this TV input service.
* @param hardwareInfo The TvInputHardwareInfo for a TV input hardware device.
+ * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
+ * label will be loaded.
* @param iconUri The {@link android.net.Uri} to load the icon image. See
* {@link android.content.ContentResolver#openInputStream}. If it is {@code null},
* the application icon of {@code service} will be loaded.
- * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
- * label will be loaded.
* @hide
*/
@SystemApi
@@ -204,12 +234,34 @@ public final class TvInputInfo implements Parcelable {
int inputType = sHardwareTypeToTvInputType.get(hardwareInfo.getType(), TYPE_TUNER);
return createTvInputInfo(context, service, generateInputIdForHardware(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
- hardwareInfo), null, inputType, true, label, iconUri, false);
+ hardwareInfo), null, inputType, true, 0, label, null, iconUri, false);
+ }
+
+ /**
+ * Create a new instance of the TvInputInfo class, instantiating it from the given Context,
+ * ResolveInfo, and TvInputHardwareInfo.
+ *
+ * @param service The ResolveInfo returned from the package manager about this TV input service.
+ * @param hardwareInfo The TvInputHardwareInfo for a TV input hardware device.
+ * @param labelRes The label resource ID of this TvInputInfo. If it is {@code 0},
+ * {@code service} label will be loaded.
+ * @param icon The {@link android.graphics.drawable.Icon} to load the icon image. If it is
+ * {@code null}, the application icon of {@code service} will be loaded.
+ * @hide
+ */
+ @SystemApi
+ public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
+ TvInputHardwareInfo hardwareInfo, int labelRes, Icon icon)
+ throws XmlPullParserException, IOException {
+ int inputType = sHardwareTypeToTvInputType.get(hardwareInfo.getType(), TYPE_TUNER);
+ return createTvInputInfo(context, service, generateInputIdForHardware(
+ new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
+ hardwareInfo), null, inputType, true, labelRes, null, icon, null, false);
}
- private static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
- String id, String parentId, int inputType, boolean isHardwareInput, String label,
- Uri iconUri, boolean isConnectedToHdmiSwitch)
+ private static TvInputInfo createTvInputInfo(Context context, ResolveInfo service, String id,
+ String parentId, int inputType, boolean isHardwareInput, int labelRes, String label,
+ Icon icon, Uri iconUri, boolean isConnectedToHdmiSwitch)
throws XmlPullParserException, IOException {
ServiceInfo si = service.serviceInfo;
PackageManager pm = context.getPackageManager();
@@ -254,7 +306,9 @@ public final class TvInputInfo implements Parcelable {
}
sa.recycle();
+ input.mLabelRes = labelRes;
input.mLabel = label;
+ input.mIcon = icon;
input.mIconUri = iconUri;
input.mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
return input;
@@ -426,11 +480,13 @@ public final class TvInputInfo implements Parcelable {
* a label, its name is returned.
*/
public CharSequence loadLabel(@NonNull Context context) {
- if (TextUtils.isEmpty(mLabel)) {
- return mService.loadLabel(context.getPackageManager());
- } else {
+ if (mLabelRes != 0) {
+ return context.getPackageManager().getText(mService.serviceInfo.packageName, mLabelRes,
+ null);
+ } else if (!TextUtils.isEmpty(mLabel)) {
return mLabel;
}
+ return mService.loadLabel(context.getPackageManager());
}
/**
@@ -454,19 +510,20 @@ public final class TvInputInfo implements Parcelable {
* application's icon is returned. If it's unavailable too, {@code null} is returned.
*/
public Drawable loadIcon(@NonNull Context context) {
- if (mIconUri == null) {
- return loadServiceIcon(context);
- }
- try (InputStream is = context.getContentResolver().openInputStream(mIconUri)) {
- Drawable drawable = Drawable.createFromStream(is, null);
- if (drawable == null) {
- return loadServiceIcon(context);
+ if (mIcon != null) {
+ return mIcon.loadDrawable(context);
+ } else if (mIconUri != null) {
+ try (InputStream is = context.getContentResolver().openInputStream(mIconUri)) {
+ Drawable drawable = Drawable.createFromStream(is, null);
+ if (drawable != null) {
+ return drawable;
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Loading the default icon due to a failure on loading " + mIconUri, e);
+ // Falls back.
}
- return drawable;
- } catch (IOException e) {
- Log.w(TAG, "Loading the default icon due to a failure on loading " + mIconUri, e);
- return loadServiceIcon(context);
}
+ return loadServiceIcon(context);
}
@Override
@@ -516,7 +573,9 @@ public final class TvInputInfo implements Parcelable {
dest.writeInt(mType);
dest.writeByte(mIsHardwareInput ? (byte) 1 : 0);
dest.writeParcelable(mHdmiDeviceInfo, flags);
+ dest.writeParcelable(mIcon, flags);
dest.writeParcelable(mIconUri, flags);
+ dest.writeInt(mLabelRes);
dest.writeString(mLabel);
dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0);
}
@@ -591,7 +650,9 @@ public final class TvInputInfo implements Parcelable {
mType = in.readInt();
mIsHardwareInput = in.readByte() == 1 ? true : false;
mHdmiDeviceInfo = in.readParcelable(null);
+ mIcon = in.readParcelable(null);
mIconUri = in.readParcelable(null);
+ mLabelRes = in.readInt();
mLabel = in.readString();
mIsConnectedToHdmiSwitch = in.readByte() == 1 ? true : false;
}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 41156cb..1bb99ff 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -76,7 +76,7 @@ public abstract class MediaBrowserService extends Service {
public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
/**
- * A key for passing the MediaItem to the ResultReceiver in getMediaItem.
+ * A key for passing the MediaItem to the ResultReceiver in getItem.
*
* @hide
*/
@@ -109,6 +109,7 @@ public abstract class MediaBrowserService extends Service {
* be thrown.
*
* @see MediaBrowserService#onLoadChildren
+ * @see MediaBrowserService#onGetMediaItem
*/
public class Result<T> {
private Object mDebug;
@@ -279,20 +280,7 @@ public abstract class MediaBrowserService extends Service {
mHandler.post(new Runnable() {
@Override
public void run() {
- final Result<MediaBrowser.MediaItem> result
- = new Result<MediaBrowser.MediaItem>(mediaId) {
- @Override
- void onResultSent(MediaBrowser.MediaItem item) {
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_MEDIA_ITEM, item);
- receiver.send(0, bundle);
- }
- };
- try {
- MediaBrowserService.this.getMediaItem(mediaId, result);
- } catch (UnsupportedOperationException e) {
- receiver.send(-1, null);
- }
+ performLoadItem(mediaId, receiver);
}
});
}
@@ -357,8 +345,7 @@ public abstract class MediaBrowserService extends Service {
@NonNull Result<List<MediaBrowser.MediaItem>> result);
/**
- * Called to get a specific media item. The mediaId should be the same id
- * that would be returned for this item when it is in a list of child items.
+ * Called to get information about a specific media item.
* <p>
* Implementations must call {@link Result#sendResult result.sendResult}. If
* loading the item will be an expensive operation {@link Result#detach
@@ -366,17 +353,15 @@ public abstract class MediaBrowserService extends Service {
* then {@link Result#sendResult result.sendResult} called when the item has
* been loaded.
* <p>
- * The default implementation throws an exception.
+ * The default implementation sends a null result.
*
- * @param mediaId The id for the specific
+ * @param itemId The id for the specific
* {@link android.media.browse.MediaBrowser.MediaItem}.
* @param result The Result to send the item to, or null if the id is
* invalid.
- * @throws UnsupportedOperationException
*/
- public void getMediaItem(String mediaId, Result<MediaBrowser.MediaItem> result)
- throws UnsupportedOperationException {
- throw new UnsupportedOperationException("getMediaItem is not supported.");
+ public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
+ result.sendResult(null);
}
/**
@@ -515,6 +500,25 @@ public abstract class MediaBrowserService extends Service {
}
}
+ private void performLoadItem(String itemId, final ResultReceiver receiver) {
+ final Result<MediaBrowser.MediaItem> result =
+ new Result<MediaBrowser.MediaItem>(itemId) {
+ @Override
+ void onResultSent(MediaBrowser.MediaItem item) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_MEDIA_ITEM, item);
+ receiver.send(0, bundle);
+ }
+ };
+
+ MediaBrowserService.this.onLoadItem(itemId, result);
+
+ if (!result.isDone()) {
+ throw new IllegalStateException("onLoadItem must call detach() or sendResult()"
+ + " before returning for id=" + itemId);
+ }
+ }
+
/**
* Contains information that the browser service needs to send to the client
* when first connected.