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