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

Commit 2a1281a2 authored by Colin Cross's avatar Colin Cross Committed by Android (Google) Code Review
Browse files

Merge "MediaSessionManager: Split abstract class Callback into interfaces"

parents c8911a14 c7e71526
Loading
Loading
Loading
Loading
+10 −8
Original line number Diff line number Diff line
@@ -4195,18 +4195,20 @@ package android.media.audiopolicy {
package android.media.session {
  public final class MediaSessionManager {
    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.Callback);
    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventDispatchedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener);
    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventSessionChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener);
    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventDispatchedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener);
    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventSessionChangedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener);
    method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler);
    method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler);
    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void unregisterCallback(@NonNull android.media.session.MediaSessionManager.Callback);
  }
  public abstract static class MediaSessionManager.Callback {
    ctor public MediaSessionManager.Callback();
    method public abstract void onAddressedPlayerChanged(android.media.session.MediaSession.Token);
    method public abstract void onAddressedPlayerChanged(android.content.ComponentName);
    method public abstract void onMediaKeyEventDispatched(android.view.KeyEvent, android.media.session.MediaSession.Token);
    method public abstract void onMediaKeyEventDispatched(android.view.KeyEvent, android.content.ComponentName);
  public static interface MediaSessionManager.OnMediaKeyEventDispatchedListener {
    method public default void onMediaKeyEventDispatched(@NonNull android.view.KeyEvent, @NonNull String, @NonNull android.media.session.MediaSession.Token);
  }
  public static interface MediaSessionManager.OnMediaKeyEventSessionChangedListener {
    method public default void onMediaKeyEventSessionChanged(@NonNull String, @Nullable android.media.session.MediaSession.Token);
  }
  public static interface MediaSessionManager.OnMediaKeyListener {
+4 −11
Original line number Diff line number Diff line
/* Copyright (C) 2016 The Android Open Source Project
/*
 * Copyright 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -15,21 +16,13 @@

package android.media.session;

import android.app.PendingIntent;
import android.content.ComponentName;
import android.media.session.MediaSession;
import android.view.KeyEvent;

/**
 * @hide
 */
oneway interface ICallback {
    void onMediaKeyEventDispatchedToMediaSession(in KeyEvent event,
oneway interface IOnMediaKeyEventDispatchedListener {
    void onMediaKeyEventDispatched(in KeyEvent event, in String packageName,
            in MediaSession.Token sessionToken);
    void onMediaKeyEventDispatchedToMediaButtonReceiver(in KeyEvent event,
            in ComponentName mediaButtonReceiver);

    void onAddressedPlayerChangedToMediaSession(in MediaSession.Token sessionToken);
    void onAddressedPlayerChangedToMediaButtonReceiver(in ComponentName mediaButtonReceiver);
}
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media.session;

import android.media.session.MediaSession;

/**
 * @hide
 */
oneway interface IOnMediaKeyEventSessionChangedListener {
    void onMediaKeyEventSessionChanged(in String packageName,
            in MediaSession.Token mediaKeyEventSessionToken);
}
+8 −3
Original line number Diff line number Diff line
@@ -20,7 +20,8 @@ import android.content.pm.ParceledListSlice;
import android.media.IRemoteVolumeController;
import android.media.Session2Token;
import android.media.session.IActiveSessionsListener;
import android.media.session.ICallback;
import android.media.session.IOnMediaKeyEventDispatchedListener;
import android.media.session.IOnMediaKeyEventSessionChangedListener;
import android.media.session.IOnMediaKeyListener;
import android.media.session.IOnVolumeKeyLongPressListener;
import android.media.session.ISession;
@@ -62,8 +63,12 @@ interface ISessionManager {
    // For PhoneWindowManager to precheck media keys
    boolean isGlobalPriorityActive();

    void registerCallback(in ICallback callback);
    void unregisterCallback(in ICallback callback);
    void addOnMediaKeyEventDispatchedListener(in IOnMediaKeyEventDispatchedListener listener);
    void removeOnMediaKeyEventDispatchedListener(in IOnMediaKeyEventDispatchedListener listener);
    void addOnMediaKeyEventSessionChangedListener(
            in IOnMediaKeyEventSessionChangedListener listener);
    void removeOnMediaKeyEventSessionChangedListener(
            in IOnMediaKeyEventSessionChangedListener listener);
    void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
    void setOnMediaKeyListener(in IOnMediaKeyListener listener);

+131 −122
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ import android.media.MediaSession2;
import android.media.Session2Token;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -78,29 +77,33 @@ public final class MediaSessionManager {
     */
    public static final int RESULT_MEDIA_KEY_HANDLED = 1;
    private final ISessionManager mService;
    private final OnMediaKeyEventDispatchedListenerStub mOnMediaKeyEventDispatchedListenerStub =
            new OnMediaKeyEventDispatchedListenerStub();
    private final OnMediaKeyEventSessionChangedListenerStub
            mOnMediaKeyEventSessionChangedListenerStub =
            new OnMediaKeyEventSessionChangedListenerStub();

    private final Object mLock = new Object();
    @GuardedBy("mLock")
    private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners
            = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>();
    private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners =
            new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>();
    @GuardedBy("mLock")
    private final ArrayMap<OnSession2TokensChangedListener, Session2TokensChangedWrapper>
            mSession2TokensListeners = new ArrayMap<>();
    @GuardedBy("mLock")
    private final CallbackStub mCbStub = new CallbackStub();
    private final Map<OnMediaKeyEventDispatchedListener, Executor>
            mOnMediaKeyEventDispatchedListeners = new HashMap<>();
    @GuardedBy("mLock")
    private final Map<Callback, Executor> mCallbacks = new HashMap<>();
    private final Map<OnMediaKeyEventSessionChangedListener, Executor>
            mMediaKeyEventSessionChangedCallbacks = new HashMap<>();
    @GuardedBy("mLock")
    private MediaSession.Token mCurMediaButtonSession;
    private String mCurMediaKeyEventSessionPackage;
    @GuardedBy("mLock")
    private ComponentName mCurMediaButtonReceiver;
    private MediaSession.Token mCurMediaKeyEventSession;

    private Context mContext;
    private OnVolumeKeyLongPressListenerImpl mOnVolumeKeyLongPressListener;
    private OnMediaKeyListenerImpl mOnMediaKeyListener;
    // TODO: Remove mLegacyCallback once Bluetooth app stop calling setCallback() method.
    @GuardedBy("mLock")
    private Callback mLegacyCallback;

    /**
     * @hide
@@ -756,89 +759,118 @@ public final class MediaSessionManager {
    }

    /**
     * Set a {@link Callback}.
     * Add a {@link OnMediaKeyEventDispatchedListener}.
     *
     * <p>System can only have a single callback, and the callback can only be set by
     * Bluetooth service process.
     * @param executor The executor on which the callback should be invoked
     * @param listener A {@link OnMediaKeyEventDispatchedListener}.
     * @hide
     */
    @SystemApi
    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
    public void addOnMediaKeyEventDispatchedListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull OnMediaKeyEventDispatchedListener listener) {
        if (executor == null) {
            throw new NullPointerException("executor shouldn't be null");
        }
        if (listener == null) {
            throw new NullPointerException("listener shouldn't be null");
        }
        synchronized (mLock) {
            try {
                mOnMediaKeyEventDispatchedListeners.put(listener, executor);
                if (mOnMediaKeyEventDispatchedListeners.size() == 1) {
                    mService.addOnMediaKeyEventDispatchedListener(
                            mOnMediaKeyEventDispatchedListenerStub);
                }
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to set media key listener", e);
            }
        }
    }

    /**
     * Remove a {@link OnMediaKeyEventDispatchedListener}.
     *
     * @param callback A {@link Callback}. {@code null} to reset.
     * @param handler The handler on which the callback should be invoked, or {@code null}
     *            if the callback should be invoked on the calling thread's looper.
     * @param listener A {@link OnMediaKeyEventDispatchedListener}.
     * @hide
     */
    // TODO: Remove this method once Bluetooth app stop calling it.
    public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
        if (handler == null) {
            handler = new Handler();
    @SystemApi
    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
    public void removeOnMediaKeyEventDispatchedListener(
            @NonNull OnMediaKeyEventDispatchedListener listener) {
        if (listener == null) {
            throw new NullPointerException("listener shouldn't be null");
        }
        synchronized (mLock) {
            if (mLegacyCallback != null) {
                unregisterCallback(mLegacyCallback);
            try {
                mOnMediaKeyEventDispatchedListeners.remove(listener);
                if (mOnMediaKeyEventDispatchedListeners.size() == 0) {
                    mService.removeOnMediaKeyEventDispatchedListener(
                            mOnMediaKeyEventDispatchedListenerStub);
                }
            mLegacyCallback = callback;
            if (callback != null) {
                registerCallback(new HandlerExecutor(handler), callback);
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to set media key event dispatched listener", e);
            }
        }
    }

    /**
     * Register a {@link Callback}.
     * Add a {@link OnMediaKeyEventDispatchedListener}.
     *
     * @param executor The executor on which the callback should be invoked
     * @param callback A {@link Callback}.
     * @param listener A {@link OnMediaKeyEventSessionChangedListener}.
     * @hide
     */
    @SystemApi
    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
            @NonNull Callback callback) {
    public void addOnMediaKeyEventSessionChangedListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull OnMediaKeyEventSessionChangedListener listener) {
        if (executor == null) {
            throw new NullPointerException("executor shouldn't be null");
        }
        if (callback == null) {
            throw new NullPointerException("callback shouldn't be null");
        if (listener == null) {
            throw new NullPointerException("listener shouldn't be null");
        }
        synchronized (mLock) {
            try {
                mCallbacks.put(callback, executor);
                if (mCurMediaButtonSession != null) {
                    executor.execute(
                            () -> callback.onAddressedPlayerChanged(mCurMediaButtonSession));
                } else if (mCurMediaButtonReceiver != null) {
                mMediaKeyEventSessionChangedCallbacks.put(listener, executor);
                executor.execute(
                            () -> callback.onAddressedPlayerChanged(mCurMediaButtonReceiver));
                }

                if (mCallbacks.size() == 1) {
                    mService.registerCallback(mCbStub);
                        () -> listener.onMediaKeyEventSessionChanged(
                                mCurMediaKeyEventSessionPackage, mCurMediaKeyEventSession));
                if (mMediaKeyEventSessionChangedCallbacks.size() == 1) {
                    mService.addOnMediaKeyEventSessionChangedListener(
                            mOnMediaKeyEventSessionChangedListenerStub);
                }
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to set media key callback", e);
                Log.e(TAG, "Failed to set media key listener", e);
            }
        }
    }

    /**
     * Unregister a {@link Callback}.
     * Remove a {@link OnMediaKeyEventSessionChangedListener}.
     *
     * @param callback A {@link Callback}.
     * @param listener A {@link OnMediaKeyEventSessionChangedListener}.
     * @hide
     */
    @SystemApi
    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
    public void unregisterCallback(@NonNull Callback callback) {
        if (callback == null) {
            throw new NullPointerException("callback shouldn't be null");
    public void removeOnMediaKeyEventSessionChangedListener(
            @NonNull OnMediaKeyEventSessionChangedListener listener) {
        if (listener == null) {
            throw new NullPointerException("listener shouldn't be null");
        }
        synchronized (mLock) {
            try {
                mCallbacks.remove(callback);
                if (mCallbacks.size() == 0) {
                    mService.unregisterCallback(mCbStub);
                mMediaKeyEventSessionChangedCallbacks.remove(listener);
                if (mMediaKeyEventSessionChangedCallbacks.size() == 0) {
                    mService.removeOnMediaKeyEventSessionChangedListener(
                            mOnMediaKeyEventSessionChangedListenerStub);
                }
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to set media key callback", e);
                Log.e(TAG, "Failed to set media key listener", e);
            }
        }
    }
@@ -900,54 +932,46 @@ public final class MediaSessionManager {
    }

    /**
     * Callbacks for the media session service.
     *
     * <p>Called when a media key event is dispatched or the addressed player is changed.
     * The addressed player is either the media session or the media button receiver that will
     * receive media key events.
     * Listener to receive when the media session service
     * @hide
     */
    @SystemApi
    public static abstract class Callback {
    public interface OnMediaKeyEventDispatchedListener {
        /**
         * Called when a media key event is dispatched to the media session
         * through the media session service.
         * Called when a media key event is dispatched through the media session service. The
         * session token can be {@link null} if the framework has sent the media key event to the
         * media button receiver to revive the media app's playback.
         *
         * @param event Dispatched media key event.
         * @param sessionToken The media session's token.
         */
        public abstract void onMediaKeyEventDispatched(KeyEvent event,
                MediaSession.Token sessionToken);

        /**
         * Called when a media key event is dispatched to the media button receiver
         * through the media session service.
         * <p>MediaSessionService may broadcast key events to the media button receiver
         * when reviving playback after the media session is released.
         * the session is dead when , but the framework sent
         *
         * @param event Dispatched media key event.
         * @param mediaButtonReceiver The media button receiver.
         * @param packageName Package
         * @param sessionToken The media session's token. Can be {@code null}.
         */
        public abstract void onMediaKeyEventDispatched(KeyEvent event,
                ComponentName mediaButtonReceiver);
        default void onMediaKeyEventDispatched(@NonNull KeyEvent event, @NonNull String packageName,
                @NonNull MediaSession.Token sessionToken) { }
    }

    /**
         * Called when the addressed player is changed to a media session.
         * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
         * {@link #registerCallback} if the addressed player exists.
         *
         * @param sessionToken The media session's token.
     * Listener to receive changes in the media key event session, which would receive the media key
     * event unless specified.
     * @hide
     */
        public abstract void onAddressedPlayerChanged(MediaSession.Token sessionToken);

    @SystemApi
    public interface OnMediaKeyEventSessionChangedListener {
        /**
         * Called when the addressed player is changed to the media button receiver.
         * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
         * {@link #registerCallback} if the addressed player exists.
         * Called when the media key session is changed to the given media session. The key event
         * session is the media session which would receive key event by default, unless the caller
         * has specified the target.
         * <p>
         * The session token can be {@link null} if the media button session is unset. In that case,
         * framework would dispatch to the last sessions's media button receiver.
         *
         * @param mediaButtonReceiver The media button receiver.
         * @param packageName The package name who would receive the media key event. Can be empty.
         * @param sessionToken The media session's token. Can be {@code null.}
         */
        public abstract void onAddressedPlayerChanged(ComponentName mediaButtonReceiver);
        default void onMediaKeyEventSessionChanged(@NonNull String packageName,
                @Nullable MediaSession.Token sessionToken) { }
    }

    /**
@@ -1149,50 +1173,35 @@ public final class MediaSessionManager {
        }
    }

    private final class CallbackStub extends ICallback.Stub {
    private final class OnMediaKeyEventDispatchedListenerStub
            extends IOnMediaKeyEventDispatchedListener.Stub {

        @Override
        public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event,
        public void onMediaKeyEventDispatched(KeyEvent event, String packageName,
                MediaSession.Token sessionToken) {
            synchronized (mLock) {
                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
                    e.getValue().execute(
                            () -> e.getKey().onMediaKeyEventDispatched(event, sessionToken));
                }
            }
        }

        @Override
        public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event,
                ComponentName mediaButtonReceiver) {
            synchronized (mLock) {
                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
                for (Map.Entry<OnMediaKeyEventDispatchedListener, Executor> e
                        : mOnMediaKeyEventDispatchedListeners.entrySet()) {
                    e.getValue().execute(
                            () -> e.getKey().onMediaKeyEventDispatched(event, mediaButtonReceiver));
                            () -> e.getKey().onMediaKeyEventDispatched(event, packageName,
                                    sessionToken));
                }
            }
        }

        @Override
        public void onAddressedPlayerChangedToMediaSession(MediaSession.Token sessionToken) {
            synchronized (mLock) {
                mCurMediaButtonSession = sessionToken;
                mCurMediaButtonReceiver = null;
                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
                    e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged(sessionToken));
                }
            }
    }

    private final class OnMediaKeyEventSessionChangedListenerStub
            extends IOnMediaKeyEventSessionChangedListener.Stub {
        @Override
        public void onAddressedPlayerChangedToMediaButtonReceiver(
                ComponentName mediaButtonReceiver) {
        public void onMediaKeyEventSessionChanged(String packageName,
                MediaSession.Token sessionToken) {
            synchronized (mLock) {
                mCurMediaButtonSession = null;
                mCurMediaButtonReceiver = mediaButtonReceiver;
                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
                    e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged(
                            mediaButtonReceiver));
                mCurMediaKeyEventSessionPackage = packageName;
                mCurMediaKeyEventSession = sessionToken;
                for (Map.Entry<OnMediaKeyEventSessionChangedListener, Executor> e
                        : mMediaKeyEventSessionChangedCallbacks.entrySet()) {
                    e.getValue().execute(() -> e.getKey().onMediaKeyEventSessionChanged(packageName,
                            sessionToken));
                }
            }
        }
Loading