1 /* 2 * Copyright 2023 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.bluetooth.audio_util; 18 19 import android.support.v4.media.session.MediaControllerCompat; 20 import android.support.v4.media.session.MediaSessionCompat; 21 import android.support.v4.media.session.PlaybackStateCompat; 22 23 import com.android.bluetooth.avrcp.AvrcpTargetService; 24 25 /** 26 * Manager class for player apps. 27 */ 28 public class PlayerSettingsManager { 29 private static final String TAG = "PlayerSettingsManager"; 30 31 private final MediaPlayerList mMediaPlayerList; 32 private final AvrcpTargetService mService; 33 34 private MediaControllerCompat mActivePlayerController; 35 private final MediaControllerCallback mControllerCallback; 36 37 /** 38 * Instantiates a new PlayerSettingsManager. 39 * 40 * @param mediaPlayerList is used to retrieve the current active player. 41 */ PlayerSettingsManager(MediaPlayerList mediaPlayerList, AvrcpTargetService service)42 public PlayerSettingsManager(MediaPlayerList mediaPlayerList, AvrcpTargetService service) { 43 mService = service; 44 mMediaPlayerList = mediaPlayerList; 45 mMediaPlayerList.setPlayerSettingsCallback( 46 (mediaPlayerWrapper) -> activePlayerChanged(mediaPlayerWrapper)); 47 mControllerCallback = new MediaControllerCallback(); 48 49 MediaPlayerWrapper wrapper = mMediaPlayerList.getActivePlayer(); 50 if (wrapper != null) { 51 mActivePlayerController = new MediaControllerCompat(mService, 52 MediaSessionCompat.Token.fromToken(wrapper.getSessionToken())); 53 mActivePlayerController.registerCallback(mControllerCallback); 54 } else { 55 mActivePlayerController = null; 56 } 57 } 58 59 /** 60 * Unregister callbacks 61 */ cleanup()62 public void cleanup() { 63 updateRemoteDevice(); 64 if (mActivePlayerController != null) { 65 mActivePlayerController.unregisterCallback(mControllerCallback); 66 } 67 } 68 69 /** 70 * Updates the active player controller. 71 */ activePlayerChanged(MediaPlayerWrapper mediaPlayerWrapper)72 private void activePlayerChanged(MediaPlayerWrapper mediaPlayerWrapper) { 73 if (mActivePlayerController != null) { 74 mActivePlayerController.unregisterCallback(mControllerCallback); 75 } 76 if (mediaPlayerWrapper != null) { 77 mActivePlayerController = new MediaControllerCompat(mService, 78 MediaSessionCompat.Token.fromToken(mediaPlayerWrapper.getSessionToken())); 79 mActivePlayerController.registerCallback(mControllerCallback); 80 } else { 81 mActivePlayerController = null; 82 updateRemoteDevice(); 83 } 84 } 85 86 /** 87 * Sends the MediaController values of the active player to the remote device. 88 * 89 * This is called when: 90 * - The class is created and the session is ready 91 * - The class is destroyed 92 * - The active player changed and the session is ready 93 * - The last active player has been removed 94 * - The repeat / shuffle player state changed 95 */ updateRemoteDevice()96 private void updateRemoteDevice() { 97 mService.sendPlayerSettings(getPlayerRepeatMode(), getPlayerShuffleMode()); 98 } 99 100 /** 101 * Called from remote device to set the active player repeat mode. 102 */ setPlayerRepeatMode(int repeatMode)103 public boolean setPlayerRepeatMode(int repeatMode) { 104 if (mActivePlayerController == null) { 105 return false; 106 } 107 MediaControllerCompat.TransportControls controls = 108 mActivePlayerController.getTransportControls(); 109 switch (repeatMode) { 110 case PlayerSettingsValues.STATE_REPEAT_OFF: 111 controls.setRepeatMode(PlaybackStateCompat.REPEAT_MODE_NONE); 112 return true; 113 case PlayerSettingsValues.STATE_REPEAT_SINGLE_TRACK: 114 controls.setRepeatMode(PlaybackStateCompat.REPEAT_MODE_ONE); 115 return true; 116 case PlayerSettingsValues.STATE_REPEAT_GROUP: 117 controls.setRepeatMode(PlaybackStateCompat.REPEAT_MODE_GROUP); 118 return true; 119 case PlayerSettingsValues.STATE_REPEAT_ALL_TRACK: 120 controls.setRepeatMode(PlaybackStateCompat.REPEAT_MODE_ALL); 121 return true; 122 default: 123 controls.setRepeatMode(PlaybackStateCompat.REPEAT_MODE_NONE); 124 return false; 125 } 126 } 127 128 /** 129 * Called from remote device to set the active player shuffle mode. 130 */ setPlayerShuffleMode(int shuffleMode)131 public boolean setPlayerShuffleMode(int shuffleMode) { 132 if (mActivePlayerController == null) { 133 return false; 134 } 135 MediaControllerCompat.TransportControls controls = 136 mActivePlayerController.getTransportControls(); 137 switch (shuffleMode) { 138 case PlayerSettingsValues.STATE_SHUFFLE_OFF: 139 controls.setShuffleMode(PlaybackStateCompat.SHUFFLE_MODE_NONE); 140 return true; 141 case PlayerSettingsValues.STATE_SHUFFLE_GROUP: 142 controls.setShuffleMode(PlaybackStateCompat.SHUFFLE_MODE_GROUP); 143 return true; 144 case PlayerSettingsValues.STATE_SHUFFLE_ALL_TRACK: 145 controls.setShuffleMode(PlaybackStateCompat.SHUFFLE_MODE_ALL); 146 return true; 147 default: 148 controls.setShuffleMode(PlaybackStateCompat.SHUFFLE_MODE_NONE); 149 return false; 150 } 151 } 152 153 /** 154 * Retrieves & converts the repeat value of the active player MediaController to AVRCP values 155 */ getPlayerRepeatMode()156 public int getPlayerRepeatMode() { 157 if (mActivePlayerController == null) { 158 return PlayerSettingsValues.STATE_REPEAT_OFF; 159 } 160 int mediaFwkMode = mActivePlayerController.getRepeatMode(); 161 switch (mediaFwkMode) { 162 case PlaybackStateCompat.REPEAT_MODE_NONE: 163 return PlayerSettingsValues.STATE_REPEAT_OFF; 164 case PlaybackStateCompat.REPEAT_MODE_ONE: 165 return PlayerSettingsValues.STATE_REPEAT_SINGLE_TRACK; 166 case PlaybackStateCompat.REPEAT_MODE_GROUP: 167 return PlayerSettingsValues.STATE_REPEAT_GROUP; 168 case PlaybackStateCompat.REPEAT_MODE_ALL: 169 return PlayerSettingsValues.STATE_REPEAT_ALL_TRACK; 170 case PlaybackStateCompat.REPEAT_MODE_INVALID: 171 return PlayerSettingsValues.STATE_REPEAT_OFF; 172 default: 173 return PlayerSettingsValues.STATE_REPEAT_OFF; 174 } 175 } 176 177 /** 178 * Retrieves & converts the shuffle value of the active player MediaController to AVRCP values 179 */ getPlayerShuffleMode()180 public int getPlayerShuffleMode() { 181 if (mActivePlayerController == null) { 182 return PlayerSettingsValues.STATE_SHUFFLE_OFF; 183 } 184 int mediaFwkMode = mActivePlayerController.getShuffleMode(); 185 switch (mediaFwkMode) { 186 case PlaybackStateCompat.SHUFFLE_MODE_NONE: 187 return PlayerSettingsValues.STATE_SHUFFLE_OFF; 188 case PlaybackStateCompat.SHUFFLE_MODE_GROUP: 189 return PlayerSettingsValues.STATE_SHUFFLE_GROUP; 190 case PlaybackStateCompat.SHUFFLE_MODE_ALL: 191 return PlayerSettingsValues.STATE_SHUFFLE_ALL_TRACK; 192 case PlaybackStateCompat.SHUFFLE_MODE_INVALID: 193 return PlayerSettingsValues.STATE_SHUFFLE_OFF; 194 default: 195 return PlayerSettingsValues.STATE_SHUFFLE_OFF; 196 } 197 } 198 199 // Receives callbacks from the MediaControllerCompat. 200 private class MediaControllerCallback extends MediaControllerCompat.Callback { 201 @Override onRepeatModeChanged(final int repeatMode)202 public void onRepeatModeChanged(final int repeatMode) { 203 updateRemoteDevice(); 204 } 205 206 @Override onSessionReady()207 public void onSessionReady() { 208 updateRemoteDevice(); 209 } 210 211 @Override onShuffleModeChanged(final int shuffleMode)212 public void onShuffleModeChanged(final int shuffleMode) { 213 updateRemoteDevice(); 214 } 215 } 216 217 /** 218 * Class containing all the Shuffle/Repeat values as defined in the BT spec. 219 */ 220 public static final class PlayerSettingsValues { 221 /** 222 * Repeat setting, as defined by Bluetooth specification. 223 */ 224 public static final int SETTING_REPEAT = 2; 225 226 /** 227 * Shuffle setting, as defined by Bluetooth specification. 228 */ 229 public static final int SETTING_SHUFFLE = 3; 230 231 /** 232 * Repeat OFF state, as defined by Bluetooth specification. 233 */ 234 public static final int STATE_REPEAT_OFF = 1; 235 236 /** 237 * Single track repeat, as defined by Bluetooth specification. 238 */ 239 public static final int STATE_REPEAT_SINGLE_TRACK = 2; 240 241 /** 242 * All track repeat, as defined by Bluetooth specification. 243 */ 244 public static final int STATE_REPEAT_ALL_TRACK = 3; 245 246 /** 247 * Group repeat, as defined by Bluetooth specification. 248 */ 249 public static final int STATE_REPEAT_GROUP = 4; 250 251 /** 252 * Shuffle OFF state, as defined by Bluetooth specification. 253 */ 254 public static final int STATE_SHUFFLE_OFF = 1; 255 256 /** 257 * All track shuffle, as defined by Bluetooth specification. 258 */ 259 public static final int STATE_SHUFFLE_ALL_TRACK = 2; 260 261 /** 262 * Group shuffle, as defined by Bluetooth specification. 263 */ 264 public static final int STATE_SHUFFLE_GROUP = 3; 265 266 /** 267 * Default state off. 268 */ 269 public static final int STATE_DEFAULT_OFF = 1; 270 } 271 } 272