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