Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aea24386 authored by Sungsoo Lim's avatar Sungsoo Lim
Browse files

Provide a way to get the command result

Bug: 122055262
Test: build
Change-Id: Icc6c2c791461df5d47479e82592895fc84b1974e
parent e7fe2a26
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;

import java.util.Objects;

@@ -103,9 +104,10 @@ public final class Controller2Link implements Parcelable {
    }

    /** Interface method for IMediaController2.sendSessionCommand */
    public void sendSessionCommand(int seq, Session2Command command, Bundle args) {
    public void sendSessionCommand(int seq, Session2Command command, Bundle args,
            ResultReceiver resultReceiver) {
        try {
            mIController.sendSessionCommand(seq, command, args);
            mIController.sendSessionCommand(seq, command, args, resultReceiver);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -126,8 +128,9 @@ public final class Controller2Link implements Parcelable {
    }

    /** Stub implementation for IMediaController2.sendSessionCommand */
    public void onSessionCommand(int seq, Session2Command command, Bundle args) {
        mController.onSessionCommand(seq, command, args);
    public void onSessionCommand(int seq, Session2Command command, Bundle args,
            ResultReceiver resultReceiver) {
        mController.onSessionCommand(seq, command, args, resultReceiver);
    }

    private class Controller2Stub extends IMediaController2.Stub {
@@ -142,8 +145,9 @@ public final class Controller2Link implements Parcelable {
        }

        @Override
        public void sendSessionCommand(int seq, Session2Command command, Bundle args) {
            Controller2Link.this.onSessionCommand(seq, command, args);
        public void sendSessionCommand(int seq, Session2Command command, Bundle args,
                ResultReceiver resultReceiver) {
            Controller2Link.this.onSessionCommand(seq, command, args, resultReceiver);
        }
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.media;

import android.os.Bundle;
import android.os.ResultReceiver;
import android.media.Session2Command;

/**
@@ -30,5 +31,6 @@ import android.media.Session2Command;
oneway interface IMediaController2 {
    void notifyConnected(int seq, in Bundle connectionResult) = 0;
    void notifyDisconnected(int seq) = 1;
    void sendSessionCommand(int seq, in Session2Command command, in Bundle args) = 2;
    void sendSessionCommand(int seq, in Session2Command command, in Bundle args,
            in ResultReceiver resultReceiver) = 2;
}
+2 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.media;

import android.os.Bundle;
import android.os.ResultReceiver;
import android.media.Controller2Link;
import android.media.Session2Command;

@@ -32,6 +33,6 @@ oneway interface IMediaSession2 {
    void connect(in Controller2Link caller, int seq, in Bundle connectionRequest) = 0;
    void disconnect(in Controller2Link caller, int seq) = 1;
    void sendSessionCommand(in Controller2Link caller, int seq, in Session2Command sessionCommand,
            in Bundle args) = 2;
            in Bundle args, in ResultReceiver resultReceiver) = 2;
    // Next Id : 3
}
+48 −8
Original line number Diff line number Diff line
@@ -27,8 +27,10 @@ import android.annotation.Nullable;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
import android.os.ResultReceiver;
import android.util.Log;

import java.util.concurrent.Executor;
@@ -56,6 +58,7 @@ public class MediaController2 implements AutoCloseable {
    private final Session2Token mSessionToken;
    private final Executor mCallbackExecutor;
    private final Controller2Link mControllerStub;
    private final Handler mResultHandler;

    private final Object mLock = new Object();
    //@GuardedBy("mLock")
@@ -95,6 +98,8 @@ public class MediaController2 implements AutoCloseable {
        mCallbackExecutor = executor;
        mCallback = callback;
        mControllerStub = new Controller2Link(this);
        // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
        mResultHandler = new Handler(context.getMainLooper());

        mNextSeqNumber = 0;

@@ -127,23 +132,36 @@ public class MediaController2 implements AutoCloseable {
     * Sends a session command to the session
     * <p>
     * @param command the session command
     * @param args optional argument
     * @param args optional arguments
     * @return a token which will be sent together in {@link ControllerCallback#onCommandResult}
     *     when its result is received.
     */
    // TODO: make cancelable and provide a way to get the result.
    public void sendSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
    // TODO: make cancelable.
    public Object sendSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
        if (command == null) {
            throw new IllegalArgumentException("command shouldn't be null");
        }

        ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
            protected void onReceiveResult(int resultCode, Bundle resultData) {
                mCallbackExecutor.execute(() -> {
                    mCallback.onCommandResult(MediaController2.this, this,
                            command, resultData);
                });
            }
        };

        synchronized (mLock) {
            if (mSessionBinder != null) {
                try {
                    mSessionBinder.sendSessionCommand(mControllerStub, mNextSeqNumber++,
                            command, args);
                            command, args, resultReceiver);
                } catch (RuntimeException e)  {
                    // No-op
                }
            }
        }
        return resultReceiver;
    }

    // Called by Controller2Link.onConnected
@@ -191,11 +209,15 @@ public class MediaController2 implements AutoCloseable {
    }

    // Called by Controller2Link.onSessionCommand
    void onSessionCommand(int seq, Session2Command command, Bundle args) {
    void onSessionCommand(int seq, Session2Command command, Bundle args,
            @Nullable ResultReceiver resultReceiver) {
        final long token = Binder.clearCallingIdentity();
        try {
            mCallbackExecutor.execute(() -> {
                mCallback.onSessionCommand(MediaController2.this, command, args);
                Bundle result = mCallback.onSessionCommand(MediaController2.this, command, args);
                if (resultReceiver != null) {
                    resultReceiver.send(0, result);
                }
            });
        } finally {
            Binder.restoreCallingIdentity(token);
@@ -251,10 +273,28 @@ public class MediaController2 implements AutoCloseable {
        public void onDisconnected(@NonNull MediaController2 controller) { }

        /**
         * Called when a controller sent a session command.
         * Called when the connected session sent a session command.
         *
         * @param controller the controller for this event
         * @param command the session command
         * @param args optional arguments
         * @return the result for the session command
         */
        public void onSessionCommand(@NonNull MediaController2 controller,
        public Bundle onSessionCommand(@NonNull MediaController2 controller,
                @NonNull Session2Command command, @Nullable Bundle args) {
            return null;
        }

        /**
         * Called when the command sent to the connected session is finished.
         *
         * @param controller the controller for this event
         * @param token the token got from {@link MediaController2#sendSessionCommand}
         * @param command the session command
         * @param result the result of the session command
         */
        public void onCommandResult(@NonNull MediaController2 controller, @NonNull Object token,
                @NonNull Session2Command command, @Nullable Bundle result) {
        }
    }
}
+77 −36
Original line number Diff line number Diff line
@@ -31,7 +31,9 @@ import android.media.session.MediaSessionManager;
import android.media.session.MediaSessionManager.RemoteUserInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Process;
import android.os.ResultReceiver;
import android.util.Log;

import java.util.ArrayList;
@@ -80,6 +82,7 @@ public class MediaSession2 implements AutoCloseable {
    private final PendingIntent mSessionActivity;
    private final Session2Token mSessionToken;
    private final MediaSessionManager mSessionManager;
    private final Handler mResultHandler;

    //@GuardedBy("mLock")
    @SuppressWarnings("WeakerAccess") /* synthetic access */
@@ -104,6 +107,8 @@ public class MediaSession2 implements AutoCloseable {
                mSessionStub);
        mSessionManager = (MediaSessionManager) mContext.getSystemService(
                Context.MEDIA_SESSION_SERVICE);
        // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
        mResultHandler = new Handler(context.getMainLooper());
    }

    @Override
@@ -129,7 +134,7 @@ public class MediaSession2 implements AutoCloseable {
     * Broadcasts a session command to all the connected controllers
     * <p>
     * @param command the session command
     * @param args optional argument
     * @param args optional arguments
     */
    public void broadcastSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
        if (command == null) {
@@ -140,7 +145,7 @@ public class MediaSession2 implements AutoCloseable {
            controllerInfos = mConnectedControllers.values();
        }
        for (ControllerInfo controller : controllerInfos) {
            controller.sendSessionCommand(command, args);
            controller.sendSessionCommand(command, args, null);
        }
    }

@@ -149,10 +154,12 @@ public class MediaSession2 implements AutoCloseable {
     * <p>
     * @param controller the controller to get the session command
     * @param command the session command
     * @param args optional argument
     * @param args optional arguments
     * @return a token which will be sent together in {@link SessionCallback#onCommandResult}
     *     when its result is received.
     */
    // TODO: make cancelable and provide a way to get the result.
    public void sendSessionCommand(@NonNull ControllerInfo controller,
    // TODO: make cancelable.
    public Object sendSessionCommand(@NonNull ControllerInfo controller,
            @NonNull Session2Command command, @Nullable Bundle args) {
        if (controller == null) {
            throw new IllegalArgumentException("controller shouldn't be null");
@@ -160,7 +167,16 @@ public class MediaSession2 implements AutoCloseable {
        if (command == null) {
            throw new IllegalArgumentException("command shouldn't be null");
        }
        controller.sendSessionCommand(command, args);
        ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
            protected void onReceiveResult(int resultCode, Bundle resultData) {
                mCallbackExecutor.execute(() -> {
                    mCallback.onCommandResult(MediaSession2.this, controller, this,
                            command, resultData);
                });
            }
        };
        controller.sendSessionCommand(command, args, resultReceiver);
        return resultReceiver;
    }

    boolean isClosed() {
@@ -264,7 +280,8 @@ public class MediaSession2 implements AutoCloseable {

    // Called by Session2Link.onSessionCommand
    void onSessionCommand(final Controller2Link controller, final int seq,
            final Session2Command command, final Bundle args) {
            final Session2Command command, final Bundle args,
            @Nullable ResultReceiver resultReceiver) {
        if (controller == null) {
            return;
        }
@@ -281,8 +298,11 @@ public class MediaSession2 implements AutoCloseable {
        try {
            mCallbackExecutor.execute(() -> {
                try {
                    mCallback.onSessionCommand(
                    Bundle result = mCallback.onSessionCommand(
                            MediaSession2.this, controllerInfo, command, args);
                    if (resultReceiver != null) {
                        resultReceiver.send(0, result);
                    }
                } catch (RuntimeException e) {
                    // Controller may be died prematurely.
                }
@@ -458,12 +478,9 @@ public class MediaSession2 implements AutoCloseable {

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof ControllerInfo)) {
                return false;
            }
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof ControllerInfo)) return false;
            if (this == obj) return true;

            ControllerInfo other = (ControllerInfo) obj;
            if (mControllerBinder != null || other.mControllerBinder != null) {
                return Objects.equals(mControllerBinder, other.mControllerBinder);
@@ -478,39 +495,42 @@ public class MediaSession2 implements AutoCloseable {
        }

        void notifyConnected(Bundle connectionResult) {
            if (mControllerBinder != null) {
            if (mControllerBinder == null) return;

            try {
                mControllerBinder.notifyConnected(getNextSeqNumber(), connectionResult);
            } catch (RuntimeException e) {
                // Controller may be died prematurely.
            }
        }
        }

        void notifyDisconnected() {
            if (mControllerBinder != null) {
            if (mControllerBinder == null) return;

            try {
                mControllerBinder.notifyDisconnected(getNextSeqNumber());
            } catch (RuntimeException e) {
                // Controller may be died prematurely.
            }
        }
        }

        void sendSessionCommand(Session2Command command, Bundle args) {
            if (mControllerBinder != null) {
        void sendSessionCommand(Session2Command command, Bundle args,
                ResultReceiver resultReceiver) {
            if (mControllerBinder == null) return;
            try {
                    mControllerBinder.sendSessionCommand(getNextSeqNumber(), command, args);
                int seq = getNextSeqNumber();
                mControllerBinder.sendSessionCommand(seq, command, args, resultReceiver);
            } catch (RuntimeException e) {
                // Controller may be died prematurely.
            }
        }
        }

        private synchronized int getNextSeqNumber() {
        private int getNextSeqNumber() {
            synchronized (this) {
                return mNextSeqNumber++;
            }
        }
    }

    /**
     * Callback to be called for all incoming commands from {@link MediaController2}s.
@@ -550,10 +570,31 @@ public class MediaSession2 implements AutoCloseable {

        /**
         * Called when a controller sent a session command.
         *
         * @param session the session for this event
         * @param controller controller information
         * @param command the session command
         * @param args optional arguments
         * @return The result for the session command
         */
        public void onSessionCommand(@NonNull MediaSession2 session,
        public Bundle onSessionCommand(@NonNull MediaSession2 session,
                @NonNull ControllerInfo controller, @NonNull Session2Command command,
                @Nullable Bundle args) {
            return null;
        }

        /**
         * Called when the command sent to the controller is finished.
         *
         * @param session the session for this event
         * @param controller controller information
         * @param token the token got from {@link MediaSession2#sendSessionCommand}
         * @param command the session command
         * @param result the result of the session command
         */
        public void onCommandResult(@NonNull MediaSession2 session,
                @NonNull ControllerInfo controller, @NonNull Object token,
                @NonNull Session2Command command, @Nullable Bundle result) {
        }
    }
}
Loading