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 com.android.media; 18 19 import static android.content.Context.NOTIFICATION_SERVICE; 20 21 import android.app.Notification; 22 import android.app.NotificationManager; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.media.MediaPlayerBase; 26 import android.media.MediaPlayerBase.PlayerEventCallback; 27 import android.media.MediaSession2; 28 import android.media.MediaSessionService2; 29 import android.media.MediaSessionService2.MediaNotification; 30 import android.media.SessionToken2; 31 import android.media.SessionToken2.TokenType; 32 import android.media.update.MediaSessionService2Provider; 33 import android.os.IBinder; 34 import android.support.annotation.GuardedBy; 35 import android.util.Log; 36 37 // TODO(jaewan): Need a test for session service itself. 38 public class MediaSessionService2Impl implements MediaSessionService2Provider { 39 40 private static final String TAG = "MPSessionService"; // to meet 23 char limit in Log tag 41 private static final boolean DEBUG = true; // TODO(jaewan): Change this. (b/74094611) 42 43 private final MediaSessionService2 mInstance; 44 private final PlayerEventCallback mCallback = new SessionServiceEventCallback(); 45 46 private final Object mLock = new Object(); 47 @GuardedBy("mLock") 48 private NotificationManager mNotificationManager; 49 @GuardedBy("mLock") 50 private Intent mStartSelfIntent; 51 52 private boolean mIsRunningForeground; 53 private MediaSession2 mSession; 54 MediaSessionService2Impl(MediaSessionService2 instance)55 public MediaSessionService2Impl(MediaSessionService2 instance) { 56 if (DEBUG) { 57 Log.d(TAG, "MediaSessionService2Impl(" + instance + ")"); 58 } 59 mInstance = instance; 60 } 61 62 @Override getSession_impl()63 public MediaSession2 getSession_impl() { 64 return getSession(); 65 } 66 getSession()67 MediaSession2 getSession() { 68 synchronized (mLock) { 69 return mSession; 70 } 71 } 72 73 @Override onUpdateNotification_impl()74 public MediaNotification onUpdateNotification_impl() { 75 // Provide default notification UI later. 76 return null; 77 } 78 79 @Override onCreate_impl()80 public void onCreate_impl() { 81 mNotificationManager = (NotificationManager) mInstance.getSystemService( 82 NOTIFICATION_SERVICE); 83 mStartSelfIntent = new Intent(mInstance, mInstance.getClass()); 84 85 SessionToken2 token = new SessionToken2(mInstance, mInstance.getPackageName(), 86 mInstance.getClass().getName()); 87 if (token.getType() != getSessionType()) { 88 throw new RuntimeException("Expected session service, but was " + token.getType()); 89 } 90 mSession = mInstance.onCreateSession(token.getId()); 91 if (mSession == null || !token.getId().equals(mSession.getToken().getId())) { 92 throw new RuntimeException("Expected session with id " + token.getId() 93 + ", but got " + mSession); 94 } 95 // TODO(jaewan): Uncomment here. 96 // mSession.registerPlayerEventCallback(mCallback, mSession.getExecutor()); 97 } 98 getSessionType()99 @TokenType int getSessionType() { 100 return SessionToken2.TYPE_SESSION_SERVICE; 101 } 102 onBind_impl(Intent intent)103 public IBinder onBind_impl(Intent intent) { 104 if (MediaSessionService2.SERVICE_INTERFACE.equals(intent.getAction())) { 105 return ((MediaSession2Impl) mSession.getProvider()).getSessionStub().asBinder(); 106 } 107 return null; 108 } 109 updateNotification(int playerState)110 private void updateNotification(int playerState) { 111 MediaNotification mediaNotification = mInstance.onUpdateNotification(); 112 if (mediaNotification == null) { 113 return; 114 } 115 switch(playerState) { 116 case MediaPlayerBase.PLAYER_STATE_PLAYING: 117 if (!mIsRunningForeground) { 118 mIsRunningForeground = true; 119 mInstance.startForegroundService(mStartSelfIntent); 120 mInstance.startForeground(mediaNotification.getNotificationId(), 121 mediaNotification.getNotification()); 122 return; 123 } 124 break; 125 case MediaPlayerBase.PLAYER_STATE_IDLE: 126 case MediaPlayerBase.PLAYER_STATE_ERROR: 127 if (mIsRunningForeground) { 128 mIsRunningForeground = false; 129 mInstance.stopForeground(true); 130 return; 131 } 132 break; 133 } 134 mNotificationManager.notify(mediaNotification.getNotificationId(), 135 mediaNotification.getNotification()); 136 } 137 138 private class SessionServiceEventCallback extends PlayerEventCallback { 139 @Override onPlayerStateChanged(MediaPlayerBase player, int state)140 public void onPlayerStateChanged(MediaPlayerBase player, int state) { 141 // TODO: Implement this 142 return; 143 } 144 } 145 146 public static class MediaNotificationImpl implements MediaNotificationProvider { 147 private int mNotificationId; 148 private Notification mNotification; 149 MediaNotificationImpl(MediaNotification instance, int notificationId, Notification notification)150 public MediaNotificationImpl(MediaNotification instance, int notificationId, 151 Notification notification) { 152 if (notification == null) { 153 throw new IllegalArgumentException("notification shouldn't be null"); 154 } 155 mNotificationId = notificationId; 156 mNotification = notification; 157 } 158 159 @Override getNotificationId_impl()160 public int getNotificationId_impl() { 161 return mNotificationId; 162 } 163 164 @Override getNotification_impl()165 public Notification getNotification_impl() { 166 return mNotification; 167 } 168 } 169 } 170