Search in sources :

Example 6 with ControllerInfo

use of androidx.media3.session.MediaSession.ControllerInfo in project media by androidx.

the class MediaLibraryServiceLegacyStub method onCustomAction.

@Override
public void onCustomAction(String action, Bundle extras, Result<Bundle> result) {
    @Nullable ControllerInfo controller = getCurrentController();
    if (controller == null) {
        result.sendError(/* extras= */
        null);
        return;
    }
    result.detach();
    postOrRun(librarySessionImpl.getApplicationHandler(), () -> {
        SessionCommand command = new SessionCommand(action, /* extras= */
        Bundle.EMPTY);
        if (!getConnectedControllersManager().isSessionCommandAvailable(controller, command)) {
            result.sendError(/* extras= */
            null);
            return;
        }
        ListenableFuture<SessionResult> future = librarySessionImpl.onCustomCommandOnHandler(controller, command, extras);
        sendCustomActionResultWhenReady(result, future);
    });
}
Also used : Nullable(androidx.annotation.Nullable) ControllerInfo(androidx.media3.session.MediaSession.ControllerInfo)

Example 7 with ControllerInfo

use of androidx.media3.session.MediaSession.ControllerInfo in project media by androidx.

the class MediaLibraryServiceLegacyStub method onLoadChildren.

@Override
public void onLoadChildren(String parentId, Result<List<MediaBrowserCompat.MediaItem>> result, @Nullable Bundle options) {
    @Nullable ControllerInfo controller = getCurrentController();
    if (controller == null) {
        result.sendError(/* extras= */
        null);
        return;
    }
    if (TextUtils.isEmpty(parentId)) {
        Log.w(TAG, "onLoadChildren(): Ignoring empty parentId from " + controller);
        result.sendError(/* extras= */
        null);
        return;
    }
    result.detach();
    postOrRun(librarySessionImpl.getApplicationHandler(), () -> {
        if (!getConnectedControllersManager().isSessionCommandAvailable(controller, SessionCommand.COMMAND_CODE_LIBRARY_GET_CHILDREN)) {
            result.sendError(/* extras= */
            null);
            return;
        }
        if (options != null) {
            options.setClassLoader(librarySessionImpl.getContext().getClassLoader());
            try {
                int page = options.getInt(EXTRA_PAGE);
                int pageSize = options.getInt(EXTRA_PAGE_SIZE);
                if (page >= 0 && pageSize > 0) {
                    // Requesting the list of children through pagination.
                    @Nullable LibraryParams params = MediaUtils.convertToLibraryParams(librarySessionImpl.getContext(), options);
                    ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> future = librarySessionImpl.onGetChildrenOnHandler(controller, parentId, page, pageSize, params);
                    sendLibraryResultWithMediaItemsWhenReady(result, future);
                    return;
                }
            // Cannot distinguish onLoadChildren() why it's called either by
            // {@link MediaBrowserCompat#subscribe()} or
            // {@link MediaBrowserServiceCompat#notifyChildrenChanged}.
            } catch (BadParcelableException e) {
            // pass-through.
            }
        }
        // A MediaBrowserCompat called loadChildren with no pagination option.
        ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> future = librarySessionImpl.onGetChildrenOnHandler(controller, parentId, /* page= */
        0, /* pageSize= */
        Integer.MAX_VALUE, /* params= */
        null);
        sendLibraryResultWithMediaItemsWhenReady(result, future);
    });
}
Also used : MediaItem(androidx.media3.common.MediaItem) LibraryParams(androidx.media3.session.MediaLibraryService.LibraryParams) Nullable(androidx.annotation.Nullable) ControllerInfo(androidx.media3.session.MediaSession.ControllerInfo) BadParcelableException(android.os.BadParcelableException)

Example 8 with ControllerInfo

use of androidx.media3.session.MediaSession.ControllerInfo in project media by androidx.

the class MediaSessionService method onStartCommand.

/**
 * Called when a component calls {@link android.content.Context#startService(Intent)}.
 *
 * <p>The default implementation handles the incoming media button events. In this case, the
 * intent will have the action {@link Intent#ACTION_MEDIA_BUTTON}. Override this method if this
 * service also needs to handle actions other than {@link Intent#ACTION_MEDIA_BUTTON}.
 */
