Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.media;
     18 
     19 import android.annotation.CallSuper;
     20 import android.annotation.NonNull;
     21 import android.annotation.Nullable;
     22 import android.app.Notification;
     23 import android.app.Service;
     24 import android.content.Intent;
     25 import android.media.MediaSession2.ControllerInfo;
     26 import android.media.update.ApiLoader;
     27 import android.media.update.MediaSessionService2Provider;
     28 import android.media.update.MediaSessionService2Provider.MediaNotificationProvider;
     29 import android.os.IBinder;
     30 
     31 /**
     32  * @hide
     33  * Base class for media session services, which is the service version of the {@link MediaSession2}.
     34  * <p>
     35  * It's highly recommended for an app to use this instead of {@link MediaSession2} if it wants
     36  * to keep media playback in the background.
     37  * <p>
     38  * Here's the benefits of using {@link MediaSessionService2} instead of
     39  * {@link MediaSession2}.
     40  * <ul>
     41  * <li>Another app can know that your app supports {@link MediaSession2} even when your app
     42  * isn't running.
     43  * <li>Another app can start playback of your app even when your app isn't running.
     44  * </ul>
     45  * For example, user's voice command can start playback of your app even when it's not running.
     46  * <p>
     47  * To extend this class, adding followings directly to your {@code AndroidManifest.xml}.
     48  * <pre>
     49  * &lt;service android:name="component_name_of_your_implementation" &gt;
     50  *   &lt;intent-filter&gt;
     51  *     &lt;action android:name="android.media.MediaSessionService2" /&gt;
     52  *   &lt;/intent-filter&gt;
     53  * &lt;/service&gt;</pre>
     54  * <p>
     55  * A {@link MediaSessionService2} is another form of {@link MediaSession2}. IDs shouldn't
     56  * be shared between the {@link MediaSessionService2} and {@link MediaSession2}. By
     57  * default, an empty string will be used for ID of the service. If you want to specify an ID,
     58  * declare metadata in the manifest as follows.
     59  * <pre>
     60  * &lt;service android:name="component_name_of_your_implementation" &gt;
     61  *   &lt;intent-filter&gt;
     62  *     &lt;action android:name="android.media.MediaSessionService2" /&gt;
     63  *   &lt;/intent-filter&gt;
     64  *   &lt;meta-data android:name="android.media.session"
     65  *       android:value="session_id"/&gt;
     66  * &lt;/service&gt;</pre>
     67  * <p>
     68  * It's recommended for an app to have a single {@link MediaSessionService2} declared in the
     69  * manifest. Otherwise, your app might be shown twice in the list of the Auto/Wearable, or another
     70  * app fails to pick the right session service when it wants to start the playback this app.
     71  * <p>
     72  * If there's conflicts with the session ID among the services, services wouldn't be available for
     73  * any controllers.
     74  * <p>
     75  * Topic covered here:
     76  * <ol>
     77  * <li><a href="#ServiceLifecycle">Service Lifecycle</a>
     78  * <li><a href="#Permissions">Permissions</a>
     79  * </ol>
     80  * <div class="special reference">
     81  * <a name="ServiceLifecycle"></a>
     82  * <h3>Service Lifecycle</h3>
     83  * <p>
     84  * Session service is bounded service. When a {@link MediaController2} is created for the
     85  * session service, the controller binds to the session service. {@link #onCreateSession(String)}
     86  * may be called after the {@link #onCreate} if the service hasn't created yet.
     87  * <p>
     88  * After the binding, session's {@link MediaSession2.SessionCallback#onConnect(MediaSession2, ControllerInfo)}
     89  *
     90  * will be called to accept or reject connection request from a controller. If the connection is
     91  * rejected, the controller will unbind. If it's accepted, the controller will be available to use
     92  * and keep binding.
     93  * <p>
     94  * When playback is started for this session service, {@link #onUpdateNotification()}
     95  * is called and service would become a foreground service. It's needed to keep playback after the
     96  * controller is destroyed. The session service becomes background service when the playback is
     97  * stopped.
     98  * <a name="Permissions"></a>
     99  * <h3>Permissions</h3>
    100  * <p>
    101  * Any app can bind to the session service with controller, but the controller can be used only if
    102  * the session service accepted the connection request through
    103  * {@link MediaSession2.SessionCallback#onConnect(MediaSession2, ControllerInfo)}.
    104  */
    105 public abstract class MediaSessionService2 extends Service {
    106     private final MediaSessionService2Provider mProvider;
    107 
    108     /**
    109      * This is the interface name that a service implementing a session service should say that it
    110      * support -- that is, this is the action it uses for its intent filter.
    111      */
    112     public static final String SERVICE_INTERFACE = "android.media.MediaSessionService2";
    113 
    114     /**
    115      * Name under which a MediaSessionService2 component publishes information about itself.
    116      * This meta-data must provide a string value for the ID.
    117      */
    118     public static final String SERVICE_META_DATA = "android.media.session";
    119 
    120     public MediaSessionService2() {
    121         super();
    122         mProvider = createProvider();
    123     }
    124 
    125     MediaSessionService2Provider createProvider() {
    126         return ApiLoader.getProvider().createMediaSessionService2(this);
    127     }
    128 
    129     /**
    130      * Default implementation for {@link MediaSessionService2} to initialize session service.
    131      * <p>
    132      * Override this method if you need your own initialization. Derived classes MUST call through
    133      * to the super class's implementation of this method.
    134      */
    135     @CallSuper
    136     @Override
    137     public void onCreate() {
    138         super.onCreate();
    139         mProvider.onCreate_impl();
    140     }
    141 
    142     /**
    143      * Called when another app requested to start this service to get {@link MediaSession2}.
    144      * <p>
    145      * Session service will accept or reject the connection with the
    146      * {@link MediaSession2.SessionCallback} in the created session.
    147      * <p>
    148      * Service wouldn't run if {@code null} is returned or session's ID doesn't match with the
    149      * expected ID that you've specified through the AndroidManifest.xml.
    150      * <p>
    151      * This method will be called on the main thread.
    152      *
    153      * @param sessionId session id written in the AndroidManifest.xml.
    154      * @return a new session
    155      * @see MediaSession2.Builder
    156      * @see #getSession()
    157      */
    158     public @NonNull abstract MediaSession2 onCreateSession(String sessionId);
    159 
    160     /**
    161      * Called when the playback state of this session is changed so notification needs update.
    162      * Override this method to show or cancel your own notification UI.
    163      * <p>
    164      * With the notification returned here, the service become foreground service when the playback
    165      * is started. It becomes background service after the playback is stopped.
    166      *
    167      * @return a {@link MediaNotification}. If it's {@code null}, notification wouldn't be shown.
    168      */
    169     public @Nullable MediaNotification onUpdateNotification() {
    170         return mProvider.onUpdateNotification_impl();
    171     }
    172 
    173     /**
    174      * Get instance of the {@link MediaSession2} that you've previously created with the
    175      * {@link #onCreateSession} for this service.
    176      * <p>
    177      * This may be {@code null} before the {@link #onCreate()} is finished.
    178      *
    179      * @return created session
    180      */
    181     public final @Nullable MediaSession2 getSession() {
    182         return mProvider.getSession_impl();
    183     }
    184 
    185     /**
    186      * Default implementation for {@link MediaSessionService2} to handle incoming binding
    187      * request. If the request is for getting the session, the intent will have action
    188      * {@link #SERVICE_INTERFACE}.
    189      * <p>
    190      * Override this method if this service also needs to handle binder requests other than
    191      * {@link #SERVICE_INTERFACE}. Derived classes MUST call through to the super class's
    192      * implementation of this method.
    193      *
    194      * @param intent
    195      * @return Binder
    196      */
    197     @CallSuper
    198     @Nullable
    199     @Override
    200     public IBinder onBind(Intent intent) {
    201         return mProvider.onBind_impl(intent);
    202     }
    203 
    204     /**
    205      * Returned by {@link #onUpdateNotification()} for making session service foreground service
    206      * to keep playback running in the background. It's highly recommended to show media style
    207      * notification here.
    208      */
    209     public static class MediaNotification {
    210         private final MediaNotificationProvider mProvider;
    211 
    212         /**
    213          * Default constructor
    214          *
    215          * @param notificationId notification id to be used for
    216          *      {@link android.app.NotificationManager#notify(int, Notification)}.
    217          * @param notification a notification to make session service foreground service. Media
    218          *      style notification is recommended here.
    219          */
    220         public MediaNotification(int notificationId, @NonNull Notification notification) {
    221             mProvider = ApiLoader.getProvider().createMediaSessionService2MediaNotification(
    222                     this, notificationId, notification);
    223         }
    224 
    225         public int getNotificationId() {
    226             return mProvider.getNotificationId_impl();
    227         }
    228 
    229         public @NonNull Notification getNotification() {
    230             return mProvider.getNotification_impl();
    231         }
    232     }
    233 }
    234