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