@CallSuper
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    if (intent == null) {
        return START_STICKY;
    }
    DefaultActionFactory actionFactory;
    synchronized (lock) {
        actionFactory = checkStateNotNull(this.actionFactory);
    }
    @Nullable Uri uri = intent.getData();
    @Nullable MediaSession session = uri != null ? MediaSession.getSession(uri) : null;
    if (actionFactory.isMediaAction(intent)) {
        if (session == null) {
            ControllerInfo controllerInfo = ControllerInfo.createLegacyControllerInfo();
            session = onGetSession(controllerInfo);
            if (session == null) {
                return START_STICKY;
            }
            addSession(session);
        }
        @Nullable KeyEvent keyEvent = actionFactory.getKeyEvent(intent);
        if (keyEvent != null) {
            session.getSessionCompat().getController().dispatchMediaButtonEvent(keyEvent);
        }
    } else if (actionFactory.isCustomAction(intent)) {
        @Nullable String customAction = actionFactory.getCustomAction(intent);
        if (session != null && customAction != null) {
            Bundle customExtras = actionFactory.getCustomActionExtras(intent);
            getMediaNotificationManager().onCustomAction(session, customAction, customExtras);
        }
    }
    return START_STICKY;
}
Also used : KeyEvent(android.view.KeyEvent) Bundle(android.os.Bundle) Uri(android.net.Uri) Nullable(androidx.annotation.Nullable) ControllerInfo(androidx.media3.session.MediaSession.ControllerInfo) CallSuper(androidx.annotation.CallSuper)

Example 9 with ControllerInfo

use of androidx.media3.session.MediaSession.ControllerInfo in project media by androidx.

the class MediaSessionStub method dispatchSessionTaskWithSessionCommandInternal.

private <T, K extends MediaSessionImpl> void dispatchSessionTaskWithSessionCommandInternal(IMediaController caller, int seq, @Nullable SessionCommand sessionCommand, @CommandCode int commandCode, SessionTask<T, K> task, PostSessionTask<T> postTask) {
    long token = Binder.clearCallingIdentity();
    try {
        @SuppressWarnings({ "unchecked", "cast.unsafe" }) @Nullable K sessionImpl = (K) this.sessionImpl.get();
        if (sessionImpl == null || sessionImpl.isReleased()) {
            return;
        }
        @Nullable ControllerInfo controller = connectedControllersManager.getController(caller.asBinder());
        if (controller == null) {
            return;
        }
        postOrRun(sessionImpl.getApplicationHandler(), () -> {
            if (!connectedControllersManager.isConnected(controller)) {
                return;
            }
            if (sessionCommand != null) {
                if (!connectedControllersManager.isSessionCommandAvailable(controller, sessionCommand)) {
                    sendSessionResult(controller, seq, new SessionResult(SessionResult.RESULT_ERROR_PERMISSION_DENIED));
                    return;
                }
            } else {
                if (!connectedControllersManager.isSessionCommandAvailable(controller, commandCode)) {
                    sendSessionResult(controller, seq, new SessionResult(SessionResult.RESULT_ERROR_PERMISSION_DENIED));
                    return;
                }
            }
            T result = task.run(sessionImpl, controller);
            postTask.run(controller, seq, result);
        });
    } finally {
        Binder.restoreCallingIdentity(token);
    }
}
Also used : COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT(androidx.media3.session.SessionCommand.COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT) COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT(androidx.media3.session.SessionCommand.COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT) COMMAND_SEEK_TO_NEXT(androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT) COMMAND_SEEK_BACK(androidx.media3.common.Player.COMMAND_SEEK_BACK) Nullable(androidx.annotation.Nullable) ControllerInfo(androidx.media3.session.MediaSession.ControllerInfo)

Example 10 with ControllerInfo

use of androidx.media3.session.MediaSession.ControllerInfo in project media by androidx.

the class MediaSessionStub method connect.

