234 lines
9.3 KiB
Java
234 lines
9.3 KiB
Java
/*
|
|
* 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 android.media;
|
|
|
|
import android.annotation.CallSuper;
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.app.Notification;
|
|
import android.app.Service;
|
|
import android.content.Intent;
|
|
import android.media.MediaSession2.ControllerInfo;
|
|
import android.media.update.ApiLoader;
|
|
import android.media.update.MediaSessionService2Provider;
|
|
import android.media.update.MediaSessionService2Provider.MediaNotificationProvider;
|
|
import android.os.IBinder;
|
|
|
|
/**
|
|
* @hide
|
|
* Base class for media session services, which is the service version of the {@link MediaSession2}.
|
|
* <p>
|
|
* It's highly recommended for an app to use this instead of {@link MediaSession2} if it wants
|
|
* to keep media playback in the background.
|
|
* <p>
|
|
* Here's the benefits of using {@link MediaSessionService2} instead of
|
|
* {@link MediaSession2}.
|
|
* <ul>
|
|
* <li>Another app can know that your app supports {@link MediaSession2} even when your app
|
|
* isn't running.
|
|
* <li>Another app can start playback of your app even when your app isn't running.
|
|
* </ul>
|
|
* For example, user's voice command can start playback of your app even when it's not running.
|
|
* <p>
|
|
* To extend this class, adding followings directly to your {@code AndroidManifest.xml}.
|
|
* <pre>
|
|
* <service android:name="component_name_of_your_implementation" >
|
|
* <intent-filter>
|
|
* <action android:name="android.media.MediaSessionService2" />
|
|
* </intent-filter>
|
|
* </service></pre>
|
|
* <p>
|
|
* A {@link MediaSessionService2} is another form of {@link MediaSession2}. IDs shouldn't
|
|
* be shared between the {@link MediaSessionService2} and {@link MediaSession2}. By
|
|
* default, an empty string will be used for ID of the service. If you want to specify an ID,
|
|
* declare metadata in the manifest as follows.
|
|
* <pre>
|
|
* <service android:name="component_name_of_your_implementation" >
|
|
* <intent-filter>
|
|
* <action android:name="android.media.MediaSessionService2" />
|
|
* </intent-filter>
|
|
* <meta-data android:name="android.media.session"
|
|
* android:value="session_id"/>
|
|
* </service></pre>
|
|
* <p>
|
|
* It's recommended for an app to have a single {@link MediaSessionService2} declared in the
|
|
* manifest. Otherwise, your app might be shown twice in the list of the Auto/Wearable, or another
|
|
* app fails to pick the right session service when it wants to start the playback this app.
|
|
* <p>
|
|
* If there's conflicts with the session ID among the services, services wouldn't be available for
|
|
* any controllers.
|
|
* <p>
|
|
* Topic covered here:
|
|
* <ol>
|
|
* <li><a href="#ServiceLifecycle">Service Lifecycle</a>
|
|
* <li><a href="#Permissions">Permissions</a>
|
|
* </ol>
|
|
* <div class="special reference">
|
|
* <a name="ServiceLifecycle"></a>
|
|
* <h3>Service Lifecycle</h3>
|
|
* <p>
|
|
* Session service is bounded service. When a {@link MediaController2} is created for the
|
|
* session service, the controller binds to the session service. {@link #onCreateSession(String)}
|
|
* may be called after the {@link #onCreate} if the service hasn't created yet.
|
|
* <p>
|
|
* After the binding, session's {@link MediaSession2.SessionCallback#onConnect(MediaSession2, ControllerInfo)}
|
|
*
|
|
* will be called to accept or reject connection request from a controller. If the connection is
|
|
* rejected, the controller will unbind. If it's accepted, the controller will be available to use
|
|
* and keep binding.
|
|
* <p>
|
|
* When playback is started for this session service, {@link #onUpdateNotification()}
|
|
* is called and service would become a foreground service. It's needed to keep playback after the
|
|
* controller is destroyed. The session service becomes background service when the playback is
|
|
* stopped.
|
|
* <a name="Permissions"></a>
|
|
* <h3>Permissions</h3>
|
|
* <p>
|
|
* Any app can bind to the session service with controller, but the controller can be used only if
|
|
* the session service accepted the connection request through
|
|
* {@link MediaSession2.SessionCallback#onConnect(MediaSession2, ControllerInfo)}.
|
|
*/
|
|
public abstract class MediaSessionService2 extends Service {
|
|
private final MediaSessionService2Provider mProvider;
|
|
|
|
/**
|
|
* This is the interface name that a service implementing a session service should say that it
|
|
* support -- that is, this is the action it uses for its intent filter.
|
|
*/
|
|
public static final String SERVICE_INTERFACE = "android.media.MediaSessionService2";
|
|
|
|
/**
|
|
* Name under which a MediaSessionService2 component publishes information about itself.
|
|
* This meta-data must provide a string value for the ID.
|
|
*/
|
|
public static final String SERVICE_META_DATA = "android.media.session";
|
|
|
|
public MediaSessionService2() {
|
|
super();
|
|
mProvider = createProvider();
|
|
}
|
|
|
|
MediaSessionService2Provider createProvider() {
|
|
return ApiLoader.getProvider().createMediaSessionService2(this);
|
|
}
|
|
|
|
/**
|
|
* Default implementation for {@link MediaSessionService2} to initialize session service.
|
|
* <p>
|
|
* Override this method if you need your own initialization. Derived classes MUST call through
|
|
* to the super class's implementation of this method.
|
|
*/
|
|
@CallSuper
|
|
@Override
|
|
public void onCreate() {
|
|
super.onCreate();
|
|
mProvider.onCreate_impl();
|
|
}
|
|
|
|
/**
|
|
* Called when another app requested to start this service to get {@link MediaSession2}.
|
|
* <p>
|
|
* Session service will accept or reject the connection with the
|
|
* {@link MediaSession2.SessionCallback} in the created session.
|
|
* <p>
|
|
* Service wouldn't run if {@code null} is returned or session's ID doesn't match with the
|
|
* expected ID that you've specified through the AndroidManifest.xml.
|
|
* <p>
|
|
* This method will be called on the main thread.
|
|
*
|
|
* @param sessionId session id written in the AndroidManifest.xml.
|
|
* @return a new session
|
|
* @see MediaSession2.Builder
|
|
* @see #getSession()
|
|
*/
|
|
public @NonNull abstract MediaSession2 onCreateSession(String sessionId);
|
|
|
|
/**
|
|
* Called when the playback state of this session is changed so notification needs update.
|
|
* Override this method to show or cancel your own notification UI.
|
|
* <p>
|
|
* With the notification returned here, the service become foreground service when the playback
|
|
* is started. It becomes background service after the playback is stopped.
|
|
*
|
|
* @return a {@link MediaNotification}. If it's {@code null}, notification wouldn't be shown.
|
|
*/
|
|
public @Nullable MediaNotification onUpdateNotification() {
|
|
return mProvider.onUpdateNotification_impl();
|
|
}
|
|
|
|
/**
|
|
* Get instance of the {@link MediaSession2} that you've previously created with the
|
|
* {@link #onCreateSession} for this service.
|
|
* <p>
|
|
* This may be {@code null} before the {@link #onCreate()} is finished.
|
|
*
|
|
* @return created session
|
|
*/
|
|
public final @Nullable MediaSession2 getSession() {
|
|
return mProvider.getSession_impl();
|
|
}
|
|
|
|
/**
|
|
* Default implementation for {@link MediaSessionService2} to handle incoming binding
|
|
* request. If the request is for getting the session, the intent will have action
|
|
* {@link #SERVICE_INTERFACE}.
|
|
* <p>
|
|
* Override this method if this service also needs to handle binder requests other than
|
|
* {@link #SERVICE_INTERFACE}. Derived classes MUST call through to the super class's
|
|
* implementation of this method.
|
|
*
|
|
* @param intent
|
|
* @return Binder
|
|
*/
|
|
@CallSuper
|
|
@Nullable
|
|
@Override
|
|
public IBinder onBind(Intent intent) {
|
|
return mProvider.onBind_impl(intent);
|
|
}
|
|
|
|
/**
|
|
* Returned by {@link #onUpdateNotification()} for making session service foreground service
|
|
* to keep playback running in the background. It's highly recommended to show media style
|
|
* notification here.
|
|
*/
|
|
public static class MediaNotification {
|
|
private final MediaNotificationProvider mProvider;
|
|
|
|
/**
|
|
* Default constructor
|
|
*
|
|
* @param notificationId notification id to be used for
|
|
* {@link android.app.NotificationManager#notify(int, Notification)}.
|
|
* @param notification a notification to make session service foreground service. Media
|
|
* style notification is recommended here.
|
|
*/
|
|
public MediaNotification(int notificationId, @NonNull Notification notification) {
|
|
mProvider = ApiLoader.getProvider().createMediaSessionService2MediaNotification(
|
|
this, notificationId, notification);
|
|
}
|
|
|
|
public int getNotificationId() {
|
|
return mProvider.getNotificationId_impl();
|
|
}
|
|
|
|
public @NonNull Notification getNotification() {
|
|
return mProvider.getNotification_impl();
|
|
}
|
|
}
|
|
}
|