Skip to content

Commit

Permalink
Improve automatic error replication for legacy browsers
Browse files Browse the repository at this point in the history
This change extends the error replication to a given set of
error codes (not only authentication error), but only
replicates an error if the caller of the service `Callback`
is a legacy controller. It also makes error replication
configurable so that apps can opt-out and report errors
manually instead, or define the error codes for which
replication is enabled.

The change also removes the restriction of `sendError` only
being available for Media3 controllers. Instead, sending an
error to a legacy controller updates the platform playback
state in the same way as sending the error to the media
notification controller.

#cherrypick

PiperOrigin-RevId: 648399237
  • Loading branch information
marcbaechinger authored and copybara-github committed Jul 1, 2024
1 parent 6bf2461 commit 70c0639
Show file tree
Hide file tree
Showing 12 changed files with 384 additions and 93 deletions.
5 changes: 5 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
`AcceptedResultBuilder.setSessionActivivty(PendingIntent)`. Once
connected, the session activity can be updated with
`MediaSession.setSessionActivity(ControllerInfo, PendingIntent)`.
* Improve error replication of calls to `MediaLibrarySession.Callback`.
Error replication can now be configured by using
`MediaLibrarySession.Builder.setLibraryErrorReplicationMode()` for
chosing the error type or opt-ing out of error replication which is on
by default.
* UI:
* Work around a platform bug causing stretched/cropped video when using
`SurfaceView` inside a Compose `AndroidView` on API 34
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,19 @@
import static androidx.media3.session.LibraryResult.ofVoid;
import static androidx.media3.session.SessionError.ERROR_BAD_VALUE;
import static androidx.media3.session.SessionError.ERROR_NOT_SUPPORTED;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import androidx.media3.common.MediaItem;
Expand All @@ -43,6 +49,10 @@
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;

/**
Expand Down Expand Up @@ -118,6 +128,37 @@ public abstract class MediaLibraryService extends MediaSessionService {
*/
public static final class MediaLibrarySession extends MediaSession {

/**
* Library error replication mode. One of {@link #LIBRARY_ERROR_REPLICATION_MODE_NONE}, {@link
* #LIBRARY_ERROR_REPLICATION_MODE_FATAL} or {@link #LIBRARY_ERROR_REPLICATION_MODE_NON_FATAL}.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
LIBRARY_ERROR_REPLICATION_MODE_NONE,
LIBRARY_ERROR_REPLICATION_MODE_FATAL,
LIBRARY_ERROR_REPLICATION_MODE_NON_FATAL
})
@UnstableApi
@interface LibraryErrorReplicationMode {}

/** No library service errors are replicated. */
@UnstableApi public static final int LIBRARY_ERROR_REPLICATION_MODE_NONE = 0;

/**
* {@linkplain SessionError Session errors} returned by the {@link MediaLibrarySession.Callback}
* as part of a {@link LibraryResult} are replicated to the platform session as a fatal error.
*/
@UnstableApi public static final int LIBRARY_ERROR_REPLICATION_MODE_FATAL = 1;

/**
* {@linkplain SessionError Session errors} returned by the {@link MediaLibrarySession.Callback}
* as part of a {@link LibraryResult} are replicated to the platform session as a non-fatal
* error.
*/
@UnstableApi public static final int LIBRARY_ERROR_REPLICATION_MODE_NON_FATAL = 2;

/**
* An extended {@link MediaSession.Callback} for the {@link MediaLibrarySession}.
*
Expand Down Expand Up @@ -393,6 +434,8 @@ default ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> onGetSearchRes
// constructor.
public static final class Builder extends BuilderBase<MediaLibrarySession, Builder, Callback> {

private @LibraryErrorReplicationMode int libraryErrorReplicationMode;

/**
* Creates a builder for {@link MediaLibrarySession}.
*
Expand All @@ -407,7 +450,7 @@ public static final class Builder extends BuilderBase<MediaLibrarySession, Build
// Ideally it's better to make it inner class of service to enforce, but it violates API
// guideline that Builders should be the inner class of the building target.
public Builder(MediaLibraryService service, Player player, Callback callback) {
super(service, player, callback);
this((Context) service, player, callback);
}

/**
Expand All @@ -421,6 +464,7 @@ public Builder(MediaLibraryService service, Player player, Callback callback) {
@UnstableApi
public Builder(Context context, Player player, Callback callback) {
super(context, player, callback);
libraryErrorReplicationMode = LIBRARY_ERROR_REPLICATION_MODE_FATAL;
}

/**
Expand Down Expand Up @@ -560,6 +604,37 @@ public Builder setPeriodicPositionUpdateEnabled(boolean isEnabled) {
return super.setPeriodicPositionUpdateEnabled(isEnabled);
}

/**
* Sets whether library result errors should be replicated to the platform media session's
* {@link android.media.session.PlaybackState} as a fatal error, a non-fatal error or not
* replicated at all. Replication is only executed for calling legacy browsers ({@link
* android.support.v4.media.MediaBrowserCompat} and {@link android.media.browse.MediaBrowser})
* to which no error codes can be transmitted as a result of the service call.
*
* <p>The default is {@link #LIBRARY_ERROR_REPLICATION_MODE_FATAL}.
*
* <p>{@link MediaLibrarySession.Callback#onGetLibraryRoot} is exempted from replication,
* because this method is part of the connection process of a legacy browser.
*
* <p>The following error codes are replicated:
*
* <ul>
* <li>{@link SessionError#ERROR_SESSION_AUTHENTICATION_EXPIRED}
* <li>{@link SessionError#ERROR_SESSION_PREMIUM_ACCOUNT_REQUIRED}
* </ul>
*
* <p>See {@link MediaLibrarySession#clearReplicatedLibraryError} also.
*
* @param libraryErrorReplicationMode The mode to use.
*/
@UnstableApi
@CanIgnoreReturnValue
public Builder setLibraryErrorReplicationMode(
@LibraryErrorReplicationMode int libraryErrorReplicationMode) {
this.libraryErrorReplicationMode = libraryErrorReplicationMode;
return this;
}

/**
* Builds a {@link MediaLibrarySession}.
*
Expand All @@ -583,7 +658,8 @@ public MediaLibrarySession build() {
sessionExtras,
checkNotNull(bitmapLoader),
playIfSuppressed,
isPeriodicPositionUpdateEnabled);
isPeriodicPositionUpdateEnabled,
libraryErrorReplicationMode);
}
}

Expand All @@ -598,7 +674,8 @@ public MediaLibrarySession build() {
Bundle sessionExtras,
BitmapLoader bitmapLoader,
boolean playIfSuppressed,
boolean isPeriodicPositionUpdateEnabled) {
boolean isPeriodicPositionUpdateEnabled,
@LibraryErrorReplicationMode int libraryErrorReplicationMode) {
super(
context,
id,
Expand All @@ -610,7 +687,8 @@ public MediaLibrarySession build() {
sessionExtras,
bitmapLoader,
playIfSuppressed,
isPeriodicPositionUpdateEnabled);
isPeriodicPositionUpdateEnabled,
libraryErrorReplicationMode);
}

@Override
Expand All @@ -625,7 +703,8 @@ public MediaLibrarySession build() {
Bundle sessionExtras,
BitmapLoader bitmapLoader,
boolean playIfSuppressed,
boolean isPeriodicPositionUpdateEnabled) {
boolean isPeriodicPositionUpdateEnabled,
@LibraryErrorReplicationMode int libraryErrorReplicationMode) {
return new MediaLibrarySessionImpl(
this,
context,
Expand All @@ -638,7 +717,8 @@ public MediaLibrarySession build() {
sessionExtras,
bitmapLoader,
playIfSuppressed,
isPeriodicPositionUpdateEnabled);
isPeriodicPositionUpdateEnabled,
libraryErrorReplicationMode);
}

@Override
Expand Down Expand Up @@ -718,6 +798,25 @@ public void notifySearchResultChanged(
.notifySearchResultChanged(
checkNotNull(browser), checkNotEmpty(query), itemCount, params);
}

/**
* Clears the replicated library error in the platform session that was set when a {@link
* LibraryResult} with an error result code was returned by the {@link
* MediaLibrarySession.Callback} that is replicated and if {@linkplain
* MediaLibrarySession.Builder#setLibraryErrorReplicationMode(int) legacy session error
* replication is not turned off}.
*
* <p>Note: If a {@link LibraryResult#RESULT_SUCCESS} was returned by a method of {@link
* MediaLibrarySession.Callback} that is considered for replication, the error is cleared
* automatically by the library.
*
* <p>Calling this method updates the platform session playback state in case there was a
* replicated error set. If no error was set, calling this method is a no-op.
*/
@UnstableApi
public void clearReplicatedLibraryError() {
getImpl().clearReplicatedLibraryError();
}
}

/**
Expand Down
Loading

0 comments on commit 70c0639

Please sign in to comment.