public final class

MediaSessionManager

extends java.lang.Object

 java.lang.Object

↳androidx.media.MediaSessionManager

Gradle dependencies

compile group: 'androidx.media', name: 'media', version: '1.7.0'

  • groupId: androidx.media
  • artifactId: media
  • version: 1.7.0

Artifact androidx.media:media:1.7.0 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.media:media com.android.support:support-media-compat

Androidx class mapping:

androidx.media.MediaSessionManager android.support.v4.media.MediaSessionManager

Overview

Provides support for interacting with media sessions that applications have published to express their ongoing media playback state.

Summary

Methods
public static MediaSessionManagergetSessionManager(Context context)

Gets an instance of the media session manager associated with the context.

public booleanisTrustedForMediaControl(MediaSessionManager.RemoteUserInfo userInfo)

Checks whether the remote user is a trusted app.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Methods

public static MediaSessionManager getSessionManager(Context context)

Gets an instance of the media session manager associated with the context.

Returns:

The MediaSessionManager instance for this context.

public boolean isTrustedForMediaControl(MediaSessionManager.RemoteUserInfo userInfo)

Checks whether the remote user is a trusted app.

An app is trusted if the app holds the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission or has an enabled notification listener.

Parameters:

userInfo: The remote user info from either getCurrentControllerInfo and MediaBrowserServiceCompat.getCurrentBrowserInfo().

Returns:

true if the remote user is trusted and its package name matches with the UID. false otherwise.

Source

/*
 * Copyright 2018 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 androidx.media;

import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;

import android.content.Context;
import android.os.Build;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;

/**
 * Provides support for interacting with {@link MediaSessionCompat media sessions} that
 * applications have published to express their ongoing media playback state.
 *
 * @see MediaSessionCompat
 * @see MediaControllerCompat
 */
public final class MediaSessionManager {
    static final String TAG = "MediaSessionManager";
    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private static final Object sLock = new Object();
    private static volatile MediaSessionManager sSessionManager;

    MediaSessionManagerImpl mImpl;

    /**
     * Gets an instance of the media session manager associated with the context.
     *
     * @return The MediaSessionManager instance for this context.
     */
    @NonNull
    public static MediaSessionManager getSessionManager(@NonNull Context context) {
        if (context == null) {
            throw new IllegalArgumentException("context cannot be null");
        }
        synchronized (sLock) {
            if (sSessionManager == null) {
                sSessionManager = new MediaSessionManager(context.getApplicationContext());
            }
            return sSessionManager;
        }
    }

    private MediaSessionManager(Context context) {
        if (Build.VERSION.SDK_INT >= 28) {
            mImpl = new MediaSessionManagerImplApi28(context);
        } else if (Build.VERSION.SDK_INT >= 21) {
            mImpl = new MediaSessionManagerImplApi21(context);
        } else {
            mImpl = new MediaSessionManagerImplBase(context);
        }
    }

    /**
     * Checks whether the remote user is a trusted app.
     * <p>
     * An app is trusted if the app holds the android.Manifest.permission.MEDIA_CONTENT_CONTROL
     * permission or has an enabled notification listener.
     *
     * @param userInfo The remote user info from either
     *            {@link MediaSessionCompat#getCurrentControllerInfo()} and
     *            {@link MediaBrowserServiceCompat#getCurrentBrowserInfo()}.
     * @return {@code true} if the remote user is trusted and its package name matches with the UID.
     *            {@code false} otherwise.
     */
    public boolean isTrustedForMediaControl(@NonNull RemoteUserInfo userInfo) {
        if (userInfo == null) {
            throw new IllegalArgumentException("userInfo should not be null");
        }
        return mImpl.isTrustedForMediaControl(userInfo.mImpl);
    }

    Context getContext() {
        return mImpl.getContext();
    }

    interface MediaSessionManagerImpl {
        Context getContext();
        boolean isTrustedForMediaControl(RemoteUserInfoImpl userInfo);
    }

    interface RemoteUserInfoImpl {
        String getPackageName();
        int getPid();
        int getUid();
    }