public void connect(IMediaController caller, int controllerVersion, String callingPackage, int pid, int uid, Bundle connectionHints) {
    MediaSessionManager.RemoteUserInfo remoteUserInfo = new MediaSessionManager.RemoteUserInfo(callingPackage, pid, uid);
    ControllerInfo controllerInfo = new ControllerInfo(remoteUserInfo, controllerVersion, sessionManager.isTrustedForMediaControl(remoteUserInfo), new Controller2Cb(caller), connectionHints);
    @Nullable MediaSessionImpl sessionImpl = this.sessionImpl.get();
    if (sessionImpl == null || sessionImpl.isReleased()) {
        try {
            caller.onDisconnected(/* seq= */
            0);
        } catch (RemoteException e) {
        // Controller may be died prematurely.
        // Not an issue because we'll ignore it anyway.
        }
        return;
    }
    pendingControllers.add(controllerInfo);
    postOrRun(sessionImpl.getApplicationHandler(), () -> {
        boolean connected = false;
        try {
            pendingControllers.remove(controllerInfo);
            if (sessionImpl.isReleased()) {
                return;
            }
            IBinder callbackBinder = checkStateNotNull((Controller2Cb) controllerInfo.getControllerCb()).getCallbackBinder();
            MediaSession.ConnectionResult connectionResult = sessionImpl.onConnectOnHandler(controllerInfo);
            // media keys to.
            if (!connectionResult.isAccepted && !controllerInfo.isTrusted()) {
                return;
            }
            if (!connectionResult.isAccepted) {
                // For the accepted controller, send non-null allowed commands to keep connection.
                connectionResult = MediaSession.ConnectionResult.accept(SessionCommands.EMPTY, Player.Commands.EMPTY);
            }
            SequencedFutureManager sequencedFutureManager;
            if (connectedControllersManager.isConnected(controllerInfo)) {
                Log.w(TAG, "Controller " + controllerInfo + " has sent connection" + " request multiple times");
            }
            connectedControllersManager.addController(callbackBinder, controllerInfo, connectionResult.availableSessionCommands, connectionResult.availablePlayerCommands);
            sequencedFutureManager = checkStateNotNull(connectedControllersManager.getSequencedFutureManager(controllerInfo));
            // If connection is accepted, notify the current state to the controller.
            // It's needed because we cannot call synchronous calls between
            // session/controller.
            PlayerWrapper playerWrapper = sessionImpl.getPlayerWrapper();
            PlayerInfo playerInfo = playerWrapper.createPlayerInfoForBundling();
            ConnectionState state = new ConnectionState(MediaLibraryInfo.VERSION_INT, MediaSessionStub.this, sessionImpl.getSessionActivity(), connectionResult.availableSessionCommands, connectionResult.availablePlayerCommands, playerWrapper.getAvailableCommands(), sessionImpl.getToken().getExtras(), playerInfo);
            // another thread.
            if (sessionImpl.isReleased()) {
                return;
            }
            try {
                caller.onConnected(sequencedFutureManager.obtainNextSequenceNumber(), state.toBundle());
                connected = true;
            } catch (RemoteException e) {
            // Controller may be died prematurely.
            }
            sessionImpl.onPostConnectOnHandler(controllerInfo);
        } finally {
            if (!connected) {
                try {
                    caller.onDisconnected(/* seq= */
                    0);
                } catch (RemoteException e) {
                // Controller may be died prematurely.
                // Not an issue because we'll ignore it anyway.
                }
            }
        }
    });
}
Also used : MediaSessionManager(androidx.media.MediaSessionManager) IBinder(android.os.IBinder) RemoteException(android.os.RemoteException) ControllerInfo(androidx.media3.session.MediaSession.ControllerInfo) Nullable(androidx.annotation.Nullable)

Aggregations

ControllerInfo (androidx.media3.session.MediaSession.ControllerInfo)44 Test (org.junit.Test)27 CountDownLatch (java.util.concurrent.CountDownLatch)26 Nullable (androidx.annotation.Nullable)22 LargeTest (androidx.test.filters.LargeTest)22 Bundle (android.os.Bundle)13 SessionCallback (androidx.media3.session.MediaSession.SessionCallback)12 Uri (android.net.Uri)8 RemoteException (android.os.RemoteException)7 LibraryParams (androidx.media3.session.MediaLibraryService.LibraryParams)7 AtomicReference (java.util.concurrent.atomic.AtomicReference)7 MediaItem (androidx.media3.common.MediaItem)6 ControllerCb (androidx.media3.session.MediaSession.ControllerCb)4 MediumTest (androidx.test.filters.MediumTest)4 DeadObjectException (android.os.DeadObjectException)3 PlaybackParameters (androidx.media3.common.PlaybackParameters)3 Rating (androidx.media3.common.Rating)3 DeviceInfo (androidx.media3.common.DeviceInfo)2 PlaybackException (androidx.media3.common.PlaybackException)2 COMMAND_SEEK_BACK (androidx.media3.common.Player.COMMAND_SEEK_BACK)2