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