    /**
     * Information of a remote user of {@link MediaSessionCompat} or
     * {@link MediaBrowserServiceCompat}. This can be used to decide whether the remote user is
     * trusted app, and also differentiate caller of {@link MediaSessionCompat} and
     * {@link MediaBrowserServiceCompat} callbacks.
     * <p>
     * See {@link #equals(Object)} to take a look at how it differentiate media controller.
     *
     * @see #isTrustedForMediaControl(RemoteUserInfo)
     */
    public static final class RemoteUserInfo {
        /**
         * Used by {@link #getPackageName()} when the session is connected to the legacy controller
         * whose exact package name cannot be obtained.
         */
        public static final String LEGACY_CONTROLLER = "android.media.session.MediaController";

        /**
         * Represents an unknown pid of an application.
         */
        @RestrictTo(LIBRARY_GROUP_PREFIX)
        public static final int UNKNOWN_PID = -1;

        /**
         * Represents an unknown uid of an application.
         */
        @RestrictTo(LIBRARY_GROUP_PREFIX)
        public static final int UNKNOWN_UID = -1;

        RemoteUserInfoImpl mImpl;

        /**
         * Public constructor.
         * <p>
         * Can be used for {@link MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)}}.
         *
         * @param packageName package name of the remote user
         * @param pid pid of the remote user
         * @param uid uid of the remote user
         * @throws IllegalArgumentException if package name is empty
         */
        public RemoteUserInfo(@NonNull String packageName, int pid, int uid) {
            if (packageName == null) {
                throw new NullPointerException("package shouldn't be null");
            } else if (TextUtils.isEmpty(packageName)) {
                throw new IllegalArgumentException("packageName should be nonempty");
            }
            if (Build.VERSION.SDK_INT >= 28) {
                mImpl = new MediaSessionManagerImplApi28.RemoteUserInfoImplApi28(
                        packageName, pid, uid);
            } else {
                // Note: We need to include IBinder to distinguish controllers in a process.
                mImpl = new MediaSessionManagerImplBase.RemoteUserInfoImplBase(
                        packageName, pid, uid);
            }
        }

        /**
         * Public constructor for internal uses.
         * <p>
         * Internal code MUST use this on SDK >= 28 to distinguish individual RemoteUserInfos in a
         * process.
         *
         * @param remoteUserInfo Framework RemoteUserInfo
         * @throws IllegalArgumentException if package name is empty
         */
        @RestrictTo(LIBRARY)
        @RequiresApi(28)
        public RemoteUserInfo(
                android.media.session.MediaSessionManager.RemoteUserInfo remoteUserInfo) {
            // Framework RemoteUserInfo doesn't ensure non-null nor non-empty package name,
            // so ensure package name here instead.
            String packageName =
                    MediaSessionManagerImplApi28.RemoteUserInfoImplApi28.getPackageName(
                            remoteUserInfo);
            if (packageName == null) {
                throw new NullPointerException("package shouldn't be null");
            } else if (TextUtils.isEmpty(packageName)) {
                throw new IllegalArgumentException("packageName should be nonempty");
            }
            mImpl = new MediaSessionManagerImplApi28.RemoteUserInfoImplApi28(remoteUserInfo);
        }

        /**
         * @return package name of the controller. Can be {@link #LEGACY_CONTROLLER} if the package
         *         name cannot be obtained.
         */
        public @NonNull String getPackageName() {
            return mImpl.getPackageName();
        }

        /**
         * @return pid of the controller. Can be a negative value if the pid cannot be obtained.
         */
        public int getPid() {
            return mImpl.getPid();
        }

        /**
         * @return uid of the controller. Can be a negative value if the uid cannot be obtained.
         */
        public int getUid() {
            return mImpl.getUid();
        }

        /**
         * Returns equality of two RemoteUserInfo by comparing their package name, UID, and PID.
         * <p>
         * On P and before (API <= 28), two RemoteUserInfo objects equal if following conditions are
         * met:
         * <ol>
         * <li>UID and package name are the same</li>
         * <li>One of the RemoteUserInfo's PID is UNKNOWN_PID or both of RemoteUserInfo's
         *     PID are the same</li>
         * </ol>
         *
         * @param obj the reference object with which to compare.
         * @return {@code true} if equals, {@code false} otherwise
         */
        @Override
        public boolean equals(@Nullable Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof RemoteUserInfo)) {
                return false;
            }
            return mImpl.equals(((RemoteUserInfo) obj).mImpl);
        }

        @Override
        public int hashCode() {
            return mImpl.hashCode();
        }
    }
}