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 * <service android:name="component_name_of_your_implementation" > 50 * <intent-filter> 51 * <action android:name="android.media.MediaSessionService2" /> 52 * </intent-filter> 53 * </service></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 * <service android:name="component_name_of_your_implementation" > 61 * <intent-filter> 62 * <action android:name="android.media.MediaSessionService2" /> 63 * </intent-filter> 64 * <meta-data android:name="android.media.session" 65 * android:value="session_id"/> 66 * </service></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 MediaSessionService2()120 public MediaSessionService2() { 121 super(); 122 mProvider = createProvider(); 123 } 124 createProvider()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 onCreate()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 */ onCreateSession(String sessionId)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 */ onUpdateNotification()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 */ getSession()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 onBind(Intent intent)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 */ MediaNotification(int notificationId, @NonNull Notification notification)220 public MediaNotification(int notificationId, @NonNull Notification notification) { 221 mProvider = ApiLoader.getProvider().createMediaSessionService2MediaNotification( 222 this, notificationId, notification); 223 } 224 getNotificationId()225 public int getNotificationId() { 226 return mProvider.getNotificationId_impl(); 227 } 228 getNotification()229 public @NonNull Notification getNotification() { 230 return mProvider.getNotification_impl(); 231 } 232 } 233 } 234