1 /* 2 * Copyright (C) 2016 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.avrcp; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.bluetooth.BluetoothA2dp; 22 import android.bluetooth.BluetoothAvrcp; 23 import android.bluetooth.BluetoothDevice; 24 import android.content.BroadcastReceiver; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.pm.ApplicationInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.PackageManager.NameNotFoundException; 32 import android.content.pm.ResolveInfo; 33 import android.content.res.Resources; 34 import android.content.SharedPreferences; 35 import android.media.AudioManager; 36 import android.media.MediaDescription; 37 import android.media.MediaMetadata; 38 import android.media.browse.MediaBrowser; 39 import android.media.session.MediaSession; 40 import android.media.session.MediaSession.QueueItem; 41 import android.media.session.MediaSessionManager; 42 import android.media.session.PlaybackState; 43 import android.os.Bundle; 44 import android.os.Handler; 45 import android.os.HandlerThread; 46 import android.os.Looper; 47 import android.os.Message; 48 import android.os.SystemClock; 49 import android.os.UserManager; 50 import android.util.Log; 51 import android.view.KeyEvent; 52 53 import com.android.bluetooth.btservice.ProfileService; 54 import com.android.bluetooth.R; 55 import com.android.bluetooth.Utils; 56 57 import java.util.ArrayList; 58 import java.util.Collections; 59 import java.util.HashMap; 60 import java.util.Iterator; 61 import java.util.List; 62 import java.util.Map; 63 import java.util.SortedMap; 64 import java.util.TreeMap; 65 66 /****************************************************************************** 67 * support Bluetooth AVRCP profile. support metadata, play status, event 68 * notifications, address player selection and browse feature implementation. 69 ******************************************************************************/ 70 71 public final class Avrcp { 72 private static final boolean DEBUG = true; 73 private static final String TAG = "Avrcp"; 74 private static final String ABSOLUTE_VOLUME_BLACKLIST = "absolute_volume_blacklist"; 75 76 private Context mContext; 77 private final AudioManager mAudioManager; 78 private AvrcpMessageHandler mHandler; 79 private MediaSessionManager mMediaSessionManager; 80 private @Nullable MediaController mMediaController; 81 private MediaControllerListener mMediaControllerCb; 82 private MediaAttributes mMediaAttributes; 83 private long mLastQueueId; 84 private PackageManager mPackageManager; 85 private int mTransportControlFlags; 86 private @NonNull PlaybackState mCurrentPlayState; 87 private int mA2dpState; 88 private int mPlayStatusChangedNT; 89 private int mReportedPlayStatus; 90 private int mTrackChangedNT; 91 private int mPlayPosChangedNT; 92 private int mAddrPlayerChangedNT; 93 private int mReportedPlayerID; 94 private long mPlaybackIntervalMs; 95 private long mLastReportedPosition; 96 private long mNextPosMs; 97 private long mPrevPosMs; 98 private int mFeatures; 99 private int mRemoteVolume; 100 private int mLastRemoteVolume; 101 private int mInitialRemoteVolume; 102 private BrowsablePlayerListBuilder mBrowsableListBuilder; 103 104 /* Local volume in audio index 0-15 */ 105 private int mLocalVolume; 106 private int mLastLocalVolume; 107 private int mAbsVolThreshold; 108 109 private String mAddress; 110 private HashMap<Integer, Integer> mVolumeMapping; 111 112 private int mLastDirection; 113 private final int mVolumeStep; 114 private final int mAudioStreamMax; 115 private boolean mVolCmdAdjustInProgress; 116 private boolean mVolCmdSetInProgress; 117 private int mAbsVolRetryTimes; 118 119 private static final int NO_PLAYER_ID = 0; 120 121 private int mCurrAddrPlayerID; 122 private int mCurrBrowsePlayerID; 123 private int mLastUsedPlayerID; 124 private AvrcpMediaRsp mAvrcpMediaRsp; 125 126 /* UID counter to be shared across different files. */ 127 static short sUIDCounter = AvrcpConstants.DEFAULT_UID_COUNTER; 128 129 /* BTRC features */ 130 public static final int BTRC_FEAT_METADATA = 0x01; 131 public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02; 132 public static final int BTRC_FEAT_BROWSE = 0x04; 133 134 /* AVRC response codes, from avrc_defs */ 135 private static final int AVRC_RSP_NOT_IMPL = 8; 136 private static final int AVRC_RSP_ACCEPT = 9; 137 private static final int AVRC_RSP_REJ = 10; 138 private static final int AVRC_RSP_IN_TRANS = 11; 139 private static final int AVRC_RSP_IMPL_STBL = 12; 140 private static final int AVRC_RSP_CHANGED = 13; 141 private static final int AVRC_RSP_INTERIM = 15; 142 143 /* AVRC request commands from Native */ 144 private static final int MSG_NATIVE_REQ_GET_RC_FEATURES = 1; 145 private static final int MSG_NATIVE_REQ_GET_PLAY_STATUS = 2; 146 private static final int MSG_NATIVE_REQ_GET_ELEM_ATTRS = 3; 147 private static final int MSG_NATIVE_REQ_REGISTER_NOTIFICATION = 4; 148 private static final int MSG_NATIVE_REQ_VOLUME_CHANGE = 5; 149 private static final int MSG_NATIVE_REQ_GET_FOLDER_ITEMS = 6; 150 private static final int MSG_NATIVE_REQ_SET_ADDR_PLAYER = 7; 151 private static final int MSG_NATIVE_REQ_SET_BR_PLAYER = 8; 152 private static final int MSG_NATIVE_REQ_CHANGE_PATH = 9; 153 private static final int MSG_NATIVE_REQ_PLAY_ITEM = 10; 154 private static final int MSG_NATIVE_REQ_GET_ITEM_ATTR = 11; 155 private static final int MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS = 12; 156 private static final int MSG_NATIVE_REQ_PASS_THROUGH = 13; 157 158 /* other AVRC messages */ 159 private static final int MSG_PLAY_INTERVAL_TIMEOUT = 14; 160 private static final int MSG_ADJUST_VOLUME = 15; 161 private static final int MSG_SET_ABSOLUTE_VOLUME = 16; 162 private static final int MSG_ABS_VOL_TIMEOUT = 17; 163 private static final int MSG_SET_A2DP_AUDIO_STATE = 18; 164 private static final int MSG_NOW_PLAYING_CHANGED_RSP = 19; 165 private static final int MSG_UPDATE_MEDIA = 20; 166 167 private static final int CMD_TIMEOUT_DELAY = 2000; 168 private static final int MEDIA_DWELL_TIME = 1000; 169 private static final int MAX_ERROR_RETRY_TIMES = 6; 170 private static final int AVRCP_MAX_VOL = 127; 171 private static final int AVRCP_BASE_VOLUME_STEP = 1; 172 173 /* Communicates with MediaPlayer to fetch media content */ 174 private BrowsedMediaPlayer mBrowsedMediaPlayer; 175 176 /* Addressed player handling */ 177 private AddressedMediaPlayer mAddressedMediaPlayer; 178 179 /* List of Media player instances, useful for retrieving MediaPlayerList or MediaPlayerInfo */ 180 private SortedMap<Integer, MediaPlayerInfo> mMediaPlayerInfoList; 181 private boolean mAvailablePlayerViewChanged; 182 183 /* List of media players which supports browse */ 184 private List<BrowsePlayerInfo> mBrowsePlayerInfoList; 185 186 /* Manage browsed players */ 187 private AvrcpBrowseManager mAvrcpBrowseManager; 188 189 /* Broadcast receiver for device connections intent broadcasts */ 190 private final BroadcastReceiver mAvrcpReceiver = new AvrcpServiceBroadcastReceiver(); 191 private final BroadcastReceiver mBootReceiver = new AvrcpServiceBootReceiver(); 192 193 /* Recording passthrough key dispatches */ 194 static private final int PASSTHROUGH_LOG_MAX_SIZE = DEBUG ? 50 : 10; 195 private EvictingQueue<MediaKeyLog> mPassthroughLogs; // Passthorugh keys dispatched 196 private List<MediaKeyLog> mPassthroughPending; // Passthrough keys sent not dispatched yet 197 private int mPassthroughDispatched; // Number of keys dispatched 198 199 private class MediaKeyLog { 200 private long mTimeSent; 201 private long mTimeProcessed; 202 private String mPackage; 203 private KeyEvent mEvent; 204 205 public MediaKeyLog(long time, KeyEvent event) { 206 mEvent = event; 207 mTimeSent = time; 208 } 209 210 public boolean addDispatch(long time, KeyEvent event, String packageName) { 211 if (mPackage != null) return false; 212 if (event.getAction() != mEvent.getAction()) return false; 213 if (event.getKeyCode() != mEvent.getKeyCode()) return false; 214 mPackage = packageName; 215 mTimeProcessed = time; 216 return true; 217 } 218 219 public String toString() { 220 StringBuilder sb = new StringBuilder(); 221 sb.append(android.text.format.DateFormat.format("MM-dd HH:mm:ss", mTimeSent)); 222 sb.append(" " + mEvent.toString()); 223 if (mPackage == null) { 224 sb.append(" (undispatched)"); 225 } else { 226 sb.append(" to " + mPackage); 227 sb.append(" in " + (mTimeProcessed - mTimeSent) + "ms"); 228 } 229 return sb.toString(); 230 } 231 } 232 233 static { 234 classInitNative(); 235 } 236 237 private Avrcp(Context context) { 238 mMediaAttributes = new MediaAttributes(null); 239 mLastQueueId = MediaSession.QueueItem.UNKNOWN_ID; 240 mCurrentPlayState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build(); 241 mReportedPlayStatus = PLAYSTATUS_ERROR; 242 mA2dpState = BluetoothA2dp.STATE_NOT_PLAYING; 243 mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 244 mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 245 mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 246 mAddrPlayerChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 247 mPlaybackIntervalMs = 0L; 248 mLastReportedPosition = -1; 249 mNextPosMs = -1; 250 mPrevPosMs = -1; 251 mFeatures = 0; 252 mRemoteVolume = -1; 253 mInitialRemoteVolume = -1; 254 mLastRemoteVolume = -1; 255 mLastDirection = 0; 256 mVolCmdAdjustInProgress = false; 257 mVolCmdSetInProgress = false; 258 mAbsVolRetryTimes = 0; 259 mLocalVolume = -1; 260 mLastLocalVolume = -1; 261 mAbsVolThreshold = 0; 262 mVolumeMapping = new HashMap<Integer, Integer>(); 263 mCurrAddrPlayerID = NO_PLAYER_ID; 264 mReportedPlayerID = mCurrAddrPlayerID; 265 mCurrBrowsePlayerID = 0; 266 mContext = context; 267 mLastUsedPlayerID = 0; 268 mAddressedMediaPlayer = null; 269 270 initNative(); 271 272 mMediaSessionManager = (MediaSessionManager) context.getSystemService( 273 Context.MEDIA_SESSION_SERVICE); 274 mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 275 mAudioStreamMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); 276 mVolumeStep = Math.max(AVRCP_BASE_VOLUME_STEP, AVRCP_MAX_VOL/mAudioStreamMax); 277 278 Resources resources = context.getResources(); 279 if (resources != null) { 280 mAbsVolThreshold = resources.getInteger(R.integer.a2dp_absolute_volume_initial_threshold); 281 } 282 283 mBrowsableListBuilder = new BrowsablePlayerListBuilder(); 284 285 // Register for package removal intent broadcasts for media button receiver persistence 286 IntentFilter pkgFilter = new IntentFilter(); 287 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 288 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 289 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 290 pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); 291 pkgFilter.addDataScheme("package"); 292 context.registerReceiver(mAvrcpReceiver, pkgFilter); 293 294 IntentFilter bootFilter = new IntentFilter(); 295 bootFilter.addAction(Intent.ACTION_BOOT_COMPLETED); 296 context.registerReceiver(mBootReceiver, bootFilter); 297 } 298 299 private synchronized void start() { 300 HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler"); 301 thread.start(); 302 Looper looper = thread.getLooper(); 303 mHandler = new AvrcpMessageHandler(looper); 304 mMediaControllerCb = new MediaControllerListener(); 305 mAvrcpMediaRsp = new AvrcpMediaRsp(); 306 mMediaPlayerInfoList = new TreeMap<Integer, MediaPlayerInfo>(); 307 mAvailablePlayerViewChanged = false; 308 mBrowsePlayerInfoList = Collections.synchronizedList(new ArrayList<BrowsePlayerInfo>()); 309 mPassthroughDispatched = 0; 310 mPassthroughLogs = new EvictingQueue<MediaKeyLog>(PASSTHROUGH_LOG_MAX_SIZE); 311 mPassthroughPending = Collections.synchronizedList(new ArrayList<MediaKeyLog>()); 312 if (mMediaSessionManager != null) { 313 mMediaSessionManager.addOnActiveSessionsChangedListener(mActiveSessionListener, null, 314 mHandler); 315 mMediaSessionManager.setCallback(mButtonDispatchCallback, null); 316 } 317 mPackageManager = mContext.getApplicationContext().getPackageManager(); 318 319 /* create object to communicate with addressed player */ 320 mAddressedMediaPlayer = new AddressedMediaPlayer(mAvrcpMediaRsp); 321 322 /* initialize BrowseMananger which manages Browse commands and response */ 323 mAvrcpBrowseManager = new AvrcpBrowseManager(mContext, mAvrcpMediaRsp); 324 325 initMediaPlayersList(); 326 327 UserManager manager = UserManager.get(mContext); 328 if (manager == null || manager.isUserUnlocked()) { 329 if (DEBUG) Log.d(TAG, "User already unlocked, initializing player lists"); 330 // initialize browsable player list and build media player list 331 mBrowsableListBuilder.start(); 332 } 333 } 334 335 public static Avrcp make(Context context) { 336 if (DEBUG) Log.v(TAG, "make"); 337 Avrcp ar = new Avrcp(context); 338 ar.start(); 339 return ar; 340 } 341 342 public synchronized void doQuit() { 343 if (DEBUG) Log.d(TAG, "doQuit"); 344 if (mMediaController != null) mMediaController.unregisterCallback(mMediaControllerCb); 345 if (mMediaSessionManager != null) { 346 mMediaSessionManager.setCallback(null, null); 347 mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveSessionListener); 348 } 349 350 mHandler.removeCallbacksAndMessages(null); 351 Looper looper = mHandler.getLooper(); 352 if (looper != null) { 353 looper.quit(); 354 } 355 356 mHandler = null; 357 mContext.unregisterReceiver(mAvrcpReceiver); 358 mContext.unregisterReceiver(mBootReceiver); 359 360 mBrowsableListBuilder.cleanup(); 361 mAddressedMediaPlayer.cleanup(); 362 mAvrcpBrowseManager.cleanup(); 363 } 364 365 public void cleanup() { 366 if (DEBUG) Log.d(TAG, "cleanup"); 367 cleanupNative(); 368 if (mVolumeMapping != null) 369 mVolumeMapping.clear(); 370 } 371 372 private class MediaControllerListener extends MediaController.Callback { 373 @Override 374 public void onMetadataChanged(MediaMetadata metadata) { 375 if (DEBUG) Log.v(TAG, "onMetadataChanged"); 376 scheduleMediaUpdate(); 377 } 378 @Override 379 public synchronized void onPlaybackStateChanged(PlaybackState state) { 380 if (DEBUG) Log.v(TAG, "onPlaybackStateChanged: state " + state.toString()); 381 scheduleMediaUpdate(); 382 } 383 384 @Override 385 public void onSessionDestroyed() { 386 Log.v(TAG, "MediaController session destroyed"); 387 synchronized (Avrcp.this) { 388 if (mMediaController != null) 389 removeMediaController(mMediaController.getWrappedInstance()); 390 } 391 } 392 393 @Override 394 public void onQueueChanged(List<MediaSession.QueueItem> queue) { 395 if (queue == null) { 396 Log.v(TAG, "onQueueChanged: received null queue"); 397 return; 398 } 399 400 Log.v(TAG, "onQueueChanged: NowPlaying list changed, Queue Size = "+ queue.size()); 401 mHandler.sendEmptyMessage(MSG_NOW_PLAYING_CHANGED_RSP); 402 } 403 } 404 405 /** Handles Avrcp messages. */ 406 private final class AvrcpMessageHandler extends Handler { 407 private AvrcpMessageHandler(Looper looper) { 408 super(looper); 409 } 410 411 @Override 412 public void handleMessage(Message msg) { 413 switch (msg.what) { 414 case MSG_NATIVE_REQ_GET_RC_FEATURES: 415 { 416 String address = (String) msg.obj; 417 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_RC_FEATURES: address="+address+ 418 ", features="+msg.arg1); 419 mFeatures = msg.arg1; 420 mFeatures = modifyRcFeatureFromBlacklist(mFeatures, address); 421 mAudioManager.avrcpSupportsAbsoluteVolume(address, isAbsoluteVolumeSupported()); 422 mLastLocalVolume = -1; 423 mRemoteVolume = -1; 424 mLocalVolume = -1; 425 mInitialRemoteVolume = -1; 426 mAddress = address; 427 if (mVolumeMapping != null) 428 mVolumeMapping.clear(); 429 break; 430 } 431 432 case MSG_NATIVE_REQ_GET_PLAY_STATUS: 433 { 434 byte[] address = (byte[]) msg.obj; 435 int btstate = getBluetoothPlayState(mCurrentPlayState); 436 int length = (int) mMediaAttributes.getLength(); 437 int position = (int) getPlayPosition(); 438 if (DEBUG) 439 Log.v(TAG, "MSG_NATIVE_REQ_GET_PLAY_STATUS, responding with state " + btstate 440 + " len " + length + " pos " + position); 441 getPlayStatusRspNative(address, btstate, length, position); 442 break; 443 } 444 445 case MSG_NATIVE_REQ_GET_ELEM_ATTRS: 446 { 447 String[] textArray; 448 AvrcpCmd.ElementAttrCmd elem = (AvrcpCmd.ElementAttrCmd) msg.obj; 449 byte numAttr = elem.mNumAttr; 450 int[] attrIds = elem.mAttrIDs; 451 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_ELEM_ATTRS:numAttr=" + numAttr); 452 textArray = new String[numAttr]; 453 StringBuilder responseDebug = new StringBuilder(); 454 responseDebug.append("getElementAttr response: "); 455 for (int i = 0; i < numAttr; ++i) { 456 textArray[i] = mMediaAttributes.getString(attrIds[i]); 457 responseDebug.append("[" + attrIds[i] + "="); 458 if (attrIds[i] == AvrcpConstants.ATTRID_TITLE 459 || attrIds[i] == AvrcpConstants.ATTRID_ARTIST 460 || attrIds[i] == AvrcpConstants.ATTRID_ALBUM) { 461 responseDebug.append(Utils.ellipsize(textArray[i]) + "] "); 462 } else { 463 responseDebug.append(textArray[i] + "] "); 464 } 465 } 466 Log.v(TAG, responseDebug.toString()); 467 byte[] bdaddr = elem.mAddress; 468 getElementAttrRspNative(bdaddr, numAttr, attrIds, textArray); 469 break; 470 } 471 472 case MSG_NATIVE_REQ_REGISTER_NOTIFICATION: 473 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_REGISTER_NOTIFICATION:event=" + msg.arg1 + 474 " param=" + msg.arg2); 475 processRegisterNotification((byte[]) msg.obj, msg.arg1, msg.arg2); 476 break; 477 478 case MSG_NOW_PLAYING_CHANGED_RSP: 479 if (DEBUG) Log.v(TAG, "MSG_NOW_PLAYING_CHANGED_RSP"); 480 removeMessages(MSG_NOW_PLAYING_CHANGED_RSP); 481 mAddressedMediaPlayer.updateNowPlayingList(mMediaController); 482 break; 483 484 case MSG_PLAY_INTERVAL_TIMEOUT: 485 sendPlayPosNotificationRsp(false); 486 break; 487 488 case MSG_NATIVE_REQ_VOLUME_CHANGE: 489 if (!isAbsoluteVolumeSupported()) { 490 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_VOLUME_CHANGE ignored, not supported"); 491 break; 492 } 493 byte absVol = (byte) ((byte) msg.arg1 & 0x7f); // discard MSB as it is RFD 494 if (DEBUG) 495 Log.v(TAG, "MSG_NATIVE_REQ_VOLUME_CHANGE: volume=" + absVol + " ctype=" 496 + msg.arg2); 497 498 boolean volAdj = false; 499 if (msg.arg2 == AVRC_RSP_ACCEPT || msg.arg2 == AVRC_RSP_REJ) { 500 if (mVolCmdAdjustInProgress == false && mVolCmdSetInProgress == false) { 501 Log.e(TAG, "Unsolicited response, ignored"); 502 break; 503 } 504 removeMessages(MSG_ABS_VOL_TIMEOUT); 505 506 volAdj = mVolCmdAdjustInProgress; 507 mVolCmdAdjustInProgress = false; 508 mVolCmdSetInProgress = false; 509 mAbsVolRetryTimes = 0; 510 } 511 512 // convert remote volume to local volume 513 int volIndex = convertToAudioStreamVolume(absVol); 514 if (mInitialRemoteVolume == -1) { 515 mInitialRemoteVolume = absVol; 516 if (mAbsVolThreshold > 0 && mAbsVolThreshold < mAudioStreamMax && volIndex > mAbsVolThreshold) { 517 if (DEBUG) Log.v(TAG, "remote inital volume too high " + volIndex + ">" + mAbsVolThreshold); 518 Message msg1 = mHandler.obtainMessage(MSG_SET_ABSOLUTE_VOLUME, mAbsVolThreshold , 0); 519 mHandler.sendMessage(msg1); 520 mRemoteVolume = absVol; 521 mLocalVolume = volIndex; 522 break; 523 } 524 } 525 526 if (mLocalVolume != volIndex && (msg.arg2 == AVRC_RSP_ACCEPT || 527 msg.arg2 == AVRC_RSP_CHANGED || 528 msg.arg2 == AVRC_RSP_INTERIM)) { 529 /* If the volume has successfully changed */ 530 mLocalVolume = volIndex; 531 if (mLastLocalVolume != -1 && msg.arg2 == AVRC_RSP_ACCEPT) { 532 if (mLastLocalVolume != volIndex) { 533 /* remote volume changed more than requested due to 534 * local and remote has different volume steps */ 535 if (DEBUG) Log.d(TAG, "Remote returned volume does not match desired volume " 536 + mLastLocalVolume + " vs " + volIndex); 537 mLastLocalVolume = mLocalVolume; 538 } 539 } 540 // remember the remote volume value, as it's the one supported by remote 541 if (volAdj) { 542 synchronized (mVolumeMapping) { 543 mVolumeMapping.put(volIndex, (int) absVol); 544 if (DEBUG) Log.v(TAG, "remember volume mapping " +volIndex+ "-"+absVol); 545 } 546 } 547 548 notifyVolumeChanged(mLocalVolume); 549 mRemoteVolume = absVol; 550 long pecentVolChanged = ((long) absVol * 100) / 0x7f; 551 Log.e(TAG, "percent volume changed: " + pecentVolChanged + "%"); 552 } else if (msg.arg2 == AVRC_RSP_REJ) { 553 Log.e(TAG, "setAbsoluteVolume call rejected"); 554 } else if (volAdj && mLastRemoteVolume > 0 && mLastRemoteVolume < AVRCP_MAX_VOL && 555 mLocalVolume == volIndex && 556 (msg.arg2 == AVRC_RSP_ACCEPT)) { 557 /* oops, the volume is still same, remote does not like the value 558 * retry a volume one step up/down */ 559 if (DEBUG) Log.d(TAG, "Remote device didn't tune volume, let's try one more step."); 560 int retry_volume = Math.min(AVRCP_MAX_VOL, 561 Math.max(0, mLastRemoteVolume + mLastDirection)); 562 if (setVolumeNative(retry_volume)) { 563 mLastRemoteVolume = retry_volume; 564 sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY); 565 mVolCmdAdjustInProgress = true; 566 } 567 } 568 break; 569 570 case MSG_ADJUST_VOLUME: 571 if (!isAbsoluteVolumeSupported()) { 572 if (DEBUG) Log.v(TAG, "ignore MSG_ADJUST_VOLUME"); 573 break; 574 } 575 576 if (DEBUG) Log.d(TAG, "MSG_ADJUST_VOLUME: direction=" + msg.arg1); 577 578 if (mVolCmdAdjustInProgress || mVolCmdSetInProgress) { 579 if (DEBUG) Log.w(TAG, "There is already a volume command in progress."); 580 break; 581 } 582 583 // Remote device didn't set initial volume. Let's black list it 584 if (mInitialRemoteVolume == -1) { 585 Log.d(TAG, "remote " + mAddress + " never tell us initial volume, black list it."); 586 blackListCurrentDevice(); 587 break; 588 } 589 590 // Wait on verification on volume from device, before changing the volume. 591 if (mRemoteVolume != -1 && (msg.arg1 == -1 || msg.arg1 == 1)) { 592 int setVol = -1; 593 int targetVolIndex = -1; 594 if (mLocalVolume == 0 && msg.arg1 == -1) { 595 if (DEBUG) Log.w(TAG, "No need to Vol down from 0."); 596 break; 597 } 598 if (mLocalVolume == mAudioStreamMax && msg.arg1 == 1) { 599 if (DEBUG) Log.w(TAG, "No need to Vol up from max."); 600 break; 601 } 602 603 targetVolIndex = mLocalVolume + msg.arg1; 604 if (DEBUG) Log.d(TAG, "Adjusting volume to " + targetVolIndex); 605 606 Integer i; 607 synchronized (mVolumeMapping) { 608 i = mVolumeMapping.get(targetVolIndex); 609 } 610 611 if (i != null) { 612 /* if we already know this volume mapping, use it */ 613 setVol = i.byteValue(); 614 if (setVol == mRemoteVolume) { 615 if (DEBUG) Log.d(TAG, "got same volume from mapping for " + targetVolIndex + ", ignore."); 616 setVol = -1; 617 } 618 if (DEBUG) Log.d(TAG, "set volume from mapping " + targetVolIndex + "-" + setVol); 619 } 620 621 if (setVol == -1) { 622 /* otherwise use phone steps */ 623 setVol = Math.min(AVRCP_MAX_VOL, 624 convertToAvrcpVolume(Math.max(0, targetVolIndex))); 625 if (DEBUG) Log.d(TAG, "set volume from local volume "+ targetVolIndex+"-"+ setVol); 626 } 627 628 if (setVolumeNative(setVol)) { 629 sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY); 630 mVolCmdAdjustInProgress = true; 631 mLastDirection = msg.arg1; 632 mLastRemoteVolume = setVol; 633 mLastLocalVolume = targetVolIndex; 634 } else { 635 if (DEBUG) Log.d(TAG, "setVolumeNative failed"); 636 } 637 } else { 638 Log.e(TAG, "Unknown direction in MSG_ADJUST_VOLUME"); 639 } 640 break; 641 642 case MSG_SET_ABSOLUTE_VOLUME: 643 if (!isAbsoluteVolumeSupported()) { 644 if (DEBUG) Log.v(TAG, "ignore MSG_SET_ABSOLUTE_VOLUME"); 645 break; 646 } 647 648 if (DEBUG) Log.v(TAG, "MSG_SET_ABSOLUTE_VOLUME"); 649 650 if (mVolCmdSetInProgress || mVolCmdAdjustInProgress) { 651 if (DEBUG) Log.w(TAG, "There is already a volume command in progress."); 652 break; 653 } 654 655 // Remote device didn't set initial volume. Let's black list it 656 if (mInitialRemoteVolume == -1) { 657 if (DEBUG) Log.d(TAG, "remote " + mAddress + " never tell us initial volume, black list it."); 658 blackListCurrentDevice(); 659 break; 660 } 661 662 int avrcpVolume = convertToAvrcpVolume(msg.arg1); 663 avrcpVolume = Math.min(AVRCP_MAX_VOL, Math.max(0, avrcpVolume)); 664 if (DEBUG) Log.d(TAG, "Setting volume to " + msg.arg1 + "-" + avrcpVolume); 665 if (setVolumeNative(avrcpVolume)) { 666 sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY); 667 mVolCmdSetInProgress = true; 668 mLastRemoteVolume = avrcpVolume; 669 mLastLocalVolume = msg.arg1; 670 } else { 671 if (DEBUG) Log.d(TAG, "setVolumeNative failed"); 672 } 673 break; 674 675 case MSG_ABS_VOL_TIMEOUT: 676 if (DEBUG) Log.v(TAG, "MSG_ABS_VOL_TIMEOUT: Volume change cmd timed out."); 677 mVolCmdAdjustInProgress = false; 678 mVolCmdSetInProgress = false; 679 if (mAbsVolRetryTimes >= MAX_ERROR_RETRY_TIMES) { 680 mAbsVolRetryTimes = 0; 681 /* too many volume change failures, black list the device */ 682 blackListCurrentDevice(); 683 } else { 684 mAbsVolRetryTimes += 1; 685 if (setVolumeNative(mLastRemoteVolume)) { 686 sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY); 687 mVolCmdSetInProgress = true; 688 } 689 } 690 break; 691 692 case MSG_SET_A2DP_AUDIO_STATE: 693 if (DEBUG) Log.v(TAG, "MSG_SET_A2DP_AUDIO_STATE:" + msg.arg1); 694 mA2dpState = msg.arg1; 695 scheduleMediaUpdate(); 696 break; 697 698 case MSG_NATIVE_REQ_GET_FOLDER_ITEMS: { 699 AvrcpCmd.FolderItemsCmd folderObj = (AvrcpCmd.FolderItemsCmd) msg.obj; 700 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_FOLDER_ITEMS " + folderObj); 701 switch (folderObj.mScope) { 702 case AvrcpConstants.BTRC_SCOPE_PLAYER_LIST: 703 handleMediaPlayerListRsp(folderObj); 704 break; 705 case AvrcpConstants.BTRC_SCOPE_FILE_SYSTEM: 706 case AvrcpConstants.BTRC_SCOPE_NOW_PLAYING: 707 handleGetFolderItemBrowseResponse(folderObj, folderObj.mAddress); 708 break; 709 default: 710 Log.e(TAG, "unknown scope for getfolderitems. scope = " 711 + folderObj.mScope); 712 getFolderItemsRspNative(folderObj.mAddress, 713 AvrcpConstants.RSP_INV_SCOPE, (short) 0, (byte) 0, 0, 714 null, null, null, null, null, null, null, null); 715 } 716 break; 717 } 718 719 case MSG_NATIVE_REQ_SET_ADDR_PLAYER: 720 // object is bdaddr, argument 1 is the selected player id 721 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_SET_ADDR_PLAYER id=" + msg.arg1); 722 setAddressedPlayer((byte[]) msg.obj, msg.arg1); 723 break; 724 725 case MSG_NATIVE_REQ_GET_ITEM_ATTR: 726 // msg object contains the item attribute object 727 AvrcpCmd.ItemAttrCmd cmd = (AvrcpCmd.ItemAttrCmd) msg.obj; 728 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_ITEM_ATTR " + cmd); 729 handleGetItemAttr(cmd); 730 break; 731 732 case MSG_NATIVE_REQ_SET_BR_PLAYER: 733 // argument 1 is the selected player id 734 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_SET_BR_PLAYER id=" + msg.arg1); 735 setBrowsedPlayer((byte[]) msg.obj, msg.arg1); 736 break; 737 738 case MSG_NATIVE_REQ_CHANGE_PATH: 739 { 740 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_CHANGE_PATH"); 741 Bundle data = msg.getData(); 742 byte[] bdaddr = data.getByteArray("BdAddress"); 743 byte[] folderUid = data.getByteArray("folderUid"); 744 byte direction = data.getByte("direction"); 745 if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) { 746 mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).changePath(folderUid, 747 direction); 748 } else { 749 Log.e(TAG, "Remote requesting change path before setbrowsedplayer"); 750 changePathRspNative(bdaddr, AvrcpConstants.RSP_BAD_CMD, 0); 751 } 752 break; 753 } 754 755 case MSG_NATIVE_REQ_PLAY_ITEM: 756 { 757 Bundle data = msg.getData(); 758 byte[] bdaddr = data.getByteArray("BdAddress"); 759 byte[] uid = data.getByteArray("uid"); 760 byte scope = data.getByte("scope"); 761 if (DEBUG) 762 Log.v(TAG, "MSG_NATIVE_REQ_PLAY_ITEM scope=" + scope + " id=" 763 + Utils.byteArrayToString(uid)); 764 handlePlayItemResponse(bdaddr, uid, scope); 765 break; 766 } 767 768 case MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS: 769 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS scope=" + msg.arg1); 770 // argument 1 is scope, object is bdaddr 771 handleGetTotalNumOfItemsResponse((byte[]) msg.obj, (byte) msg.arg1); 772 break; 773 774 case MSG_NATIVE_REQ_PASS_THROUGH: 775 if (DEBUG) 776 Log.v(TAG, "MSG_NATIVE_REQ_PASS_THROUGH: id=" + msg.arg1 + " st=" + msg.arg2); 777 // argument 1 is id, argument 2 is keyState 778 handlePassthroughCmd(msg.arg1, msg.arg2); 779 break; 780 781 case MSG_UPDATE_MEDIA: 782 if (DEBUG) Log.v(TAG, "MSG_UPDATE_MEDIA"); 783 // Throttle to once per MEDIA_DWELL_TIME 784 removeMessages(MSG_UPDATE_MEDIA); 785 updateCurrentMediaState(false); 786 break; 787 788 default: 789 Log.e(TAG, "unknown message! msg.what=" + msg.what); 790 break; 791 } 792 } 793 } 794 795 private PlaybackState updatePlaybackState() { 796 PlaybackState newState = new PlaybackState.Builder() 797 .setState(PlaybackState.STATE_NONE, 798 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f) 799 .build(); 800 synchronized (this) { 801 PlaybackState controllerState = null; 802 if (mMediaController != null) { 803 controllerState = mMediaController.getPlaybackState(); 804 } 805 806 if (controllerState != null) { 807 newState = controllerState; 808 } else if (mAudioManager != null && mAudioManager.isMusicActive()) { 809 // Use A2DP state if we don't have a state from MediaControlller 810 PlaybackState.Builder builder = new PlaybackState.Builder(); 811 if (mA2dpState == BluetoothA2dp.STATE_PLAYING) { 812 builder.setState(PlaybackState.STATE_PLAYING, 813 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f); 814 } else { 815 builder.setState(PlaybackState.STATE_PAUSED, 816 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f); 817 } 818 newState = builder.build(); 819 } 820 } 821 822 byte newPlayStatus = getBluetoothPlayState(newState); 823 824 /* update play status in global media player list */ 825 MediaPlayerInfo player = getAddressedPlayerInfo(); 826 if (player != null) { 827 player.setPlayStatus(newPlayStatus); 828 } 829 830 if (DEBUG) { 831 Log.v(TAG, "updatePlaybackState (" + mPlayStatusChangedNT + "): " + mReportedPlayStatus 832 + "" + newPlayStatus + "(" + newState + ")"); 833 } 834 835 if (newState != null) mCurrentPlayState = newState; 836 837 if (mPlayStatusChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM 838 && (mReportedPlayStatus != newPlayStatus)) { 839 sendPlaybackStatus(AvrcpConstants.NOTIFICATION_TYPE_CHANGED, newPlayStatus); 840 } 841 return mCurrentPlayState; 842 } 843 844 private void sendPlaybackStatus(int playStatusChangedNT, byte playbackState) { 845 registerNotificationRspPlayStatusNative(playStatusChangedNT, playbackState); 846 mPlayStatusChangedNT = playStatusChangedNT; 847 mReportedPlayStatus = playbackState; 848 } 849 850 private void updateTransportControls(int transportControlFlags) { 851 mTransportControlFlags = transportControlFlags; 852 } 853 854 class MediaAttributes { 855 private boolean exists; 856 private String title; 857 private String artistName; 858 private String albumName; 859 private String mediaNumber; 860 private String mediaTotalNumber; 861 private String genre; 862 private long playingTimeMs; 863 864 private static final int ATTR_TITLE = 1; 865 private static final int ATTR_ARTIST_NAME = 2; 866 private static final int ATTR_ALBUM_NAME = 3; 867 private static final int ATTR_MEDIA_NUMBER = 4; 868 private static final int ATTR_MEDIA_TOTAL_NUMBER = 5; 869 private static final int ATTR_GENRE = 6; 870 private static final int ATTR_PLAYING_TIME_MS = 7; 871 872 873 public MediaAttributes(MediaMetadata data) { 874 exists = data != null; 875 if (!exists) 876 return; 877 878 artistName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ARTIST)); 879 albumName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ALBUM)); 880 mediaNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER)); 881 mediaTotalNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS)); 882 genre = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_GENRE)); 883 playingTimeMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION); 884 885 // Try harder for the title. 886 title = data.getString(MediaMetadata.METADATA_KEY_TITLE); 887 888 if (title == null) { 889 MediaDescription desc = data.getDescription(); 890 if (desc != null) { 891 CharSequence val = desc.getDescription(); 892 if (val != null) 893 title = val.toString(); 894 } 895 } 896 897 if (title == null) 898 title = new String(); 899 } 900 901 public long getLength() { 902 if (!exists) return 0L; 903 return playingTimeMs; 904 } 905 906 public boolean equals(MediaAttributes other) { 907 if (other == null) 908 return false; 909 910 if (exists != other.exists) 911 return false; 912 913 if (exists == false) 914 return true; 915 916 return (title.equals(other.title)) && (artistName.equals(other.artistName)) 917 && (albumName.equals(other.albumName)) 918 && (mediaNumber.equals(other.mediaNumber)) 919 && (mediaTotalNumber.equals(other.mediaTotalNumber)) 920 && (genre.equals(other.genre)) && (playingTimeMs == other.playingTimeMs); 921 } 922 923 public String getString(int attrId) { 924 if (!exists) 925 return new String(); 926 927 switch (attrId) { 928 case ATTR_TITLE: 929 return title; 930 case ATTR_ARTIST_NAME: 931 return artistName; 932 case ATTR_ALBUM_NAME: 933 return albumName; 934 case ATTR_MEDIA_NUMBER: 935 return mediaNumber; 936 case ATTR_MEDIA_TOTAL_NUMBER: 937 return mediaTotalNumber; 938 case ATTR_GENRE: 939 return genre; 940 case ATTR_PLAYING_TIME_MS: 941 return Long.toString(playingTimeMs); 942 default: 943 return new String(); 944 } 945 } 946 947 private String stringOrBlank(String s) { 948 return s == null ? new String() : s; 949 } 950 951 private String longStringOrBlank(Long s) { 952 return s == null ? new String() : s.toString(); 953 } 954 955 public String toString() { 956 if (!exists) { 957 return "[MediaAttributes: none]"; 958 } 959 960 return "[MediaAttributes: " + title + " - " + albumName + " by " + artistName + " (" 961 + playingTimeMs + " " + mediaNumber + "/" + mediaTotalNumber + ") " + genre 962 + "]"; 963 } 964 965 public String toRedactedString() { 966 if (!exists) { 967 return "[MediaAttributes: none]"; 968 } 969 970 return "[MediaAttributes: " + Utils.ellipsize(title) + " - " 971 + Utils.ellipsize(albumName) + " by " + Utils.ellipsize(artistName) + " (" 972 + playingTimeMs + " " + mediaNumber + "/" + mediaTotalNumber + ") " + genre 973 + "]"; 974 } 975 } 976 977 private void scheduleMediaUpdate() { 978 Message msg = mHandler.obtainMessage(MSG_UPDATE_MEDIA); 979 mHandler.sendMessageDelayed(msg, MEDIA_DWELL_TIME); 980 } 981 982 private void updateCurrentMediaState(boolean registering) { 983 // Only do player updates when we aren't registering for track changes. 984 if (!registering) { 985 if (mAvailablePlayerViewChanged) { 986 registerNotificationRspAvalPlayerChangedNative( 987 AvrcpConstants.NOTIFICATION_TYPE_CHANGED); 988 mAvailablePlayerViewChanged = false; 989 } 990 if (mAddrPlayerChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM 991 && mReportedPlayerID != mCurrAddrPlayerID) { 992 registerNotificationRspAddrPlayerChangedNative( 993 AvrcpConstants.NOTIFICATION_TYPE_CHANGED, mCurrAddrPlayerID, sUIDCounter); 994 mAddrPlayerChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 995 // Changing player sends reject to anything else we would notify... 996 mReportedPlayerID = mCurrAddrPlayerID; 997 mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 998 mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 999 mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 1000 // If the player changed, they need to re-request anything here again 1001 // so we can skip the rest of the update. 1002 return; 1003 } 1004 } 1005 1006 MediaAttributes currentAttributes; 1007 PlaybackState newState = updatePlaybackState(); 1008 1009 synchronized (this) { 1010 if (mMediaController == null) { 1011 currentAttributes = new MediaAttributes(null); 1012 } else { 1013 newState = mMediaController.getPlaybackState(); 1014 currentAttributes = new MediaAttributes(mMediaController.getMetadata()); 1015 } 1016 } 1017 1018 long newQueueId = MediaSession.QueueItem.UNKNOWN_ID; 1019 if (newState != null) newQueueId = newState.getActiveQueueItemId(); 1020 Log.v(TAG, "Media update: id " + mLastQueueId + "" + newQueueId + "? " 1021 + currentAttributes.toRedactedString()); 1022 // Notify track changed if: 1023 // - The CT is registering for the notification 1024 // - Queue ID is UNKNOWN and MediaMetadata is different 1025 // - Queue ID is valid and different and MediaMetadata is different 1026 if (registering || (((newQueueId == -1) || (newQueueId != mLastQueueId)) 1027 && !currentAttributes.equals(mMediaAttributes))) { 1028 sendTrackChangedRsp(registering); 1029 mMediaAttributes = currentAttributes; 1030 mLastQueueId = newQueueId; 1031 } 1032 sendPlayPosNotificationRsp(false); 1033 } 1034 1035 private void getRcFeaturesRequestFromNative(byte[] address, int features) { 1036 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_RC_FEATURES, features, 0, 1037 Utils.getAddressStringFromByte(address)); 1038 mHandler.sendMessage(msg); 1039 } 1040 1041 private void getPlayStatusRequestFromNative(byte[] address) { 1042 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_PLAY_STATUS); 1043 msg.obj = address; 1044 mHandler.sendMessage(msg); 1045 } 1046 1047 private void getElementAttrRequestFromNative(byte[] address, byte numAttr, int[] attrs) { 1048 AvrcpCmd avrcpCmdobj = new AvrcpCmd(); 1049 AvrcpCmd.ElementAttrCmd elemAttr = avrcpCmdobj.new ElementAttrCmd(address, numAttr, attrs); 1050 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_ELEM_ATTRS); 1051 msg.obj = elemAttr; 1052 mHandler.sendMessage(msg); 1053 } 1054 1055 private void registerNotificationRequestFromNative(byte[] address,int eventId, int param) { 1056 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_REGISTER_NOTIFICATION, eventId, param); 1057 msg.obj = address; 1058 mHandler.sendMessage(msg); 1059 } 1060 1061 private void processRegisterNotification(byte[] address, int eventId, int param) { 1062 switch (eventId) { 1063 case EVT_PLAY_STATUS_CHANGED: 1064 mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 1065 updatePlaybackState(); 1066 sendPlaybackStatus(AvrcpConstants.NOTIFICATION_TYPE_INTERIM, 1067 getBluetoothPlayState(mCurrentPlayState)); 1068 break; 1069 1070 case EVT_TRACK_CHANGED: 1071 Log.v(TAG, "Track changed notification enabled"); 1072 mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; 1073 updateCurrentMediaState(true); 1074 break; 1075 1076 case EVT_PLAY_POS_CHANGED: 1077 mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; 1078 mPlaybackIntervalMs = (long) param * 1000L; 1079 sendPlayPosNotificationRsp(true); 1080 break; 1081 1082 case EVT_AVBL_PLAYERS_CHANGED: 1083 /* Notify remote available players changed */ 1084 if (DEBUG) Log.d(TAG, "Available Players notification enabled"); 1085 registerNotificationRspAvalPlayerChangedNative( 1086 AvrcpConstants.NOTIFICATION_TYPE_INTERIM); 1087 break; 1088 1089 case EVT_ADDR_PLAYER_CHANGED: 1090 /* Notify remote addressed players changed */ 1091 if (DEBUG) Log.d(TAG, "Addressed Player notification enabled"); 1092 registerNotificationRspAddrPlayerChangedNative( 1093 AvrcpConstants.NOTIFICATION_TYPE_INTERIM, 1094 mCurrAddrPlayerID, sUIDCounter); 1095 mAddrPlayerChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; 1096 mReportedPlayerID = mCurrAddrPlayerID; 1097 break; 1098 1099 case EVENT_UIDS_CHANGED: 1100 if (DEBUG) Log.d(TAG, "UIDs changed notification enabled"); 1101 registerNotificationRspUIDsChangedNative( 1102 AvrcpConstants.NOTIFICATION_TYPE_INTERIM, sUIDCounter); 1103 break; 1104 1105 case EVENT_NOW_PLAYING_CONTENT_CHANGED: 1106 if (DEBUG) Log.d(TAG, "Now Playing List changed notification enabled"); 1107 /* send interim response to remote device */ 1108 if (!registerNotificationRspNowPlayingChangedNative( 1109 AvrcpConstants.NOTIFICATION_TYPE_INTERIM)) { 1110 Log.e(TAG, "EVENT_NOW_PLAYING_CONTENT_CHANGED: " + 1111 "registerNotificationRspNowPlayingChangedNative for Interim rsp failed!"); 1112 } 1113 break; 1114 } 1115 } 1116 1117 private void handlePassthroughCmdRequestFromNative(byte[] address, int id, int keyState) { 1118 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_PASS_THROUGH, id, keyState); 1119 mHandler.sendMessage(msg); 1120 } 1121 1122 private void sendTrackChangedRsp(boolean registering) { 1123 if (!registering && mTrackChangedNT != AvrcpConstants.NOTIFICATION_TYPE_INTERIM) { 1124 if (DEBUG) Log.d(TAG, "sendTrackChangedRsp: Not registered or registering."); 1125 return; 1126 } 1127 1128 mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 1129 if (registering) mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; 1130 1131 MediaPlayerInfo info = getAddressedPlayerInfo(); 1132 // for non-browsable players or no player 1133 if (info != null && !info.isBrowseSupported()) { 1134 byte[] track = AvrcpConstants.TRACK_IS_SELECTED; 1135 if (!mMediaAttributes.exists) track = AvrcpConstants.NO_TRACK_SELECTED; 1136 registerNotificationRspTrackChangeNative(mTrackChangedNT, track); 1137 return; 1138 } 1139 1140 mAddressedMediaPlayer.sendTrackChangeWithId(mTrackChangedNT, mMediaController); 1141 } 1142 1143 private long getPlayPosition() { 1144 if (mCurrentPlayState == null) { 1145 return -1L; 1146 } 1147 1148 if (mCurrentPlayState.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN) { 1149 return -1L; 1150 } 1151 1152 if (isPlayingState(mCurrentPlayState)) { 1153 long sinceUpdate = 1154 (SystemClock.elapsedRealtime() - mCurrentPlayState.getLastPositionUpdateTime()); 1155 return sinceUpdate + mCurrentPlayState.getPosition(); 1156 } 1157 1158 return mCurrentPlayState.getPosition(); 1159 } 1160 1161 private boolean isPlayingState(@Nullable PlaybackState state) { 1162 if (state == null) return false; 1163 return (state != null) && (state.getState() == PlaybackState.STATE_PLAYING) 1164 || (state.getState() == PlaybackState.STATE_BUFFERING); 1165 } 1166 1167 /** 1168 * Sends a play position notification, or schedules one to be 1169 * sent later at an appropriate time. If |requested| is true, 1170 * does both because this was called in reponse to a request from the 1171 * TG. 1172 */ 1173 private void sendPlayPosNotificationRsp(boolean requested) { 1174 if (!requested && mPlayPosChangedNT != AvrcpConstants.NOTIFICATION_TYPE_INTERIM) { 1175 if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: Not registered or requesting."); 1176 return; 1177 } 1178 1179 long playPositionMs = getPlayPosition(); 1180 String debugLine = "sendPlayPosNotificationRsp: "; 1181 1182 // mNextPosMs is set to -1 when the previous position was invalid 1183 // so this will be true if the new position is valid & old was invalid. 1184 // mPlayPositionMs is set to -1 when the new position is invalid, 1185 // and the old mPrevPosMs is >= 0 so this is true when the new is invalid 1186 // and the old was valid. 1187 if (DEBUG) { 1188 debugLine += "(" + requested + ") " + mPrevPosMs + " <=? " + playPositionMs + " <=? " 1189 + mNextPosMs; 1190 if (isPlayingState(mCurrentPlayState)) debugLine += " Playing"; 1191 debugLine += " State: " + mCurrentPlayState.getState(); 1192 } 1193 if (requested || ((mLastReportedPosition != playPositionMs) && 1194 (playPositionMs >= mNextPosMs) || (playPositionMs <= mPrevPosMs))) { 1195 if (!requested) mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 1196 registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int) playPositionMs); 1197 mLastReportedPosition = playPositionMs; 1198 if (playPositionMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) { 1199 mNextPosMs = playPositionMs + mPlaybackIntervalMs; 1200 mPrevPosMs = playPositionMs - mPlaybackIntervalMs; 1201 } else { 1202 mNextPosMs = -1; 1203 mPrevPosMs = -1; 1204 } 1205 } 1206 1207 mHandler.removeMessages(MSG_PLAY_INTERVAL_TIMEOUT); 1208 if (mPlayPosChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM && isPlayingState(mCurrentPlayState)) { 1209 Message msg = mHandler.obtainMessage(MSG_PLAY_INTERVAL_TIMEOUT); 1210 long delay = mPlaybackIntervalMs; 1211 if (mNextPosMs != -1) { 1212 delay = mNextPosMs - (playPositionMs > 0 ? playPositionMs : 0); 1213 } 1214 if (DEBUG) debugLine += " Timeout " + delay + "ms"; 1215 mHandler.sendMessageDelayed(msg, delay); 1216 } 1217 if (DEBUG) Log.d(TAG, debugLine); 1218 } 1219 1220 /** 1221 * This is called from AudioService. It will return whether this device supports abs volume. 1222 * NOT USED AT THE MOMENT. 1223 */ 1224 public boolean isAbsoluteVolumeSupported() { 1225 return ((mFeatures & BTRC_FEAT_ABSOLUTE_VOLUME) != 0); 1226 } 1227 1228 /** 1229 * We get this call from AudioService. This will send a message to our handler object, 1230 * requesting our handler to call setVolumeNative() 1231 */ 1232 public void adjustVolume(int direction) { 1233 Message msg = mHandler.obtainMessage(MSG_ADJUST_VOLUME, direction, 0); 1234 mHandler.sendMessage(msg); 1235 } 1236 1237 public void setAbsoluteVolume(int volume) { 1238 if (volume == mLocalVolume) { 1239 if (DEBUG) Log.v(TAG, "setAbsoluteVolume is setting same index, ignore "+volume); 1240 return; 1241 } 1242 1243 mHandler.removeMessages(MSG_ADJUST_VOLUME); 1244 Message msg = mHandler.obtainMessage(MSG_SET_ABSOLUTE_VOLUME, volume, 0); 1245 mHandler.sendMessage(msg); 1246 } 1247 1248 /* Called in the native layer as a btrc_callback to return the volume set on the carkit in the 1249 * case when the volume is change locally on the carkit. This notification is not called when 1250 * the volume is changed from the phone. 1251 * 1252 * This method will send a message to our handler to change the local stored volume and notify 1253 * AudioService to update the UI 1254 */ 1255 private void volumeChangeRequestFromNative(byte[] address, int volume, int ctype) { 1256 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_VOLUME_CHANGE, volume, ctype); 1257 Bundle data = new Bundle(); 1258 data.putByteArray("BdAddress" , address); 1259 msg.setData(data); 1260 mHandler.sendMessage(msg); 1261 } 1262 1263 private void getFolderItemsRequestFromNative( 1264 byte[] address, byte scope, long startItem, long endItem, byte numAttr, int[] attrIds) { 1265 AvrcpCmd avrcpCmdobj = new AvrcpCmd(); 1266 AvrcpCmd.FolderItemsCmd folderObj = avrcpCmdobj.new FolderItemsCmd(address, scope, 1267 startItem, endItem, numAttr, attrIds); 1268 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_FOLDER_ITEMS, 0, 0); 1269 msg.obj = folderObj; 1270 mHandler.sendMessage(msg); 1271 } 1272 1273 private void setAddressedPlayerRequestFromNative(byte[] address, int playerId) { 1274 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_SET_ADDR_PLAYER, playerId, 0); 1275 msg.obj = address; 1276 mHandler.sendMessage(msg); 1277 } 1278 1279 private void setBrowsedPlayerRequestFromNative(byte[] address, int playerId) { 1280 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_SET_BR_PLAYER, playerId, 0); 1281 msg.obj = address; 1282 mHandler.sendMessage(msg); 1283 } 1284 1285 private void changePathRequestFromNative(byte[] address, byte direction, byte[] folderUid) { 1286 Bundle data = new Bundle(); 1287 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_CHANGE_PATH); 1288 data.putByteArray("BdAddress" , address); 1289 data.putByteArray("folderUid" , folderUid); 1290 data.putByte("direction" , direction); 1291 msg.setData(data); 1292 mHandler.sendMessage(msg); 1293 } 1294 1295 private void getItemAttrRequestFromNative(byte[] address, byte scope, byte[] itemUid, int uidCounter, 1296 byte numAttr, int[] attrs) { 1297 AvrcpCmd avrcpCmdobj = new AvrcpCmd(); 1298 AvrcpCmd.ItemAttrCmd itemAttr = avrcpCmdobj.new ItemAttrCmd(address, scope, 1299 itemUid, uidCounter, numAttr, attrs); 1300 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_ITEM_ATTR); 1301 msg.obj = itemAttr; 1302 mHandler.sendMessage(msg); 1303 } 1304 1305 private void searchRequestFromNative(byte[] address, int charsetId, byte[] searchStr) { 1306 /* Search is not supported */ 1307 Log.w(TAG, "searchRequestFromNative: search is not supported"); 1308 searchRspNative(address, AvrcpConstants.RSP_SRCH_NOT_SPRTD, 0, 0); 1309 } 1310 1311 private void playItemRequestFromNative(byte[] address, byte scope, int uidCounter, byte[] uid) { 1312 Bundle data = new Bundle(); 1313 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_PLAY_ITEM); 1314 data.putByteArray("BdAddress" , address); 1315 data.putByteArray("uid" , uid); 1316 data.putInt("uidCounter" , uidCounter); 1317 data.putByte("scope" , scope); 1318 msg.setData(data); 1319 mHandler.sendMessage(msg); 1320 } 1321 1322 private void addToPlayListRequestFromNative(byte[] address, byte scope, byte[] uid, int uidCounter) { 1323 /* add to NowPlaying not supported */ 1324 Log.w(TAG, "addToPlayListRequestFromNative: not supported! scope=" + scope); 1325 addToNowPlayingRspNative(address, AvrcpConstants.RSP_INTERNAL_ERR); 1326 } 1327 1328 private void getTotalNumOfItemsRequestFromNative(byte[] address, byte scope) { 1329 Bundle data = new Bundle(); 1330 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS); 1331 msg.arg1 = scope; 1332 msg.obj = address; 1333 mHandler.sendMessage(msg); 1334 } 1335 1336 private void notifyVolumeChanged(int volume) { 1337 mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 1338 AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME); 1339 } 1340 1341 private int convertToAudioStreamVolume(int volume) { 1342 // Rescale volume to match AudioSystem's volume 1343 return (int) Math.floor((double) volume*mAudioStreamMax/AVRCP_MAX_VOL); 1344 } 1345 1346 private int convertToAvrcpVolume(int volume) { 1347 return (int) Math.ceil((double) volume*AVRCP_MAX_VOL/mAudioStreamMax); 1348 } 1349 1350 private void blackListCurrentDevice() { 1351 mFeatures &= ~BTRC_FEAT_ABSOLUTE_VOLUME; 1352 mAudioManager.avrcpSupportsAbsoluteVolume(mAddress, isAbsoluteVolumeSupported()); 1353 1354 SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, 1355 Context.MODE_PRIVATE); 1356 SharedPreferences.Editor editor = pref.edit(); 1357 editor.putBoolean(mAddress, true); 1358 editor.apply(); 1359 } 1360 1361 private int modifyRcFeatureFromBlacklist(int feature, String address) { 1362 SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, 1363 Context.MODE_PRIVATE); 1364 if (!pref.contains(address)) { 1365 return feature; 1366 } 1367 if (pref.getBoolean(address, false)) { 1368 feature &= ~BTRC_FEAT_ABSOLUTE_VOLUME; 1369 } 1370 return feature; 1371 } 1372 1373 public void resetBlackList(String address) { 1374 SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, 1375 Context.MODE_PRIVATE); 1376 SharedPreferences.Editor editor = pref.edit(); 1377 editor.remove(address); 1378 editor.apply(); 1379 } 1380 1381 /** 1382 * This is called from A2dpStateMachine to set A2dp audio state. 1383 */ 1384 public void setA2dpAudioState(int state) { 1385 Message msg = mHandler.obtainMessage(MSG_SET_A2DP_AUDIO_STATE, state, 0); 1386 mHandler.sendMessage(msg); 1387 } 1388 1389 private class AvrcpServiceBootReceiver extends BroadcastReceiver { 1390 @Override 1391 public void onReceive(Context context, Intent intent) { 1392 String action = intent.getAction(); 1393 if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 1394 if (DEBUG) Log.d(TAG, "Boot completed, initializing player lists"); 1395 /* initializing media player's list */ 1396 mBrowsableListBuilder.start(); 1397 } 1398 } 1399 } 1400 1401 private class AvrcpServiceBroadcastReceiver extends BroadcastReceiver { 1402 @Override 1403 public void onReceive(Context context, Intent intent) { 1404 String action = intent.getAction(); 1405 if (DEBUG) Log.d(TAG, "AvrcpServiceBroadcastReceiver-> Action: " + action); 1406 1407 if (action.equals(Intent.ACTION_PACKAGE_REMOVED) 1408 || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) { 1409 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 1410 // a package is being removed, not replaced 1411 String packageName = intent.getData().getSchemeSpecificPart(); 1412 if (packageName != null) { 1413 handlePackageModified(packageName, true); 1414 } 1415 } 1416 1417 } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) 1418 || action.equals(Intent.ACTION_PACKAGE_CHANGED)) { 1419 String packageName = intent.getData().getSchemeSpecificPart(); 1420 if (DEBUG) Log.d(TAG,"AvrcpServiceBroadcastReceiver-> packageName: " 1421 + packageName); 1422 if (packageName != null) { 1423 handlePackageModified(packageName, false); 1424 } 1425 } 1426 } 1427 } 1428 1429 private void handlePackageModified(String packageName, boolean removed) { 1430 if (DEBUG) Log.d(TAG, "packageName: " + packageName + " removed: " + removed); 1431 1432 if (removed) { 1433 removeMediaPlayerInfo(packageName); 1434 // old package is removed, updating local browsable player's list 1435 if (isBrowseSupported(packageName)) { 1436 removePackageFromBrowseList(packageName); 1437 } 1438 } else { 1439 // new package has been added. 1440 if (isBrowsableListUpdated(packageName)) { 1441 // Rebuilding browsable players list 1442 mBrowsableListBuilder.start(); 1443 } 1444 } 1445 } 1446 1447 private boolean isBrowsableListUpdated(String newPackageName) { 1448 // getting the browsable media players list from package manager 1449 Intent intent = new Intent("android.media.browse.MediaBrowserService"); 1450 List<ResolveInfo> resInfos = mPackageManager.queryIntentServices(intent, 1451 PackageManager.MATCH_ALL); 1452 for (ResolveInfo resolveInfo : resInfos) { 1453 if (resolveInfo.serviceInfo.packageName.equals(newPackageName)) { 1454 if (DEBUG) 1455 Log.d(TAG, 1456 "isBrowsableListUpdated: package includes MediaBrowserService, true"); 1457 return true; 1458 } 1459 } 1460 1461 // if list has different size 1462 if (resInfos.size() != mBrowsePlayerInfoList.size()) { 1463 if (DEBUG) Log.d(TAG, "isBrowsableListUpdated: browsable list size mismatch, true"); 1464 return true; 1465 } 1466 1467 Log.d(TAG, "isBrowsableListUpdated: false"); 1468 return false; 1469 } 1470 1471 private void removePackageFromBrowseList(String packageName) { 1472 if (DEBUG) Log.d(TAG, "removePackageFromBrowseList: " + packageName); 1473 synchronized (mBrowsePlayerInfoList) { 1474 int browseInfoID = getBrowseId(packageName); 1475 if (browseInfoID != -1) { 1476 mBrowsePlayerInfoList.remove(browseInfoID); 1477 } 1478 } 1479 } 1480 1481 /* 1482 * utility function to get the browse player index from global browsable 1483 * list. It may return -1 if specified package name is not in the list. 1484 */ 1485 private int getBrowseId(String packageName) { 1486 boolean response = false; 1487 int browseInfoID = 0; 1488 synchronized (mBrowsePlayerInfoList) { 1489 for (BrowsePlayerInfo info : mBrowsePlayerInfoList) { 1490 if (info.packageName.equals(packageName)) { 1491 response = true; 1492 break; 1493 } 1494 browseInfoID++; 1495 } 1496 } 1497 1498 if (!response) { 1499 browseInfoID = -1; 1500 } 1501 1502 if (DEBUG) Log.d(TAG, "getBrowseId for packageName: " + packageName + 1503 " , browseInfoID: " + browseInfoID); 1504 return browseInfoID; 1505 } 1506 1507 private void setAddressedPlayer(byte[] bdaddr, int selectedId) { 1508 String functionTag = "setAddressedPlayer(" + selectedId + "): "; 1509 1510 synchronized (mMediaPlayerInfoList) { 1511 if (mMediaPlayerInfoList.isEmpty()) { 1512 Log.w(TAG, functionTag + "no players, send no available players"); 1513 setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_AVBL_PLAY); 1514 return; 1515 } 1516 if (!mMediaPlayerInfoList.containsKey(selectedId)) { 1517 Log.w(TAG, functionTag + "invalid id, sending response back "); 1518 setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_INV_PLAYER); 1519 return; 1520 } 1521 1522 if (isPlayerAlreadyAddressed(selectedId)) { 1523 MediaPlayerInfo info = getAddressedPlayerInfo(); 1524 Log.i(TAG, functionTag + "player already addressed: " + info); 1525 setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR); 1526 return; 1527 } 1528 // register new Media Controller Callback and update the current IDs 1529 if (!updateCurrentController(selectedId, mCurrBrowsePlayerID)) { 1530 Log.e(TAG, functionTag + "updateCurrentController failed!"); 1531 setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR); 1532 return; 1533 } 1534 // If we don't have a controller, try to launch the player 1535 MediaPlayerInfo info = getAddressedPlayerInfo(); 1536 if (info.getMediaController() == null) { 1537 Intent launch = mPackageManager.getLaunchIntentForPackage(info.getPackageName()); 1538 Log.i(TAG, functionTag + "launching player " + launch); 1539 mContext.startActivity(launch); 1540 } 1541 } 1542 setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR); 1543 } 1544 1545 private void setBrowsedPlayer(byte[] bdaddr, int selectedId) { 1546 int status = AvrcpConstants.RSP_NO_ERROR; 1547 1548 // checking for error cases 1549 if (mMediaPlayerInfoList.isEmpty()) { 1550 status = AvrcpConstants.RSP_NO_AVBL_PLAY; 1551 Log.w(TAG, " No Available Players to set, sending response back "); 1552 } else { 1553 // update current browse player id and start browsing service 1554 updateNewIds(mCurrAddrPlayerID, selectedId); 1555 String browsedPackage = getPackageName(selectedId); 1556 1557 if (!isPackageNameValid(browsedPackage)) { 1558 Log.w(TAG, " Invalid package for id:" + mCurrBrowsePlayerID); 1559 status = AvrcpConstants.RSP_INV_PLAYER; 1560 } else if (!isBrowseSupported(browsedPackage)) { 1561 Log.w(TAG, "Browse unsupported for id:" + mCurrBrowsePlayerID 1562 + ", packagename : " + browsedPackage); 1563 status = AvrcpConstants.RSP_PLAY_NOT_BROW; 1564 } else if (!startBrowseService(bdaddr, browsedPackage)) { 1565 Log.e(TAG, "service cannot be started for browse player id:" + mCurrBrowsePlayerID 1566 + ", packagename : " + browsedPackage); 1567 status = AvrcpConstants.RSP_INTERNAL_ERR; 1568 } 1569 } 1570 1571 if (status != AvrcpConstants.RSP_NO_ERROR) { 1572 setBrowsedPlayerRspNative(bdaddr, status, (byte) 0x00, 0, null); 1573 } 1574 1575 if (DEBUG) Log.d(TAG, "setBrowsedPlayer for selectedId: " + selectedId + 1576 " , status: " + status); 1577 } 1578 1579 private MediaSessionManager.OnActiveSessionsChangedListener mActiveSessionListener = 1580 new MediaSessionManager.OnActiveSessionsChangedListener() { 1581 1582 @Override 1583 public void onActiveSessionsChanged( 1584 List<android.media.session.MediaController> newControllers) { 1585 // Update the current players 1586 for (android.media.session.MediaController controller : newControllers) { 1587 addMediaPlayerController(controller); 1588 } 1589 1590 if (newControllers.size() > 0 && getAddressedPlayerInfo() == null) { 1591 if (DEBUG) 1592 Log.v(TAG, "No addressed player but active sessions, taking first."); 1593 setAddressedMediaSessionPackage(newControllers.get(0).getPackageName()); 1594 } 1595 scheduleMediaUpdate(); 1596 } 1597 }; 1598 1599 private void setAddressedMediaSessionPackage(@Nullable String packageName) { 1600 if (packageName == null) { 1601 // Should only happen when there's no media players, reset to no available player. 1602 updateCurrentController(0, mCurrBrowsePlayerID); 1603 return; 1604 } 1605 // No change. 1606 if (getPackageName(mCurrAddrPlayerID).equals(packageName)) return; 1607 if (DEBUG) Log.v(TAG, "Changing addressed media session to " + packageName); 1608 // If the player doesn't exist, we need to add it. 1609 if (getMediaPlayerInfo(packageName) == null) { 1610 addMediaPlayerPackage(packageName); 1611 scheduleMediaUpdate(); 1612 } 1613 synchronized (mMediaPlayerInfoList) { 1614 for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { 1615 if (entry.getValue().getPackageName().equals(packageName)) { 1616 int newAddrID = entry.getKey(); 1617 if (DEBUG) Log.v(TAG, "Set addressed #" + newAddrID + " " + entry.getValue()); 1618 updateCurrentController(newAddrID, mCurrBrowsePlayerID); 1619 scheduleMediaUpdate(); 1620 return; 1621 } 1622 } 1623 } 1624 // We shouldn't ever get here. 1625 Log.e(TAG, "Player info for " + packageName + " doesn't exist!"); 1626 } 1627 1628 private void setActiveMediaSession(MediaSession.Token token) { 1629 android.media.session.MediaController activeController = 1630 new android.media.session.MediaController(mContext, token); 1631 if (DEBUG) Log.v(TAG, "Set active media session " + activeController.getPackageName()); 1632 addMediaPlayerController(activeController); 1633 setAddressedMediaSessionPackage(activeController.getPackageName()); 1634 } 1635 1636 private boolean startBrowseService(byte[] bdaddr, String packageName) { 1637 boolean status = true; 1638 1639 /* creating new instance for Browse Media Player */ 1640 String browseService = getBrowseServiceName(packageName); 1641 if (!browseService.isEmpty()) { 1642 mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).setBrowsed( 1643 packageName, browseService); 1644 } else { 1645 Log.w(TAG, "No Browser service available for " + packageName); 1646 status = false; 1647 } 1648 1649 if (DEBUG) Log.d(TAG, "startBrowseService for packageName: " + packageName + 1650 ", status = " + status); 1651 return status; 1652 } 1653 1654 private String getBrowseServiceName(String packageName) { 1655 String browseServiceName = ""; 1656 1657 // getting the browse service name from browse player info 1658 synchronized (mBrowsePlayerInfoList) { 1659 int browseInfoID = getBrowseId(packageName); 1660 if (browseInfoID != -1) { 1661 browseServiceName = mBrowsePlayerInfoList.get(browseInfoID).serviceClass; 1662 } 1663 } 1664 1665 if (DEBUG) Log.d(TAG, "getBrowseServiceName for packageName: " + packageName + 1666 ", browseServiceName = " + browseServiceName); 1667 return browseServiceName; 1668 } 1669 1670 private class BrowsablePlayerListBuilder extends MediaBrowser.ConnectionCallback { 1671 List<ResolveInfo> mWaiting; 1672 BrowsePlayerInfo mCurrentPlayer; 1673 MediaBrowser mCurrentBrowser; 1674 boolean mPlayersChanged; 1675 1676 public BrowsablePlayerListBuilder() {} 1677 1678 public void start() { 1679 mBrowsePlayerInfoList.clear(); 1680 cleanup(); 1681 Intent intent = new Intent(android.service.media.MediaBrowserService.SERVICE_INTERFACE); 1682 mWaiting = mPackageManager.queryIntentServices(intent, PackageManager.MATCH_ALL); 1683 connectNextPlayer(); 1684 } 1685 1686 public void cleanup() { 1687 if (mWaiting != null) mWaiting.clear(); 1688 mPlayersChanged = false; 1689 if (mCurrentBrowser != null) mCurrentBrowser.disconnect(); 1690 } 1691 1692 private void connectNextPlayer() { 1693 if (mWaiting.isEmpty()) { 1694 // Done. Send players changed if needed. 1695 if (mPlayersChanged) { 1696 registerNotificationRspAvalPlayerChangedNative( 1697 AvrcpConstants.NOTIFICATION_TYPE_CHANGED); 1698 } 1699 return; 1700 } 1701 ResolveInfo info = mWaiting.remove(0); 1702 String displayableName = info.loadLabel(mPackageManager).toString(); 1703 String serviceName = info.serviceInfo.name; 1704 String packageName = info.serviceInfo.packageName; 1705 1706 mCurrentPlayer = new BrowsePlayerInfo(packageName, displayableName, serviceName); 1707 mCurrentBrowser = new MediaBrowser( 1708 mContext, new ComponentName(packageName, serviceName), this, null); 1709 if (DEBUG) Log.d(TAG, "Trying to connect to " + serviceName); 1710 mCurrentBrowser.connect(); 1711 } 1712 1713 @Override 1714 public void onConnected() { 1715 Log.d(TAG, "BrowsablePlayerListBuilder: " + mCurrentPlayer.packageName + " OK"); 1716 mCurrentBrowser.disconnect(); 1717 mCurrentBrowser = null; 1718 mBrowsePlayerInfoList.add(mCurrentPlayer); 1719 MediaPlayerInfo info = getMediaPlayerInfo(mCurrentPlayer.packageName); 1720 MediaController controller = (info == null) ? null : info.getMediaController(); 1721 // Refresh the media player entry so it notices we can browse 1722 if (controller != null) { 1723 addMediaPlayerController(controller.getWrappedInstance()); 1724 } else { 1725 addMediaPlayerPackage(mCurrentPlayer.packageName); 1726 } 1727 mPlayersChanged = true; 1728 connectNextPlayer(); 1729 } 1730 1731 @Override 1732 public void onConnectionFailed() { 1733 Log.d(TAG, "BrowsablePlayerListBuilder: " + mCurrentPlayer.packageName + " FAIL"); 1734 connectNextPlayer(); 1735 } 1736 } 1737 1738 /* Initializes list of media players identified from session manager active sessions */ 1739 private void initMediaPlayersList() { 1740 synchronized (mMediaPlayerInfoList) { 1741 // Clearing old browsable player's list 1742 mMediaPlayerInfoList.clear(); 1743 1744 if (mMediaSessionManager == null) { 1745 if (DEBUG) Log.w(TAG, "initMediaPlayersList: no media session manager!"); 1746 return; 1747 } 1748 1749 List<android.media.session.MediaController> controllers = 1750 mMediaSessionManager.getActiveSessions(null); 1751 if (DEBUG) 1752 Log.v(TAG, "initMediaPlayerInfoList: " + controllers.size() + " controllers"); 1753 /* Initializing all media players */ 1754 for (android.media.session.MediaController controller : controllers) { 1755 addMediaPlayerController(controller); 1756 } 1757 1758 scheduleMediaUpdate(); 1759 1760 if (mMediaPlayerInfoList.size() > 0) { 1761 // Set the first one as the Addressed Player 1762 updateCurrentController(mMediaPlayerInfoList.firstKey(), -1); 1763 } 1764 } 1765 } 1766 1767 private List<android.media.session.MediaController> getMediaControllers() { 1768 List<android.media.session.MediaController> controllers = 1769 new ArrayList<android.media.session.MediaController>(); 1770 synchronized (mMediaPlayerInfoList) { 1771 for (MediaPlayerInfo info : mMediaPlayerInfoList.values()) { 1772 MediaController controller = info.getMediaController(); 1773 if (controller != null) { 1774 controllers.add(controller.getWrappedInstance()); 1775 } 1776 } 1777 } 1778 return controllers; 1779 } 1780 1781 /** Add (or update) a player to the media player list without a controller */ 1782 private boolean addMediaPlayerPackage(String packageName) { 1783 MediaPlayerInfo info = new MediaPlayerInfo(null, AvrcpConstants.PLAYER_TYPE_AUDIO, 1784 AvrcpConstants.PLAYER_SUBTYPE_NONE, PLAYSTATUS_STOPPED, 1785 getFeatureBitMask(packageName), packageName, getAppLabel(packageName)); 1786 return addMediaPlayerInfo(info); 1787 } 1788 1789 /** Add (or update) a player to the media player list given an active controller */ 1790 private boolean addMediaPlayerController(android.media.session.MediaController controller) { 1791 String packageName = controller.getPackageName(); 1792 MediaPlayerInfo info = new MediaPlayerInfo(MediaController.wrap(controller), 1793 AvrcpConstants.PLAYER_TYPE_AUDIO, AvrcpConstants.PLAYER_SUBTYPE_NONE, 1794 getBluetoothPlayState(controller.getPlaybackState()), 1795 getFeatureBitMask(packageName), controller.getPackageName(), 1796 getAppLabel(packageName)); 1797 return addMediaPlayerInfo(info); 1798 } 1799 1800 /** Add or update a player to the media player list given the MediaPlayerInfo object. 1801 * @return true if an item was updated, false if it was added instead 1802 */ 1803 private boolean addMediaPlayerInfo(MediaPlayerInfo info) { 1804 int updateId = -1; 1805 boolean updated = false; 1806 boolean currentRemoved = false; 1807 synchronized (mMediaPlayerInfoList) { 1808 for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { 1809 MediaPlayerInfo current = entry.getValue(); 1810 int id = entry.getKey(); 1811 if (info.getPackageName().equals(current.getPackageName())) { 1812 if (!current.equalView(info)) { 1813 // If we would present a different player, make it a new player 1814 // so that controllers know whether a player is browsable or not. 1815 mMediaPlayerInfoList.remove(id); 1816 currentRemoved = (mCurrAddrPlayerID == id); 1817 break; 1818 } 1819 updateId = id; 1820 updated = true; 1821 break; 1822 } 1823 } 1824 if (updateId == -1) { 1825 // New player 1826 mLastUsedPlayerID++; 1827 updateId = mLastUsedPlayerID; 1828 mAvailablePlayerViewChanged = true; 1829 } 1830 mMediaPlayerInfoList.put(updateId, info); 1831 if (DEBUG) 1832 Log.d(TAG, (updated ? "update #" : "add #") + updateId + ":" + info.toString()); 1833 if (currentRemoved || updateId == mCurrAddrPlayerID) { 1834 updateCurrentController(updateId, mCurrBrowsePlayerID); 1835 } 1836 } 1837 return updated; 1838 } 1839 1840 /** Remove all players related to |packageName| from the media player info list */ 1841 private MediaPlayerInfo removeMediaPlayerInfo(String packageName) { 1842 synchronized (mMediaPlayerInfoList) { 1843 int removeKey = -1; 1844 for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { 1845 if (entry.getValue().getPackageName().equals(packageName)) { 1846 removeKey = entry.getKey(); 1847 break; 1848 } 1849 } 1850 if (removeKey != -1) { 1851 if (DEBUG) 1852 Log.d(TAG, "remove #" + removeKey + ":" + mMediaPlayerInfoList.get(removeKey)); 1853 mAvailablePlayerViewChanged = true; 1854 return mMediaPlayerInfoList.remove(removeKey); 1855 } 1856 1857 return null; 1858 } 1859 } 1860 1861 /** Remove the controller referenced by |controller| from any player in the list */ 1862 private void removeMediaController(@Nullable android.media.session.MediaController controller) { 1863 if (controller == null) return; 1864 synchronized (mMediaPlayerInfoList) { 1865 for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { 1866 MediaPlayerInfo info = entry.getValue(); 1867 MediaController c = info.getMediaController(); 1868 if (c != null && c.equals(controller)) { 1869 info.setMediaController(null); 1870 if (entry.getKey() == mCurrAddrPlayerID) { 1871 updateCurrentController(mCurrAddrPlayerID, mCurrBrowsePlayerID); 1872 } 1873 } 1874 } 1875 } 1876 } 1877 1878 /* 1879 * utility function to get the playback state of any media player through 1880 * media controller APIs. 1881 */ 1882 private byte getBluetoothPlayState(PlaybackState pbState) { 1883 if (pbState == null) { 1884 Log.w(TAG, "playState object null, sending STOPPED"); 1885 return PLAYSTATUS_STOPPED; 1886 } 1887 1888 switch (pbState.getState()) { 1889 case PlaybackState.STATE_PLAYING: 1890 case PlaybackState.STATE_BUFFERING: 1891 return PLAYSTATUS_PLAYING; 1892 1893 case PlaybackState.STATE_STOPPED: 1894 case PlaybackState.STATE_NONE: 1895 case PlaybackState.STATE_CONNECTING: 1896 return PLAYSTATUS_STOPPED; 1897 1898 case PlaybackState.STATE_PAUSED: 1899 return PLAYSTATUS_PAUSED; 1900 1901 case PlaybackState.STATE_FAST_FORWARDING: 1902 case PlaybackState.STATE_SKIPPING_TO_NEXT: 1903 case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM: 1904 return PLAYSTATUS_FWD_SEEK; 1905 1906 case PlaybackState.STATE_REWINDING: 1907 case PlaybackState.STATE_SKIPPING_TO_PREVIOUS: 1908 return PLAYSTATUS_REV_SEEK; 1909 1910 case PlaybackState.STATE_ERROR: 1911 default: 1912 return PLAYSTATUS_ERROR; 1913 } 1914 } 1915 1916 /* 1917 * utility function to get the feature bit mask of any media player through 1918 * package name 1919 */ 1920 private short[] getFeatureBitMask(String packageName) { 1921 1922 ArrayList<Short> featureBitsList = new ArrayList<Short>(); 1923 1924 /* adding default feature bits */ 1925 featureBitsList.add(AvrcpConstants.AVRC_PF_PLAY_BIT_NO); 1926 featureBitsList.add(AvrcpConstants.AVRC_PF_STOP_BIT_NO); 1927 featureBitsList.add(AvrcpConstants.AVRC_PF_PAUSE_BIT_NO); 1928 featureBitsList.add(AvrcpConstants.AVRC_PF_REWIND_BIT_NO); 1929 featureBitsList.add(AvrcpConstants.AVRC_PF_FAST_FWD_BIT_NO); 1930 featureBitsList.add(AvrcpConstants.AVRC_PF_FORWARD_BIT_NO); 1931 featureBitsList.add(AvrcpConstants.AVRC_PF_BACKWARD_BIT_NO); 1932 featureBitsList.add(AvrcpConstants.AVRC_PF_ADV_CTRL_BIT_NO); 1933 1934 /* Add/Modify browse player supported features. */ 1935 if (isBrowseSupported(packageName)) { 1936 featureBitsList.add(AvrcpConstants.AVRC_PF_BROWSE_BIT_NO); 1937 featureBitsList.add(AvrcpConstants.AVRC_PF_UID_UNIQUE_BIT_NO); 1938 featureBitsList.add(AvrcpConstants.AVRC_PF_NOW_PLAY_BIT_NO); 1939 featureBitsList.add(AvrcpConstants.AVRC_PF_GET_NUM_OF_ITEMS_BIT_NO); 1940 } 1941 1942 // converting arraylist to array for response 1943 short[] featureBitsArray = new short[featureBitsList.size()]; 1944 1945 for (int i = 0; i < featureBitsList.size(); i++) { 1946 featureBitsArray[i] = featureBitsList.get(i).shortValue(); 1947 } 1948 1949 return featureBitsArray; 1950 } 1951 1952 /** 1953 * Checks the Package name if it supports Browsing or not. 1954 * 1955 * @param packageName - name of the package to get the Id. 1956 * @return true if it supports browsing, else false. 1957 */ 1958 private boolean isBrowseSupported(String packageName) { 1959 synchronized (mBrowsePlayerInfoList) { 1960 /* check if Browsable Player's list contains this package name */ 1961 for (BrowsePlayerInfo info : mBrowsePlayerInfoList) { 1962 if (info.packageName.equals(packageName)) { 1963 if (DEBUG) Log.v(TAG, "isBrowseSupported for " + packageName + ": true"); 1964 return true; 1965 } 1966 } 1967 } 1968 1969 if (DEBUG) Log.v(TAG, "isBrowseSupported for " + packageName + ": false"); 1970 return false; 1971 } 1972 1973 private String getPackageName(int id) { 1974 MediaPlayerInfo player = null; 1975 synchronized (mMediaPlayerInfoList) { 1976 player = mMediaPlayerInfoList.getOrDefault(id, null); 1977 } 1978 1979 if (player == null) { 1980 Log.w(TAG, "No package name for player (" + id + " not valid)"); 1981 return ""; 1982 } 1983 1984 String packageName = player.getPackageName(); 1985 if (DEBUG) Log.v(TAG, "Player " + id + " package: " + packageName); 1986 return packageName; 1987 } 1988 1989 /* from the global object, getting the current browsed player's package name */ 1990 private String getCurrentBrowsedPlayer(byte[] bdaddr) { 1991 String browsedPlayerPackage = ""; 1992 1993 Map<String, BrowsedMediaPlayer> connList = mAvrcpBrowseManager.getConnList(); 1994 String bdaddrStr = new String(bdaddr); 1995 if(connList.containsKey(bdaddrStr)){ 1996 browsedPlayerPackage = connList.get(bdaddrStr).getPackageName(); 1997 } 1998 if (DEBUG) Log.v(TAG, "getCurrentBrowsedPlayerPackage: " + browsedPlayerPackage); 1999 return browsedPlayerPackage; 2000 } 2001 2002 /* Returns the MediaPlayerInfo for the currently addressed media player */ 2003 private MediaPlayerInfo getAddressedPlayerInfo() { 2004 synchronized (mMediaPlayerInfoList) { 2005 return mMediaPlayerInfoList.getOrDefault(mCurrAddrPlayerID, null); 2006 } 2007 } 2008 2009 /* 2010 * Utility function to get the Media player info from package name returns 2011 * null if package name not found in media players list 2012 */ 2013 private MediaPlayerInfo getMediaPlayerInfo(String packageName) { 2014 synchronized (mMediaPlayerInfoList) { 2015 if (mMediaPlayerInfoList.isEmpty()) { 2016 if (DEBUG) Log.v(TAG, "getMediaPlayerInfo: Media players list empty"); 2017 return null; 2018 } 2019 2020 for (MediaPlayerInfo info : mMediaPlayerInfoList.values()) { 2021 if (packageName.equals(info.getPackageName())) { 2022 if (DEBUG) Log.v(TAG, "getMediaPlayerInfo: Found " + packageName); 2023 return info; 2024 } 2025 } 2026 if (DEBUG) Log.w(TAG, "getMediaPlayerInfo: " + packageName + " not found"); 2027 return null; 2028 } 2029 } 2030 2031 /* prepare media list & return the media player list response object */ 2032 private MediaPlayerListRsp prepareMediaPlayerRspObj() { 2033 synchronized (mMediaPlayerInfoList) { 2034 int numPlayers = mMediaPlayerInfoList.size(); 2035 2036 int[] playerIds = new int[numPlayers]; 2037 byte[] playerTypes = new byte[numPlayers]; 2038 int[] playerSubTypes = new int[numPlayers]; 2039 String[] displayableNameArray = new String[numPlayers]; 2040 byte[] playStatusValues = new byte[numPlayers]; 2041 short[] featureBitMaskValues = 2042 new short[numPlayers * AvrcpConstants.AVRC_FEATURE_MASK_SIZE]; 2043 2044 int players = 0; 2045 for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { 2046 MediaPlayerInfo info = entry.getValue(); 2047 playerIds[players] = entry.getKey(); 2048 playerTypes[players] = info.getMajorType(); 2049 playerSubTypes[players] = info.getSubType(); 2050 displayableNameArray[players] = info.getDisplayableName(); 2051 playStatusValues[players] = info.getPlayStatus(); 2052 2053 short[] featureBits = info.getFeatureBitMask(); 2054 for (int numBit = 0; numBit < featureBits.length; numBit++) { 2055 /* gives which octet this belongs to */ 2056 byte octet = (byte) (featureBits[numBit] / 8); 2057 /* gives the bit position within the octet */ 2058 byte bit = (byte) (featureBits[numBit] % 8); 2059 featureBitMaskValues[(players * AvrcpConstants.AVRC_FEATURE_MASK_SIZE) 2060 + octet] |= (1 << bit); 2061 } 2062 2063 /* printLogs */ 2064 if (DEBUG) { 2065 Log.d(TAG, "Player " + playerIds[players] + ": " + displayableNameArray[players] 2066 + " type: " + playerTypes[players] + ", " 2067 + playerSubTypes[players] + " status: " 2068 + playStatusValues[players]); 2069 } 2070 2071 players++; 2072 } 2073 2074 if (DEBUG) Log.d(TAG, "prepareMediaPlayerRspObj: numPlayers = " + numPlayers); 2075 2076 return new MediaPlayerListRsp(AvrcpConstants.RSP_NO_ERROR, sUIDCounter, numPlayers, 2077 AvrcpConstants.BTRC_ITEM_PLAYER, playerIds, playerTypes, playerSubTypes, 2078 playStatusValues, featureBitMaskValues, displayableNameArray); 2079 } 2080 } 2081 2082 /* build media player list and send it to remote. */ 2083 private void handleMediaPlayerListRsp(AvrcpCmd.FolderItemsCmd folderObj) { 2084 MediaPlayerListRsp rspObj = null; 2085 synchronized (mMediaPlayerInfoList) { 2086 int numPlayers = mMediaPlayerInfoList.size(); 2087 if (numPlayers == 0) { 2088 mediaPlayerListRspNative(folderObj.mAddress, AvrcpConstants.RSP_NO_AVBL_PLAY, 2089 (short) 0, (byte) 0, 0, null, null, null, null, null, null); 2090 return; 2091 } 2092 if (folderObj.mStartItem >= numPlayers) { 2093 Log.i(TAG, "handleMediaPlayerListRsp: start = " + folderObj.mStartItem 2094 + " > num of items = " + numPlayers); 2095 mediaPlayerListRspNative(folderObj.mAddress, AvrcpConstants.RSP_INV_RANGE, 2096 (short) 0, (byte) 0, 0, null, null, null, null, null, null); 2097 return; 2098 } 2099 rspObj = prepareMediaPlayerRspObj(); 2100 } 2101 if (DEBUG) Log.d(TAG, "handleMediaPlayerListRsp: sending " + rspObj.mNumItems + " players"); 2102 mediaPlayerListRspNative(folderObj.mAddress, rspObj.mStatus, rspObj.mUIDCounter, 2103 rspObj.itemType, rspObj.mNumItems, rspObj.mPlayerIds, rspObj.mPlayerTypes, 2104 rspObj.mPlayerSubTypes, rspObj.mPlayStatusValues, rspObj.mFeatureBitMaskValues, 2105 rspObj.mPlayerNameList); 2106 } 2107 2108 /* unregister to the old controller, update new IDs and register to the new controller */ 2109 private boolean updateCurrentController(int addrId, int browseId) { 2110 boolean registerRsp = true; 2111 2112 updateNewIds(addrId, browseId); 2113 2114 MediaController newController = null; 2115 MediaPlayerInfo info = getAddressedPlayerInfo(); 2116 if (info != null) newController = info.getMediaController(); 2117 2118 if (DEBUG) 2119 Log.d(TAG, "updateCurrentController: " + mMediaController + " to " + newController); 2120 synchronized (this) { 2121 if (mMediaController == null || (!mMediaController.equals(newController))) { 2122 if (mMediaController != null) { 2123 mMediaController.unregisterCallback(mMediaControllerCb); 2124 } 2125 mMediaController = newController; 2126 if (mMediaController != null) { 2127 mMediaController.registerCallback(mMediaControllerCb, mHandler); 2128 mAddressedMediaPlayer.updateNowPlayingList(mMediaController); 2129 } else { 2130 mAddressedMediaPlayer.updateNowPlayingList(null); 2131 registerRsp = false; 2132 } 2133 } 2134 } 2135 scheduleMediaUpdate(); 2136 return registerRsp; 2137 } 2138 2139 /* Handle getfolderitems for scope = VFS, Search, NowPlayingList */ 2140 private void handleGetFolderItemBrowseResponse(AvrcpCmd.FolderItemsCmd folderObj, byte[] bdaddr) { 2141 int status = AvrcpConstants.RSP_NO_ERROR; 2142 2143 /* Browsed player is already set */ 2144 if (folderObj.mScope == AvrcpConstants.BTRC_SCOPE_FILE_SYSTEM) { 2145 if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) == null) { 2146 Log.e(TAG, "handleGetFolderItemBrowseResponse: no browsed player set for " 2147 + Utils.getAddressStringFromByte(bdaddr)); 2148 getFolderItemsRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR, (short) 0, 2149 (byte) 0x00, 0, null, null, null, null, null, null, null, null); 2150 return; 2151 } 2152 mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).getFolderItemsVFS(folderObj); 2153 return; 2154 } 2155 if (folderObj.mScope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) { 2156 mAddressedMediaPlayer.getFolderItemsNowPlaying(bdaddr, folderObj, mMediaController); 2157 return; 2158 } 2159 2160 /* invalid scope */ 2161 Log.e(TAG, "handleGetFolderItemBrowseResponse: unknown scope " + folderObj.mScope); 2162 getFolderItemsRspNative(bdaddr, AvrcpConstants.RSP_INV_SCOPE, (short) 0, (byte) 0x00, 0, 2163 null, null, null, null, null, null, null, null); 2164 } 2165 2166 /* utility function to update the global values of current Addressed and browsed player */ 2167 private void updateNewIds(int addrId, int browseId) { 2168 if (DEBUG) 2169 Log.v(TAG, "updateNewIds: Addressed:" + mCurrAddrPlayerID + " to " + addrId 2170 + ", Browse:" + mCurrBrowsePlayerID + " to " + browseId); 2171 mCurrAddrPlayerID = addrId; 2172 mCurrBrowsePlayerID = browseId; 2173 } 2174 2175 /* Getting the application's displayable name from package name */ 2176 private String getAppLabel(String packageName) { 2177 ApplicationInfo appInfo = null; 2178 try { 2179 appInfo = mPackageManager.getApplicationInfo(packageName, 0); 2180 } catch (NameNotFoundException e) { 2181 e.printStackTrace(); 2182 } 2183 2184 return (String) (appInfo != null ? mPackageManager 2185 .getApplicationLabel(appInfo) : "Unknown"); 2186 } 2187 2188 private void handlePlayItemResponse(byte[] bdaddr, byte[] uid, byte scope) { 2189 if (scope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) { 2190 mAddressedMediaPlayer.playItem(bdaddr, uid, mMediaController); 2191 } 2192 else { 2193 if(!isAddrPlayerSameAsBrowsed(bdaddr)) { 2194 Log.w(TAG, "Remote requesting play item on uid which may not be recognized by" + 2195 "current addressed player"); 2196 playItemRspNative(bdaddr, AvrcpConstants.RSP_INV_ITEM); 2197 } 2198 2199 if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) { 2200 mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).playItem(uid, scope); 2201 } else { 2202 Log.e(TAG, "handlePlayItemResponse: Remote requested playitem " + 2203 "before setbrowsedplayer"); 2204 playItemRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR); 2205 } 2206 } 2207 } 2208 2209 private void handleGetItemAttr(AvrcpCmd.ItemAttrCmd itemAttr) { 2210 if (itemAttr.mScope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) { 2211 if (mCurrAddrPlayerID == NO_PLAYER_ID) { 2212 getItemAttrRspNative( 2213 itemAttr.mAddress, AvrcpConstants.RSP_NO_AVBL_PLAY, (byte) 0, null, null); 2214 return; 2215 } 2216 mAddressedMediaPlayer.getItemAttr(itemAttr.mAddress, itemAttr, mMediaController); 2217 return; 2218 } 2219 // All other scopes use browsed player 2220 if (mAvrcpBrowseManager.getBrowsedMediaPlayer(itemAttr.mAddress) != null) { 2221 mAvrcpBrowseManager.getBrowsedMediaPlayer(itemAttr.mAddress).getItemAttr(itemAttr); 2222 } else { 2223 Log.e(TAG, "Could not get attributes. mBrowsedMediaPlayer is null"); 2224 getItemAttrRspNative( 2225 itemAttr.mAddress, AvrcpConstants.RSP_INTERNAL_ERR, (byte) 0, null, null); 2226 } 2227 } 2228 2229 private void handleGetTotalNumOfItemsResponse(byte[] bdaddr, byte scope) { 2230 // for scope as media player list 2231 if (scope == AvrcpConstants.BTRC_SCOPE_PLAYER_LIST) { 2232 int numPlayers = 0; 2233 synchronized (mMediaPlayerInfoList) { 2234 numPlayers = mMediaPlayerInfoList.size(); 2235 } 2236 if (DEBUG) Log.d(TAG, "handleGetTotalNumOfItemsResponse: " + numPlayers + " players."); 2237 getTotalNumOfItemsRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, numPlayers); 2238 } else if (scope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) { 2239 mAddressedMediaPlayer.getTotalNumOfItems(bdaddr, mMediaController); 2240 } else { 2241 // for FileSystem browsing scopes as VFS, Now Playing 2242 if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) { 2243 mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).getTotalNumOfItems(scope); 2244 } else { 2245 Log.e(TAG, "Could not get Total NumOfItems. mBrowsedMediaPlayer is null"); 2246 getTotalNumOfItemsRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR, 0, 0); 2247 } 2248 } 2249 2250 } 2251 2252 /* check if browsed player and addressed player are same */ 2253 private boolean isAddrPlayerSameAsBrowsed(byte[] bdaddr) { 2254 String browsedPlayer = getCurrentBrowsedPlayer(bdaddr); 2255 2256 if (!isPackageNameValid(browsedPlayer)) { 2257 Log.w(TAG, "Browsed player name empty"); 2258 return false; 2259 } 2260 2261 MediaPlayerInfo info = getAddressedPlayerInfo(); 2262 String packageName = (info == null) ? "<none>" : info.getPackageName(); 2263 if (info == null || !packageName.equals(browsedPlayer)) { 2264 if (DEBUG) Log.d(TAG, browsedPlayer + " is not addressed player " + packageName); 2265 return false; 2266 } 2267 return true; 2268 } 2269 2270 /* checks if package name is not null or empty */ 2271 private boolean isPackageNameValid(String browsedPackage) { 2272 boolean isValid = (browsedPackage != null && browsedPackage.length() > 0); 2273 if (DEBUG) Log.d(TAG, "isPackageNameValid: browsedPackage = " + browsedPackage + 2274 "isValid = " + isValid); 2275 return isValid; 2276 } 2277 2278 /* checks if selected addressed player is already addressed */ 2279 private boolean isPlayerAlreadyAddressed(int selectedId) { 2280 // checking if selected ID is same as the current addressed player id 2281 boolean isAddressed = (mCurrAddrPlayerID == selectedId); 2282 if (DEBUG) Log.d(TAG, "isPlayerAlreadyAddressed: isAddressed = " + isAddressed); 2283 return isAddressed; 2284 } 2285 2286 public void dump(StringBuilder sb) { 2287 sb.append("AVRCP:\n"); 2288 ProfileService.println(sb, "mMediaAttributes: " + mMediaAttributes.toRedactedString()); 2289 ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags); 2290 ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState); 2291 ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT); 2292 ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT); 2293 ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs); 2294 ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT); 2295 ProfileService.println(sb, "mNextPosMs: " + mNextPosMs); 2296 ProfileService.println(sb, "mPrevPosMs: " + mPrevPosMs); 2297 ProfileService.println(sb, "mFeatures: " + mFeatures); 2298 ProfileService.println(sb, "mRemoteVolume: " + mRemoteVolume); 2299 ProfileService.println(sb, "mLastRemoteVolume: " + mLastRemoteVolume); 2300 ProfileService.println(sb, "mLastDirection: " + mLastDirection); 2301 ProfileService.println(sb, "mVolumeStep: " + mVolumeStep); 2302 ProfileService.println(sb, "mAudioStreamMax: " + mAudioStreamMax); 2303 ProfileService.println(sb, "mVolCmdAdjustInProgress: " + mVolCmdAdjustInProgress); 2304 ProfileService.println(sb, "mVolCmdSetInProgress: " + mVolCmdSetInProgress); 2305 ProfileService.println(sb, "mAbsVolRetryTimes: " + mAbsVolRetryTimes); 2306 ProfileService.println(sb, "mVolumeMapping: " + mVolumeMapping.toString()); 2307 synchronized (this) { 2308 if (mMediaController != null) 2309 ProfileService.println(sb, "mMediaController: " 2310 + mMediaController.getWrappedInstance() + " pkg " 2311 + mMediaController.getPackageName()); 2312 } 2313 ProfileService.println(sb, ""); 2314 ProfileService.println(sb, "Media Players:"); 2315 synchronized (mMediaPlayerInfoList) { 2316 for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { 2317 int key = entry.getKey(); 2318 ProfileService.println(sb, ((mCurrAddrPlayerID == key) ? " *#" : " #") 2319 + entry.getKey() + ": " + entry.getValue()); 2320 } 2321 } 2322 2323 ProfileService.println(sb, ""); 2324 mAddressedMediaPlayer.dump(sb, mMediaController); 2325 2326 ProfileService.println(sb, ""); 2327 ProfileService.println(sb, mPassthroughDispatched + " passthrough operations: "); 2328 if (mPassthroughDispatched > mPassthroughLogs.size()) 2329 ProfileService.println(sb, " (last " + mPassthroughLogs.size() + ")"); 2330 synchronized (mPassthroughLogs) { 2331 for (MediaKeyLog log : mPassthroughLogs) { 2332 ProfileService.println(sb, " " + log); 2333 } 2334 } 2335 synchronized (mPassthroughPending) { 2336 for (MediaKeyLog log : mPassthroughPending) { 2337 ProfileService.println(sb, " " + log); 2338 } 2339 } 2340 } 2341 2342 public class AvrcpBrowseManager { 2343 Map<String, BrowsedMediaPlayer> connList = new HashMap<String, BrowsedMediaPlayer>(); 2344 private AvrcpMediaRspInterface mMediaInterface; 2345 private Context mContext; 2346 2347 public AvrcpBrowseManager(Context context, AvrcpMediaRspInterface mediaInterface) { 2348 mContext = context; 2349 mMediaInterface = mediaInterface; 2350 } 2351 2352 public void cleanup() { 2353 Iterator entries = connList.entrySet().iterator(); 2354 while (entries.hasNext()) { 2355 Map.Entry entry = (Map.Entry) entries.next(); 2356 BrowsedMediaPlayer browsedMediaPlayer = (BrowsedMediaPlayer) entry.getValue(); 2357 if (browsedMediaPlayer != null) { 2358 browsedMediaPlayer.cleanup(); 2359 } 2360 } 2361 // clean up the map 2362 connList.clear(); 2363 } 2364 2365 // get the a free media player interface based on the passed bd address 2366 // if the no items is found for the passed media player then it assignes a 2367 // available media player interface 2368 public BrowsedMediaPlayer getBrowsedMediaPlayer(byte[] bdaddr) { 2369 BrowsedMediaPlayer mediaPlayer; 2370 String bdaddrStr = new String(bdaddr); 2371 if (connList.containsKey(bdaddrStr)) { 2372 mediaPlayer = connList.get(bdaddrStr); 2373 } else { 2374 mediaPlayer = new BrowsedMediaPlayer(bdaddr, mContext, mMediaInterface); 2375 connList.put(bdaddrStr, mediaPlayer); 2376 } 2377 return mediaPlayer; 2378 } 2379 2380 // clears the details pertaining to passed bdaddres 2381 public boolean clearBrowsedMediaPlayer(byte[] bdaddr) { 2382 String bdaddrStr = new String(bdaddr); 2383 if (connList.containsKey(bdaddrStr)) { 2384 connList.remove(bdaddrStr); 2385 return true; 2386 } 2387 return false; 2388 } 2389 2390 public Map<String, BrowsedMediaPlayer> getConnList() { 2391 return connList; 2392 } 2393 2394 /* Helper function to convert colon separated bdaddr to byte string */ 2395 private byte[] hexStringToByteArray(String s) { 2396 int len = s.length(); 2397 byte[] data = new byte[len / 2]; 2398 for (int i = 0; i < len; i += 2) { 2399 data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) 2400 + Character.digit(s.charAt(i+1), 16)); 2401 } 2402 return data; 2403 } 2404 } 2405 2406 /* 2407 * private class which handles responses from AvrcpMediaManager. Maps responses to native 2408 * responses. This class implements the AvrcpMediaRspInterface interface. 2409 */ 2410 private class AvrcpMediaRsp implements AvrcpMediaRspInterface { 2411 private static final String TAG = "AvrcpMediaRsp"; 2412 2413 public void setAddrPlayerRsp(byte[] address, int rspStatus) { 2414 if (!setAddressedPlayerRspNative(address, rspStatus)) { 2415 Log.e(TAG, "setAddrPlayerRsp failed!"); 2416 } 2417 } 2418 2419 public void setBrowsedPlayerRsp(byte[] address, int rspStatus, byte depth, int numItems, 2420 String[] textArray) { 2421 if (!setBrowsedPlayerRspNative(address, rspStatus, depth, numItems, textArray)) { 2422 Log.e(TAG, "setBrowsedPlayerRsp failed!"); 2423 } 2424 } 2425 2426 public void mediaPlayerListRsp(byte[] address, int rspStatus, MediaPlayerListRsp rspObj) { 2427 if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) { 2428 if (!mediaPlayerListRspNative(address, rspStatus, sUIDCounter, rspObj.itemType, 2429 rspObj.mNumItems, rspObj.mPlayerIds, rspObj.mPlayerTypes, 2430 rspObj.mPlayerSubTypes, rspObj.mPlayStatusValues, 2431 rspObj.mFeatureBitMaskValues, rspObj.mPlayerNameList)) 2432 Log.e(TAG, "mediaPlayerListRsp failed!"); 2433 } else { 2434 Log.e(TAG, "mediaPlayerListRsp: rspObj is null"); 2435 if (!mediaPlayerListRspNative(address, rspStatus, sUIDCounter, (byte) 0x00, 0, null, 2436 null, null, null, null, null)) 2437 Log.e(TAG, "mediaPlayerListRsp failed!"); 2438 } 2439 } 2440 2441 public void folderItemsRsp(byte[] address, int rspStatus, FolderItemsRsp rspObj) { 2442 if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) { 2443 if (!getFolderItemsRspNative(address, rspStatus, sUIDCounter, rspObj.mScope, 2444 rspObj.mNumItems, rspObj.mFolderTypes, rspObj.mPlayable, rspObj.mItemTypes, 2445 rspObj.mItemUid, rspObj.mDisplayNames, rspObj.mAttributesNum, 2446 rspObj.mAttrIds, rspObj.mAttrValues)) 2447 Log.e(TAG, "getFolderItemsRspNative failed!"); 2448 } else { 2449 Log.e(TAG, "folderItemsRsp: rspObj is null or rspStatus is error:" + rspStatus); 2450 if (!getFolderItemsRspNative(address, rspStatus, sUIDCounter, (byte) 0x00, 0, 2451 null, null, null, null, null, null, null, null)) 2452 Log.e(TAG, "getFolderItemsRspNative failed!"); 2453 } 2454 2455 } 2456 2457 public void changePathRsp(byte[] address, int rspStatus, int numItems) { 2458 if (!changePathRspNative(address, rspStatus, numItems)) 2459 Log.e(TAG, "changePathRspNative failed!"); 2460 } 2461 2462 public void getItemAttrRsp(byte[] address, int rspStatus, ItemAttrRsp rspObj) { 2463 if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) { 2464 if (!getItemAttrRspNative(address, rspStatus, rspObj.mNumAttr, 2465 rspObj.mAttributesIds, rspObj.mAttributesArray)) 2466 Log.e(TAG, "getItemAttrRspNative failed!"); 2467 } else { 2468 Log.e(TAG, "getItemAttrRsp: rspObj is null or rspStatus is error:" + rspStatus); 2469 if (!getItemAttrRspNative(address, rspStatus, (byte) 0x00, null, null)) 2470 Log.e(TAG, "getItemAttrRspNative failed!"); 2471 } 2472 } 2473 2474 public void playItemRsp(byte[] address, int rspStatus) { 2475 if (!playItemRspNative(address, rspStatus)) { 2476 Log.e(TAG, "playItemRspNative failed!"); 2477 } 2478 } 2479 2480 public void getTotalNumOfItemsRsp(byte[] address, int rspStatus, int uidCounter, 2481 int numItems) { 2482 if (!getTotalNumOfItemsRspNative(address, rspStatus, sUIDCounter, numItems)) { 2483 Log.e(TAG, "getTotalNumOfItemsRspNative failed!"); 2484 } 2485 } 2486 2487 public void addrPlayerChangedRsp(int type, int playerId, int uidCounter) { 2488 if (!registerNotificationRspAddrPlayerChangedNative(type, playerId, sUIDCounter)) { 2489 Log.e(TAG, "registerNotificationRspAddrPlayerChangedNative failed!"); 2490 } 2491 } 2492 2493 public void avalPlayerChangedRsp(byte[] address, int type) { 2494 if (!registerNotificationRspAvalPlayerChangedNative(type)) { 2495 Log.e(TAG, "registerNotificationRspAvalPlayerChangedNative failed!"); 2496 } 2497 } 2498 2499 public void uidsChangedRsp(int type) { 2500 if (!registerNotificationRspUIDsChangedNative(type, sUIDCounter)) { 2501 Log.e(TAG, "registerNotificationRspUIDsChangedNative failed!"); 2502 } 2503 } 2504 2505 public void nowPlayingChangedRsp(int type) { 2506 if (!registerNotificationRspNowPlayingChangedNative(type)) { 2507 Log.e(TAG, "registerNotificationRspNowPlayingChangedNative failed!"); 2508 } 2509 } 2510 2511 public void trackChangedRsp(int type, byte[] uid) { 2512 if (!registerNotificationRspTrackChangeNative(type, uid)) { 2513 Log.e(TAG, "registerNotificationRspTrackChangeNative failed!"); 2514 } 2515 } 2516 } 2517 2518 /* getters for some private variables */ 2519 public AvrcpBrowseManager getAvrcpBrowseManager() { 2520 return mAvrcpBrowseManager; 2521 } 2522 2523 /* PASSTHROUGH COMMAND MANAGEMENT */ 2524 2525 void handlePassthroughCmd(int op, int state) { 2526 int code = avrcpPassthroughToKeyCode(op); 2527 if (code == KeyEvent.KEYCODE_UNKNOWN) { 2528 Log.w(TAG, "Ignoring passthrough of unknown key " + op + " state " + state); 2529 return; 2530 } 2531 int action = KeyEvent.ACTION_DOWN; 2532 if (state == AvrcpConstants.KEY_STATE_RELEASE) action = KeyEvent.ACTION_UP; 2533 KeyEvent event = new KeyEvent(action, code); 2534 if (!KeyEvent.isMediaKey(code)) { 2535 Log.w(TAG, "Passthrough non-media key " + op + " (code " + code + ") state " + state); 2536 } 2537 mMediaSessionManager.dispatchMediaKeyEvent(event); 2538 addKeyPending(event); 2539 } 2540 2541 private int avrcpPassthroughToKeyCode(int operation) { 2542 switch (operation) { 2543 case BluetoothAvrcp.PASSTHROUGH_ID_UP: 2544 return KeyEvent.KEYCODE_DPAD_UP; 2545 case BluetoothAvrcp.PASSTHROUGH_ID_DOWN: 2546 return KeyEvent.KEYCODE_DPAD_DOWN; 2547 case BluetoothAvrcp.PASSTHROUGH_ID_LEFT: 2548 return KeyEvent.KEYCODE_DPAD_LEFT; 2549 case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT: 2550 return KeyEvent.KEYCODE_DPAD_RIGHT; 2551 case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT_UP: 2552 return KeyEvent.KEYCODE_DPAD_UP_RIGHT; 2553 case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT_DOWN: 2554 return KeyEvent.KEYCODE_DPAD_DOWN_RIGHT; 2555 case BluetoothAvrcp.PASSTHROUGH_ID_LEFT_UP: 2556 return KeyEvent.KEYCODE_DPAD_UP_LEFT; 2557 case BluetoothAvrcp.PASSTHROUGH_ID_LEFT_DOWN: 2558 return KeyEvent.KEYCODE_DPAD_DOWN_LEFT; 2559 case BluetoothAvrcp.PASSTHROUGH_ID_0: 2560 return KeyEvent.KEYCODE_NUMPAD_0; 2561 case BluetoothAvrcp.PASSTHROUGH_ID_1: 2562 return KeyEvent.KEYCODE_NUMPAD_1; 2563 case BluetoothAvrcp.PASSTHROUGH_ID_2: 2564 return KeyEvent.KEYCODE_NUMPAD_2; 2565 case BluetoothAvrcp.PASSTHROUGH_ID_3: 2566 return KeyEvent.KEYCODE_NUMPAD_3; 2567 case BluetoothAvrcp.PASSTHROUGH_ID_4: 2568 return KeyEvent.KEYCODE_NUMPAD_4; 2569 case BluetoothAvrcp.PASSTHROUGH_ID_5: 2570 return KeyEvent.KEYCODE_NUMPAD_5; 2571 case BluetoothAvrcp.PASSTHROUGH_ID_6: 2572 return KeyEvent.KEYCODE_NUMPAD_6; 2573 case BluetoothAvrcp.PASSTHROUGH_ID_7: 2574 return KeyEvent.KEYCODE_NUMPAD_7; 2575 case BluetoothAvrcp.PASSTHROUGH_ID_8: 2576 return KeyEvent.KEYCODE_NUMPAD_8; 2577 case BluetoothAvrcp.PASSTHROUGH_ID_9: 2578 return KeyEvent.KEYCODE_NUMPAD_9; 2579 case BluetoothAvrcp.PASSTHROUGH_ID_DOT: 2580 return KeyEvent.KEYCODE_NUMPAD_DOT; 2581 case BluetoothAvrcp.PASSTHROUGH_ID_ENTER: 2582 return KeyEvent.KEYCODE_NUMPAD_ENTER; 2583 case BluetoothAvrcp.PASSTHROUGH_ID_CLEAR: 2584 return KeyEvent.KEYCODE_CLEAR; 2585 case BluetoothAvrcp.PASSTHROUGH_ID_CHAN_UP: 2586 return KeyEvent.KEYCODE_CHANNEL_UP; 2587 case BluetoothAvrcp.PASSTHROUGH_ID_CHAN_DOWN: 2588 return KeyEvent.KEYCODE_CHANNEL_DOWN; 2589 case BluetoothAvrcp.PASSTHROUGH_ID_PREV_CHAN: 2590 return KeyEvent.KEYCODE_LAST_CHANNEL; 2591 case BluetoothAvrcp.PASSTHROUGH_ID_INPUT_SEL: 2592 return KeyEvent.KEYCODE_TV_INPUT; 2593 case BluetoothAvrcp.PASSTHROUGH_ID_DISP_INFO: 2594 return KeyEvent.KEYCODE_INFO; 2595 case BluetoothAvrcp.PASSTHROUGH_ID_HELP: 2596 return KeyEvent.KEYCODE_HELP; 2597 case BluetoothAvrcp.PASSTHROUGH_ID_PAGE_UP: 2598 return KeyEvent.KEYCODE_PAGE_UP; 2599 case BluetoothAvrcp.PASSTHROUGH_ID_PAGE_DOWN: 2600 return KeyEvent.KEYCODE_PAGE_DOWN; 2601 case BluetoothAvrcp.PASSTHROUGH_ID_POWER: 2602 return KeyEvent.KEYCODE_POWER; 2603 case BluetoothAvrcp.PASSTHROUGH_ID_VOL_UP: 2604 return KeyEvent.KEYCODE_VOLUME_UP; 2605 case BluetoothAvrcp.PASSTHROUGH_ID_VOL_DOWN: 2606 return KeyEvent.KEYCODE_VOLUME_DOWN; 2607 case BluetoothAvrcp.PASSTHROUGH_ID_MUTE: 2608 return KeyEvent.KEYCODE_MUTE; 2609 case BluetoothAvrcp.PASSTHROUGH_ID_PLAY: 2610 return KeyEvent.KEYCODE_MEDIA_PLAY; 2611 case BluetoothAvrcp.PASSTHROUGH_ID_STOP: 2612 return KeyEvent.KEYCODE_MEDIA_STOP; 2613 case BluetoothAvrcp.PASSTHROUGH_ID_PAUSE: 2614 return KeyEvent.KEYCODE_MEDIA_PAUSE; 2615 case BluetoothAvrcp.PASSTHROUGH_ID_RECORD: 2616 return KeyEvent.KEYCODE_MEDIA_RECORD; 2617 case BluetoothAvrcp.PASSTHROUGH_ID_REWIND: 2618 return KeyEvent.KEYCODE_MEDIA_REWIND; 2619 case BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR: 2620 return KeyEvent.KEYCODE_MEDIA_FAST_FORWARD; 2621 case BluetoothAvrcp.PASSTHROUGH_ID_EJECT: 2622 return KeyEvent.KEYCODE_MEDIA_EJECT; 2623 case BluetoothAvrcp.PASSTHROUGH_ID_FORWARD: 2624 return KeyEvent.KEYCODE_MEDIA_NEXT; 2625 case BluetoothAvrcp.PASSTHROUGH_ID_BACKWARD: 2626 return KeyEvent.KEYCODE_MEDIA_PREVIOUS; 2627 case BluetoothAvrcp.PASSTHROUGH_ID_F1: 2628 return KeyEvent.KEYCODE_F1; 2629 case BluetoothAvrcp.PASSTHROUGH_ID_F2: 2630 return KeyEvent.KEYCODE_F2; 2631 case BluetoothAvrcp.PASSTHROUGH_ID_F3: 2632 return KeyEvent.KEYCODE_F3; 2633 case BluetoothAvrcp.PASSTHROUGH_ID_F4: 2634 return KeyEvent.KEYCODE_F4; 2635 case BluetoothAvrcp.PASSTHROUGH_ID_F5: 2636 return KeyEvent.KEYCODE_F5; 2637 // Fallthrough for all unknown key mappings 2638 case BluetoothAvrcp.PASSTHROUGH_ID_SELECT: 2639 case BluetoothAvrcp.PASSTHROUGH_ID_ROOT_MENU: 2640 case BluetoothAvrcp.PASSTHROUGH_ID_SETUP_MENU: 2641 case BluetoothAvrcp.PASSTHROUGH_ID_CONT_MENU: 2642 case BluetoothAvrcp.PASSTHROUGH_ID_FAV_MENU: 2643 case BluetoothAvrcp.PASSTHROUGH_ID_EXIT: 2644 case BluetoothAvrcp.PASSTHROUGH_ID_SOUND_SEL: 2645 case BluetoothAvrcp.PASSTHROUGH_ID_ANGLE: 2646 case BluetoothAvrcp.PASSTHROUGH_ID_SUBPICT: 2647 case BluetoothAvrcp.PASSTHROUGH_ID_VENDOR: 2648 default: 2649 return KeyEvent.KEYCODE_UNKNOWN; 2650 } 2651 } 2652 2653 private void addKeyPending(KeyEvent event) { 2654 mPassthroughPending.add(new MediaKeyLog(System.currentTimeMillis(), event)); 2655 } 2656 2657 private void recordKeyDispatched(KeyEvent event, String packageName) { 2658 long time = System.currentTimeMillis(); 2659 Log.v(TAG, "recordKeyDispatched: " + event + " dispatched to " + packageName); 2660 setAddressedMediaSessionPackage(packageName); 2661 synchronized (mPassthroughPending) { 2662 Iterator<MediaKeyLog> pending = mPassthroughPending.iterator(); 2663 while (pending.hasNext()) { 2664 MediaKeyLog log = pending.next(); 2665 if (log.addDispatch(time, event, packageName)) { 2666 mPassthroughDispatched++; 2667 mPassthroughLogs.add(log); 2668 pending.remove(); 2669 return; 2670 } 2671 } 2672 Log.w(TAG, "recordKeyDispatch: can't find matching log!"); 2673 } 2674 } 2675 2676 private final MediaSessionManager.Callback mButtonDispatchCallback = 2677 new MediaSessionManager.Callback() { 2678 @Override 2679 public void onMediaKeyEventDispatched(KeyEvent event, MediaSession.Token token) { 2680 // Get the package name 2681 android.media.session.MediaController controller = 2682 new android.media.session.MediaController(mContext, token); 2683 String targetPackage = controller.getPackageName(); 2684 recordKeyDispatched(event, targetPackage); 2685 } 2686 2687 @Override 2688 public void onMediaKeyEventDispatched(KeyEvent event, ComponentName receiver) { 2689 recordKeyDispatched(event, receiver.getPackageName()); 2690 } 2691 2692 @Override 2693 public void onAddressedPlayerChanged(MediaSession.Token token) { 2694 setActiveMediaSession(token); 2695 } 2696 2697 @Override 2698 public void onAddressedPlayerChanged(ComponentName receiver) { 2699 if (receiver == null) { 2700 // No active sessions, and no session to revive, give up. 2701 setAddressedMediaSessionPackage(null); 2702 return; 2703 } 2704 // We can still get a passthrough which will revive this player. 2705 setAddressedMediaSessionPackage(receiver.getPackageName()); 2706 } 2707 }; 2708 2709 // Do not modify without updating the HAL bt_rc.h files. 2710 2711 // match up with btrc_play_status_t enum of bt_rc.h 2712 final static byte PLAYSTATUS_STOPPED = 0; 2713 final static byte PLAYSTATUS_PLAYING = 1; 2714 final static byte PLAYSTATUS_PAUSED = 2; 2715 final static byte PLAYSTATUS_FWD_SEEK = 3; 2716 final static byte PLAYSTATUS_REV_SEEK = 4; 2717 final static byte PLAYSTATUS_ERROR = (byte) 255; 2718 2719 // match up with btrc_media_attr_t enum of bt_rc.h 2720 final static int MEDIA_ATTR_TITLE = 1; 2721 final static int MEDIA_ATTR_ARTIST = 2; 2722 final static int MEDIA_ATTR_ALBUM = 3; 2723 final static int MEDIA_ATTR_TRACK_NUM = 4; 2724 final static int MEDIA_ATTR_NUM_TRACKS = 5; 2725 final static int MEDIA_ATTR_GENRE = 6; 2726 final static int MEDIA_ATTR_PLAYING_TIME = 7; 2727 2728 // match up with btrc_event_id_t enum of bt_rc.h 2729 final static int EVT_PLAY_STATUS_CHANGED = 1; 2730 final static int EVT_TRACK_CHANGED = 2; 2731 final static int EVT_TRACK_REACHED_END = 3; 2732 final static int EVT_TRACK_REACHED_START = 4; 2733 final static int EVT_PLAY_POS_CHANGED = 5; 2734 final static int EVT_BATT_STATUS_CHANGED = 6; 2735 final static int EVT_SYSTEM_STATUS_CHANGED = 7; 2736 final static int EVT_APP_SETTINGS_CHANGED = 8; 2737 final static int EVENT_NOW_PLAYING_CONTENT_CHANGED = 9; 2738 final static int EVT_AVBL_PLAYERS_CHANGED = 0xa; 2739 final static int EVT_ADDR_PLAYER_CHANGED = 0xb; 2740 final static int EVENT_UIDS_CHANGED = 0x0c; 2741 2742 private native static void classInitNative(); 2743 private native void initNative(); 2744 private native void cleanupNative(); 2745 private native boolean getPlayStatusRspNative(byte[] address, int playStatus, int songLen, 2746 int songPos); 2747 private native boolean getElementAttrRspNative(byte[] address, byte numAttr, int[] attrIds, 2748 String[] textArray); 2749 private native boolean registerNotificationRspPlayStatusNative(int type, int playStatus); 2750 private native boolean registerNotificationRspTrackChangeNative(int type, byte[] track); 2751 private native boolean registerNotificationRspPlayPosNative(int type, int playPos); 2752 private native boolean setVolumeNative(int volume); 2753 private native boolean sendPassThroughCommandNative(int keyCode, int keyState); 2754 private native boolean setAddressedPlayerRspNative(byte[] address, int rspStatus); 2755 private native boolean setBrowsedPlayerRspNative(byte[] address, int rspStatus, byte depth, 2756 int numItems, String[] textArray); 2757 private native boolean mediaPlayerListRspNative(byte[] address, int rsStatus, int uidCounter, 2758 byte item_type, int numItems, int[] playerIds, byte[] playerTypes, int[] playerSubTypes, 2759 byte[] playStatusValues, short[] featureBitMaskValues, String[] textArray); 2760 private native boolean getFolderItemsRspNative(byte[] address, int rspStatus, short uidCounter, 2761 byte scope, int numItems, byte[] folderTypes, byte[] playable, byte[] itemTypes, 2762 byte[] itemUidArray, String[] textArray, int[] AttributesNum, int[] AttributesIds, 2763 String[] attributesArray); 2764 private native boolean changePathRspNative(byte[] address, int rspStatus, int numItems); 2765 private native boolean getItemAttrRspNative(byte[] address, int rspStatus, byte numAttr, 2766 int[] attrIds, String[] textArray); 2767 private native boolean playItemRspNative(byte[] address, int rspStatus); 2768 private native boolean getTotalNumOfItemsRspNative(byte[] address, int rspStatus, 2769 int uidCounter, int numItems); 2770 private native boolean searchRspNative(byte[] address, int rspStatus, int uidCounter, 2771 int numItems); 2772 private native boolean addToNowPlayingRspNative(byte[] address, int rspStatus); 2773 private native boolean registerNotificationRspAddrPlayerChangedNative(int type, 2774 int playerId, int uidCounter); 2775 private native boolean registerNotificationRspAvalPlayerChangedNative(int type); 2776 private native boolean registerNotificationRspUIDsChangedNative(int type, int uidCounter); 2777 private native boolean registerNotificationRspNowPlayingChangedNative(int type); 2778 2779 } 2780