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