Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
6042bec1
authored
Mar 02, 2023
by
bachinger
Committed by
tonihei
Mar 02, 2023
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Fix some JavaDoc in the Media3 session module
#minor-release PiperOrigin-RevId: 513501046
parent
cd753bd7
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
65 additions
and
52 deletions
libraries/session/src/main/java/androidx/media3/session/MediaSession.java
libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java
libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java
libraries/session/src/main/java/androidx/media3/session/MediaSession.java
View file @
6042bec1
...
@@ -68,14 +68,16 @@ import java.util.List;
...
@@ -68,14 +68,16 @@ import java.util.List;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/**
/**
* A session that allows a media app to expose its
transport controls and playback information in a
* A session that allows a media app to expose its
player functionality, information of the playlist
*
process to other processes including the Android framework and other apps. The common use cases
*
and the media item currently being played to other processes including the Android framework and
* are as follows:
*
other apps. The common use cases
are as follows:
*
*
* <ul>
* <ul>
* <li>Bluetooth/wired headset key events support
* <li>Receiving and dispatching media key events (for instance Bluetooth/wired headset and remote
* <li>Android Auto/Wearable support
* control devices).
* <li>Separating UI process and playback process
* <li>Publish media playback information and player commands to SystemUI (media notification) and
* Android Auto/Wear OS.
* <li>Separating UI process and playback process.
* </ul>
* </ul>
*
*
* <p>A session should be created when an app wants to publish media playback information or handle
* <p>A session should be created when an app wants to publish media playback information or handle
...
@@ -83,9 +85,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -83,9 +85,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* sessions can be created to provide finer grain controls of media. See <a
* sessions can be created to provide finer grain controls of media. See <a
* href="#MultipleSessions">Supporting Multiple Sessions</a> for details.
* href="#MultipleSessions">Supporting Multiple Sessions</a> for details.
*
*
* <p>If you want to support background playback, {@link MediaSessionService} is preferred. With the
* <p>If an app wants to support playback when in the background, using a {@link
* service, your playback can be revived even after playback is finished. See {@link
* MediaSessionService} is the preferred approach. See {@link MediaSessionService} for details.
* MediaSessionService} for details.
*
*
* <p>Topics covered here:
* <p>Topics covered here:
*
*
...
@@ -104,7 +105,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -104,7 +105,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* #getToken() session token} to other processes to allow them to create a {@link MediaController}
* #getToken() session token} to other processes to allow them to create a {@link MediaController}
* to interact with the session.
* to interact with the session.
*
*
* <p>When a session receives
transport control commands, the session sends the commands directly to
* <p>When a session receives
playback commands, the session calls corresponding methods directly on
* the underlying player set by {@link Builder#Builder(Context, Player)} or {@link
* the underlying player set by {@link Builder#Builder(Context, Player)} or {@link
* #setPlayer(Player)}.
* #setPlayer(Player)}.
*
*
...
@@ -114,15 +115,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -114,15 +115,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
*
*
* <h2 id="ThreadingModel">Threading Model</h2>
* <h2 id="ThreadingModel">Threading Model</h2>
*
*
* <p>The instances are thread safe, but
should be used on the
thread with a looper.
* <p>The instances are thread safe, but
must be used on a
thread with a looper.
*
*
* <p>{@link Callback} methods will be called
from
the application thread associated with the {@link
* <p>{@link Callback} methods will be called
on
the application thread associated with the {@link
* Player#getApplicationLooper() application looper} of the underlying player. When a new player is
* Player#getApplicationLooper() application looper} of the underlying player. When a new player is
* set by {@link #setPlayer}, the player
should
use the same application looper as the previous one.
* set by {@link #setPlayer}, the player
must
use the same application looper as the previous one.
*
*
* <p>The session listens to
events from the underlying player via {@link Player.Listener} and
* <p>The session listens to
player events via {@link Player.Listener} and expects the callback
*
expects the callback methods to be called from the application thread. If the player violates the
*
methods to be called on the application thread. If the player violates the threading contract, an
*
threading contract,
{@link IllegalStateException} will be thrown.
* {@link IllegalStateException} will be thrown.
*
*
* <h2 id="KeyEvents">Media Key Events Mapping</h2>
* <h2 id="KeyEvents">Media Key Events Mapping</h2>
*
*
...
@@ -161,7 +162,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -161,7 +162,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* </li>
* </li>
* <li>{@link Player#play()} otherwise</li>
* <li>{@link Player#play()} otherwise</li>
* </ul>
* </ul>
* <li>For a double tap, {@link Player#seekToNext()}</li>
* <li>In case the media key events are coming from another package ID than the package ID of
* the media app (events coming for instance from Bluetooth), a double tap generating two
* key events within a brief amount of time, is converted to {@link Player#seekToNext()}
* </li>
* </ul>
* </ul>
* </td>
* </td>
* </tr>
* </tr>
...
@@ -194,16 +198,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -194,16 +198,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* media or remote playback, since the <a
* media or remote playback, since the <a
* href="https://developer.android.com/guide/topics/media-apps/audio-focus">audio focus policy</a>
* href="https://developer.android.com/guide/topics/media-apps/audio-focus">audio focus policy</a>
* recommends not playing multiple audio content at the same time. Also, keep in mind that multiple
* recommends not playing multiple audio content at the same time. Also, keep in mind that multiple
* media sessions would make Android Auto and Bluetooth device
with display to show your apps
* media sessions would make Android Auto and Bluetooth device
s with display to show your app
* multiple times, because they list up media sessions, not media apps.
* multiple times, because they list up media sessions, not media apps.
*
*
* <h2 id="BackwardCompatibility">Backward Compatibility with Legacy Session APIs</h2>
* <h2 id="BackwardCompatibility">Backward Compatibility with Legacy Session APIs</h2>
*
*
* <p>An active {@link MediaSessionCompat} is internally created with the session for the backward
* <p>An active {@link MediaSessionCompat} is internally created with the session for backwards
* compatibility. It's used to handle incoming connection and commands from {@link
* compatibility. It's used to handle incoming connections and commands from {@link
* MediaControllerCompat}, and helps to utilize existing APIs that are built with legacy media
* MediaControllerCompat} instances, and helps to utilize existing APIs that are built with legacy
* session APIs. Use {@link #getSessionCompatToken} to get the legacy token of {@link
* media session APIs.
* MediaSessionCompat}.
*
*
* <h2 id="CompatibilityController">Backward Compatibility with Legacy Controller APIs</h2>
* <h2 id="CompatibilityController">Backward Compatibility with Legacy Controller APIs</h2>
*
*
...
@@ -212,10 +215,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -212,10 +215,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* {@linkplain MediaControllerCompat AndroidX controller compat}. However, {@link ControllerInfo}
* {@linkplain MediaControllerCompat AndroidX controller compat}. However, {@link ControllerInfo}
* may not be precise for legacy controllers. See {@link ControllerInfo} for the details.
* may not be precise for legacy controllers. See {@link ControllerInfo} for the details.
*
*
* <p>
Unknown package name nor UID doesn't mean that you should disallow connection nor commands.
* <p>
Neither an unknown package name nor an unknown UID mean that you should disallow a connection
*
For SDK levels where such issues happen, session tokens could only be obtained by trust
ed
*
or commands per se. For SDK levels where such issues happen, session tokens can only be obtain
ed
*
controllers (e.g. Bluetooth, Auto, ...), so it may be better for you to allow them as you did
*
by trusted controllers (e.g. Bluetooth, Auto, ...). This means only trusted controllers can
* with legacy sessions.
*
connect and an app can accept such controllers in the same way as
with legacy sessions.
*/
*/
public
class
MediaSession
{
public
class
MediaSession
{
...
@@ -243,7 +246,7 @@ public class MediaSession {
...
@@ -243,7 +246,7 @@ public class MediaSession {
* Creates a builder for {@link MediaSession}.
* Creates a builder for {@link MediaSession}.
*
*
* @param context The context.
* @param context The context.
* @param player The underlying player to perform playback and handle
transport control
s.
* @param player The underlying player to perform playback and handle
player command
s.
* @throws IllegalArgumentException if {@link Player#canAdvertiseSession()} returns false.
* @throws IllegalArgumentException if {@link Player#canAdvertiseSession()} returns false.
*/
*/
public
Builder
(
Context
context
,
Player
player
)
{
public
Builder
(
Context
context
,
Player
player
)
{
...
@@ -254,13 +257,13 @@ public class MediaSession {
...
@@ -254,13 +257,13 @@ public class MediaSession {
* Sets a {@link PendingIntent} to launch an {@link android.app.Activity} for the {@link
* Sets a {@link PendingIntent} to launch an {@link android.app.Activity} for the {@link
* MediaSession}. This can be used as a quick link to an ongoing media screen.
* MediaSession}. This can be used as a quick link to an ongoing media screen.
*
*
* <p>A client can use this pending intent to start an activity belonging to this session.
Whe
n
* <p>A client can use this pending intent to start an activity belonging to this session.
O
n
*
this pending intent is for instance included in the notification
{@linkplain
*
API levels below 33 the pending intent can be used
{@linkplain
* NotificationCompat.Builder#setContentIntent(PendingIntent) as the content intent}
, t
apping
* NotificationCompat.Builder#setContentIntent(PendingIntent) as the content intent}
. T
apping
* the notification will
open this activity.
* the notification will
then send that pending intent and open the activity (see <a
*
*
href="https://developer.android.com/training/notify-user/navigation">'Start an Activity from
*
<p>See <a href="https://developer.android.com/training/notify-user/navigation">'Start an
*
a Notification'</a>). For API levels starting with 33, the media notification reads the
*
Activity from a Notification'</a> also
.
*
pending intent directly from the session
.
*
*
* @param pendingIntent The pending intent.
* @param pendingIntent The pending intent.
* @return The builder to allow chaining.
* @return The builder to allow chaining.
...
@@ -291,6 +294,13 @@ public class MediaSession {
...
@@ -291,6 +294,13 @@ public class MediaSession {
* Sets a callback for the {@link MediaSession} to handle incoming requests from {link
* Sets a callback for the {@link MediaSession} to handle incoming requests from {link
* MediaController}.
* MediaController}.
*
*
* <p>Apps that want to allow controllers to {@linkplain MediaController#setMediaItems(List)
* set} or {@linkplain MediaController#addMediaItems(List) add} media items to the playlist,
* must use a callback and override its {@link
* MediaSession.Callback#onSetMediaItems(MediaSession, ControllerInfo, List, int, long)} or
* {@link MediaSession.Callback#onSetMediaItems(MediaSession, ControllerInfo, List, int, long)}
* methods.
*
* @param callback The callback.
* @param callback The callback.
* @return The builder to allow chaining.
* @return The builder to allow chaining.
*/
*/
...
@@ -372,7 +382,8 @@ public class MediaSession {
...
@@ -372,7 +382,8 @@ public class MediaSession {
* @param remoteUserInfo The remote user info.
* @param remoteUserInfo The remote user info.
* @param trusted {@code true} if trusted, {@code false} otherwise.
* @param trusted {@code true} if trusted, {@code false} otherwise.
* @param cb ControllerCb. Can be {@code null} only when a MediaBrowserCompat connects to
* @param cb ControllerCb. Can be {@code null} only when a MediaBrowserCompat connects to
* MediaSessionService and ControllerInfo is needed for {@code SessionCallback#onConnect()}.
* MediaSessionService and ControllerInfo is needed for {@link
* MediaSession.Callback#onConnect(MediaSession, ControllerInfo)}.
* @param connectionHints A session-specific argument sent from the controller for the
* @param connectionHints A session-specific argument sent from the controller for the
* connection. The contents of this bundle may affect the connection result.
* connection. The contents of this bundle may affect the connection result.
*/
*/
...
...
libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java
View file @
6042bec1
...
@@ -448,7 +448,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
...
@@ -448,7 +448,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
public
MediaSession
.
ConnectionResult
onConnectOnHandler
(
ControllerInfo
controller
)
{
public
MediaSession
.
ConnectionResult
onConnectOnHandler
(
ControllerInfo
controller
)
{
return
checkNotNull
(
return
checkNotNull
(
callback
.
onConnect
(
instance
,
controller
),
"onConn
tex
t must return non-null future"
);
callback
.
onConnect
(
instance
,
controller
),
"onConn
ec
t must return non-null future"
);
}
}
public
void
onPostConnectOnHandler
(
ControllerInfo
controller
)
{
public
void
onPostConnectOnHandler
(
ControllerInfo
controller
)
{
...
...
libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java
View file @
6042bec1
...
@@ -57,26 +57,27 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -57,26 +57,27 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
/**
* Superclass to be extended by services hosting {@link MediaSession media sessions}.
* Superclass to be extended by services hosting {@link MediaSession media sessions}.
*
*
* <p>It's highly recommended for an app to use this class if
they want to keep media playback in
* <p>It's highly recommended for an app to use this class if
media playback should continue while
*
the background. The service allows other apps to know that your app supports {@link MediaSession}
*
in the background. The service allows other apps to know that your app supports {@link
*
even when your app isn't running. For example, a user voice command may start your app to play
*
MediaSession} even when your app isn't running. This way, a user voice command may be able start
* media.
*
your app to play
media.
*
*
* <p>To extend this class, declare the intent filter in your {@code AndroidManifest.xml}:
* <p>To extend this class, declare the intent filter in your {@code AndroidManifest.xml}:
*
*
* <pre>{@code
* <pre>{@code
* <service
* <service
* android:name="NameOfYourService"
* android:name="NameOfYourService"
* android:foregroundServiceType="mediaPlayback">
* android:foregroundServiceType="mediaPlayback"
* android:exported="true">
* <intent-filter>
* <intent-filter>
* <action android:name="androidx.media3.session.MediaSessionService"/>
* <action android:name="androidx.media3.session.MediaSessionService"/>
* </intent-filter>
* </intent-filter>
* </service>
* </service>
* }</pre>
* }</pre>
*
*
* <p>You may also declare
{@code android.media.browse.MediaBrowserService} for compatibility with
* <p>You may also declare
the action {@code android.media.browse.MediaBrowserService} for
*
{@link android.support.v4.media.MediaBrowserCompat}. This service can handle the cas
e
*
compatibility with {@link android.support.v4.media.MediaBrowserCompat}. This service can handl
e
* automatically.
*
the case
automatically.
*
*
* <p>It's recommended for an app to have a single service declared in the manifest. Otherwise, your
* <p>It's recommended for an app to have a single service declared in the manifest. Otherwise, your
* app might be shown twice in the list of the controller apps, or another app might fail to pick
* app might be shown twice in the list of the controller apps, or another app might fail to pick
...
@@ -93,10 +94,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -93,10 +94,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* <h2 id="ServiceLifecycle">Service Lifecycle</h2>
* <h2 id="ServiceLifecycle">Service Lifecycle</h2>
*
*
* <p>A media session service is a bound service and its <a
* <p>A media session service is a bound service and its <a
* href="https://developer.android.com/guide/topics/manifest/service-element#foregroundservicetype">
foreground
* href="https://developer.android.com/guide/topics/manifest/service-element#foregroundservicetype">
*
service type</a> must include <em>mediaPlayback</em>. When a {@link MediaController} is created
*
foreground service type</a> must include <em>mediaPlayback</em>. When a {@link MediaController}
*
for the service, the controller binds to the service. {@link #onGetSession(ControllerInfo)} will
*
is created for the service, the controller binds to the service. {@link
* be called from {@link #onBind(Intent)}.
*
#onGetSession(ControllerInfo)} will
be called from {@link #onBind(Intent)}.
*
*
* <p>After binding, the session's {@link MediaSession.Callback#onConnect(MediaSession,
* <p>After binding, the session's {@link MediaSession.Callback#onConnect(MediaSession,
* MediaSession.ControllerInfo)} will be called to accept or reject the connection request from the
* MediaSession.ControllerInfo)} will be called to accept or reject the connection request from the
...
@@ -115,8 +116,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...
@@ -115,8 +116,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* #onUpdateNotification(MediaSession)}. In this case, you must also start or stop the service from
* #onUpdateNotification(MediaSession)}. In this case, you must also start or stop the service from
* the foreground, when playback starts or stops respectively.
* the foreground, when playback starts or stops respectively.
*
*
* <p>The service will be destroyed when all sessions are
closed, or no controller is binding to the
* <p>The service will be destroyed when all sessions are
{@linkplain MediaController#release()
* service while the service is in the background.
*
released}, or no controller is binding to the
service while the service is in the background.
*
*
* <h2 id="MultipleSessions">Supporting Multiple Sessions</h2>
* <h2 id="MultipleSessions">Supporting Multiple Sessions</h2>
*
*
...
@@ -247,7 +248,8 @@ public abstract class MediaSessionService extends Service {
...
@@ -247,7 +248,8 @@ public abstract class MediaSessionService extends Service {
* Adds a {@link MediaSession} to this service. This is not necessary for most media apps. See <a
* Adds a {@link MediaSession} to this service. This is not necessary for most media apps. See <a
* href="#MultipleSessions">Supporting Multiple Sessions</a> for details.
* href="#MultipleSessions">Supporting Multiple Sessions</a> for details.
*
*
* <p>The added session will be removed automatically when it's closed.
* <p>The added session will be removed automatically {@linkplain MediaSession#release() when the
* session is released}.
*
*
* @param session A session to be added.
* @param session A session to be added.
* @see #removeSession(MediaSession)
* @see #removeSession(MediaSession)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment