Avrcp.java revision 0f9c79e8afa3e575dfd8c80c2c58b9321e18898d
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 AvrcpCmd.FolderItemsCmd folderObj = (AvrcpCmd.FolderItemsCmd) msg.obj; 707 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_FOLDER_ITEMS " + folderObj); 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 AvrcpCmd.ItemAttrCmd cmd = (AvrcpCmd.ItemAttrCmd) msg.obj; 735 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_ITEM_ATTR " + cmd); 736 handleGetItemAttr(cmd); 737 break; 738 739 case MSG_NATIVE_REQ_SET_BR_PLAYER: 740 // argument 1 is the selected player id 741 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_SET_BR_PLAYER id=" + msg.arg1); 742 setBrowsedPlayer((byte[]) msg.obj, msg.arg1); 743 break; 744 745 case MSG_NATIVE_REQ_CHANGE_PATH: 746 { 747 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_CHANGE_PATH"); 748 Bundle data = msg.getData(); 749 byte[] bdaddr = data.getByteArray("BdAddress"); 750 byte[] folderUid = data.getByteArray("folderUid"); 751 byte direction = data.getByte("direction"); 752 if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) { 753 mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).changePath(folderUid, 754 direction); 755 } else { 756 Log.e(TAG, "Remote requesting change path before setbrowsedplayer"); 757 changePathRspNative(bdaddr, AvrcpConstants.RSP_BAD_CMD, 0); 758 } 759 break; 760 } 761 762 case MSG_NATIVE_REQ_PLAY_ITEM: 763 { 764 Bundle data = msg.getData(); 765 byte[] bdaddr = data.getByteArray("BdAddress"); 766 byte[] uid = data.getByteArray("uid"); 767 byte scope = data.getByte("scope"); 768 if (DEBUG) 769 Log.v(TAG, "MSG_NATIVE_REQ_PLAY_ITEM scope=" + scope + " id=" 770 + Utils.byteArrayToString(uid)); 771 handlePlayItemResponse(bdaddr, uid, scope); 772 break; 773 } 774 775 case MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS: 776 if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS scope=" + msg.arg1); 777 // argument 1 is scope, object is bdaddr 778 handleGetTotalNumOfItemsResponse((byte[]) msg.obj, (byte) msg.arg1); 779 break; 780 781 case MSG_NATIVE_REQ_PASS_THROUGH: 782 if (DEBUG) 783 Log.v(TAG, "MSG_NATIVE_REQ_PASS_THROUGH: id=" + msg.arg1 + " st=" + msg.arg2); 784 // argument 1 is id, argument 2 is keyState 785 handlePassthroughCmd(msg.arg1, msg.arg2); 786 break; 787 788 default: 789 Log.e(TAG, "unknown message! msg.what=" + msg.what); 790 break; 791 } 792 } 793 } 794 795 private void updateA2dpAudioState(int state) { 796 boolean isPlaying = (state == BluetoothA2dp.STATE_PLAYING); 797 if (isPlaying != isPlayingState(mCurrentPlayState)) { 798 /* if a2dp is streaming, check to make sure music is active */ 799 if (isPlaying && !mAudioManager.isMusicActive()) 800 return; 801 PlaybackState.Builder builder = new PlaybackState.Builder(); 802 if (isPlaying) { 803 builder.setState(PlaybackState.STATE_PLAYING, 804 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f); 805 } else { 806 builder.setState(PlaybackState.STATE_PAUSED, 807 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f); 808 } 809 updatePlaybackState(builder.build()); 810 } 811 } 812 813 private void updatePlaybackState(PlaybackState state) { 814 if (state == null) { 815 state = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, 816 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build(); 817 } 818 819 int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState); 820 int newPlayStatus = convertPlayStateToPlayStatus(state); 821 822 if (DEBUG) { 823 Log.v(TAG, "updatePlaybackState (" + mPlayStatusChangedNT + "): "+ 824 "old=" + mCurrentPlayState + "(" + oldPlayStatus + "), "+ 825 "new=" + state + "(" + newPlayStatus + ")"); 826 } 827 828 mCurrentPlayState = state; 829 mLastStateUpdate = SystemClock.elapsedRealtime(); 830 831 sendPlayPosNotificationRsp(false); 832 833 if (mPlayStatusChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM && 834 (oldPlayStatus != newPlayStatus)) { 835 mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 836 registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, newPlayStatus); 837 } 838 } 839 840 private void updateTransportControls(int transportControlFlags) { 841 mTransportControlFlags = transportControlFlags; 842 } 843 844 class MediaAttributes { 845 private boolean exists; 846 private String title; 847 private String artistName; 848 private String albumName; 849 private String mediaNumber; 850 private String mediaTotalNumber; 851 private String genre; 852 private String playingTimeMs; 853 854 private static final int ATTR_TITLE = 1; 855 private static final int ATTR_ARTIST_NAME = 2; 856 private static final int ATTR_ALBUM_NAME = 3; 857 private static final int ATTR_MEDIA_NUMBER = 4; 858 private static final int ATTR_MEDIA_TOTAL_NUMBER = 5; 859 private static final int ATTR_GENRE = 6; 860 private static final int ATTR_PLAYING_TIME_MS = 7; 861 862 863 public MediaAttributes(MediaMetadata data) { 864 exists = data != null; 865 if (!exists) 866 return; 867 868 artistName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ARTIST)); 869 albumName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ALBUM)); 870 mediaNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER)); 871 mediaTotalNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS)); 872 genre = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_GENRE)); 873 playingTimeMs = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_DURATION)); 874 875 // Try harder for the title. 876 title = data.getString(MediaMetadata.METADATA_KEY_TITLE); 877 878 if (title == null) { 879 MediaDescription desc = data.getDescription(); 880 if (desc != null) { 881 CharSequence val = desc.getDescription(); 882 if (val != null) 883 title = val.toString(); 884 } 885 } 886 887 if (title == null) 888 title = new String(); 889 } 890 891 public boolean equals(MediaAttributes other) { 892 if (other == null) 893 return false; 894 895 if (exists != other.exists) 896 return false; 897 898 if (exists == false) 899 return true; 900 901 return (title.equals(other.title)) && 902 (artistName.equals(other.artistName)) && 903 (albumName.equals(other.albumName)) && 904 (mediaNumber.equals(other.mediaNumber)) && 905 (mediaTotalNumber.equals(other.mediaTotalNumber)) && 906 (genre.equals(other.genre)) && 907 (playingTimeMs.equals(other.playingTimeMs)); 908 } 909 910 public String getString(int attrId) { 911 if (!exists) 912 return new String(); 913 914 switch (attrId) { 915 case ATTR_TITLE: 916 return title; 917 case ATTR_ARTIST_NAME: 918 return artistName; 919 case ATTR_ALBUM_NAME: 920 return albumName; 921 case ATTR_MEDIA_NUMBER: 922 return mediaNumber; 923 case ATTR_MEDIA_TOTAL_NUMBER: 924 return mediaTotalNumber; 925 case ATTR_GENRE: 926 return genre; 927 case ATTR_PLAYING_TIME_MS: 928 return playingTimeMs; 929 default: 930 return new String(); 931 } 932 } 933 934 private String stringOrBlank(String s) { 935 return s == null ? new String() : s; 936 } 937 938 private String longStringOrBlank(Long s) { 939 return s == null ? new String() : s.toString(); 940 } 941 942 public String toString() { 943 if (!exists) { 944 return "[MediaAttributes: none]"; 945 } 946 947 return "[MediaAttributes: " + title + " - " + albumName + " by " 948 + artistName + " (" + mediaNumber + "/" + mediaTotalNumber + ") " 949 + genre + "]"; 950 } 951 } 952 953 private void updateMetadata(MediaMetadata data) { 954 MediaAttributes oldAttributes = mMediaAttributes; 955 mMediaAttributes = new MediaAttributes(data); 956 if (data == null) { 957 mSongLengthMs = 0L; 958 } else { 959 mSongLengthMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION); 960 } 961 962 if (!oldAttributes.equals(mMediaAttributes)) { 963 Log.v(TAG, "MediaAttributes Changed to " + mMediaAttributes.toString()); 964 mTracksPlayed++; 965 966 if (mTrackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM) { 967 mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 968 sendTrackChangedRsp(); 969 } 970 } else { 971 Log.v(TAG, "Updated " + mMediaAttributes.toString() + " but no change!"); 972 } 973 974 // Update the play state, which sends play state and play position 975 // notifications if needed. 976 if (mMediaController != null) { 977 updatePlaybackState(mMediaController.getPlaybackState()); 978 } else { 979 updatePlaybackState(null); 980 } 981 } 982 983 private void getRcFeaturesRequestFromNative(byte[] address, int features) { 984 if (DEBUG) Log.v(TAG, "getRcFeaturesRequestFromNative: address=" + address.toString()); 985 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_RC_FEATURES, features, 0, 986 Utils.getAddressStringFromByte(address)); 987 mHandler.sendMessage(msg); 988 } 989 990 private void getPlayStatusRequestFromNative(byte[] address) { 991 if (DEBUG) Log.v(TAG, "getPlayStatusRequestFromNative: address" + address.toString()); 992 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_PLAY_STATUS); 993 msg.obj = address; 994 mHandler.sendMessage(msg); 995 } 996 997 private void getElementAttrRequestFromNative(byte[] address, byte numAttr, int[] attrs) { 998 if (DEBUG) Log.v(TAG, "getElementAttrRequestFromNative: numAttr=" + numAttr); 999 AvrcpCmd avrcpCmdobj = new AvrcpCmd(); 1000 AvrcpCmd.ElementAttrCmd elemAttr = avrcpCmdobj.new ElementAttrCmd(address, numAttr, attrs); 1001 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_ELEM_ATTRS); 1002 msg.obj = elemAttr; 1003 mHandler.sendMessage(msg); 1004 } 1005 1006 private void registerNotificationRequestFromNative(byte[] address,int eventId, int param) { 1007 if (DEBUG) Log.v(TAG, "registerNotificationRequestFromNative: eventId=" + eventId); 1008 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_REGISTER_NOTIFICATION, eventId, param); 1009 msg.obj = address; 1010 mHandler.sendMessage(msg); 1011 } 1012 1013 private void processRegisterNotification(byte[] address, int eventId, int param) { 1014 switch (eventId) { 1015 case EVT_PLAY_STATUS_CHANGED: 1016 mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; 1017 registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, 1018 convertPlayStateToPlayStatus(mCurrentPlayState)); 1019 break; 1020 1021 case EVT_TRACK_CHANGED: 1022 Log.v(TAG, "Track changed notification enabled"); 1023 mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; 1024 sendTrackChangedRsp(); 1025 break; 1026 1027 case EVT_PLAY_POS_CHANGED: 1028 mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM; 1029 mPlaybackIntervalMs = (long) param * 1000L; 1030 sendPlayPosNotificationRsp(true); 1031 break; 1032 1033 case EVT_AVBL_PLAYERS_CHANGED: 1034 /* Notify remote available players changed */ 1035 if (DEBUG) Log.d (TAG, "sending availablePlayersChanged to remote "); 1036 registerNotificationRspAvalPlayerChangedNative( 1037 AvrcpConstants.NOTIFICATION_TYPE_INTERIM); 1038 break; 1039 1040 case EVT_ADDR_PLAYER_CHANGED: 1041 /* Notify remote addressed players changed */ 1042 if (DEBUG) Log.d (TAG, "sending addressedPlayersChanged to remote "); 1043 registerNotificationRspAddrPlayerChangedNative( 1044 AvrcpConstants.NOTIFICATION_TYPE_INTERIM, 1045 mCurrAddrPlayerID, sUIDCounter); 1046 break; 1047 1048 case EVENT_UIDS_CHANGED: 1049 if (DEBUG) Log.d(TAG, "sending UIDs changed to remote"); 1050 registerNotificationRspUIDsChangedNative( 1051 AvrcpConstants.NOTIFICATION_TYPE_INTERIM, sUIDCounter); 1052 break; 1053 1054 case EVENT_NOW_PLAYING_CONTENT_CHANGED: 1055 if (DEBUG) Log.d(TAG, "sending NowPlayingList changed to remote"); 1056 /* send interim response to remote device */ 1057 if (!registerNotificationRspNowPlayingChangedNative( 1058 AvrcpConstants.NOTIFICATION_TYPE_INTERIM)) { 1059 Log.e(TAG, "EVENT_NOW_PLAYING_CONTENT_CHANGED: " + 1060 "registerNotificationRspNowPlayingChangedNative for Interim rsp failed!"); 1061 } 1062 break; 1063 } 1064 } 1065 1066 private void handlePassthroughCmdRequestFromNative(byte[] address, int id, int keyState) { 1067 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_PASS_THROUGH, id, keyState); 1068 mHandler.sendMessage(msg); 1069 } 1070 1071 private void sendTrackChangedRsp() { 1072 MediaPlayerInfo info = getAddressedPlayerInfo(); 1073 if (info != null && !info.isBrowseSupported()) { 1074 // for players which does not support Browse or when no track is currently selected 1075 trackChangeRspForBrowseUnsupported(); 1076 } else { 1077 // for players which support browsing 1078 mAddressedMediaPlayer.sendTrackChangeWithId(mTrackChangedNT, mMediaController); 1079 } 1080 } 1081 1082 private void trackChangeRspForBrowseUnsupported() { 1083 byte[] track = AvrcpConstants.TRACK_IS_SELECTED; 1084 if (mTrackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM 1085 && !mMediaAttributes.exists) { 1086 track = AvrcpConstants.NO_TRACK_SELECTED; 1087 } 1088 registerNotificationRspTrackChangeNative(mTrackChangedNT, track); 1089 } 1090 1091 private long getPlayPosition() { 1092 if (mCurrentPlayState == null) { 1093 return -1L; 1094 } 1095 1096 if (mCurrentPlayState.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN) { 1097 return -1L; 1098 } 1099 1100 if (isPlayingState(mCurrentPlayState)) { 1101 return SystemClock.elapsedRealtime() - mLastStateUpdate + mCurrentPlayState.getPosition(); 1102 } 1103 1104 return mCurrentPlayState.getPosition(); 1105 } 1106 1107 private int convertPlayStateToPlayStatus(PlaybackState state) { 1108 int playStatus = PLAYSTATUS_ERROR; 1109 switch (state.getState()) { 1110 case PlaybackState.STATE_PLAYING: 1111 case PlaybackState.STATE_BUFFERING: 1112 playStatus = PLAYSTATUS_PLAYING; 1113 break; 1114 1115 case PlaybackState.STATE_STOPPED: 1116 case PlaybackState.STATE_NONE: 1117 playStatus = PLAYSTATUS_STOPPED; 1118 break; 1119 1120 case PlaybackState.STATE_PAUSED: 1121 playStatus = PLAYSTATUS_PAUSED; 1122 break; 1123 1124 case PlaybackState.STATE_FAST_FORWARDING: 1125 case PlaybackState.STATE_SKIPPING_TO_NEXT: 1126 case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM: 1127 playStatus = PLAYSTATUS_FWD_SEEK; 1128 break; 1129 1130 case PlaybackState.STATE_REWINDING: 1131 case PlaybackState.STATE_SKIPPING_TO_PREVIOUS: 1132 playStatus = PLAYSTATUS_REV_SEEK; 1133 break; 1134 1135 case PlaybackState.STATE_ERROR: 1136 playStatus = PLAYSTATUS_ERROR; 1137 break; 1138 1139 } 1140 return playStatus; 1141 } 1142 1143 private boolean isPlayingState(PlaybackState state) { 1144 return (state.getState() == PlaybackState.STATE_PLAYING) || 1145 (state.getState() == PlaybackState.STATE_BUFFERING); 1146 } 1147 1148 /** 1149 * Sends a play position notification, or schedules one to be 1150 * sent later at an appropriate time. If |requested| is true, 1151 * does both because this was called in reponse to a request from the 1152 * TG. 1153 */ 1154 private void sendPlayPosNotificationRsp(boolean requested) { 1155 if (!requested && mPlayPosChangedNT != AvrcpConstants.NOTIFICATION_TYPE_INTERIM) { 1156 if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: Not registered or requesting."); 1157 return; 1158 } 1159 1160 long playPositionMs = getPlayPosition(); 1161 1162 // mNextPosMs is set to -1 when the previous position was invalid 1163 // so this will be true if the new position is valid & old was invalid. 1164 // mPlayPositionMs is set to -1 when the new position is invalid, 1165 // and the old mPrevPosMs is >= 0 so this is true when the new is invalid 1166 // and the old was valid. 1167 if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: (" + requested + ") " 1168 + mPrevPosMs + " <=? " + playPositionMs + " <=? " + mNextPosMs); 1169 if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: currentPlayState " + mCurrentPlayState); 1170 if (requested || ((mLastReportedPosition != playPositionMs) && 1171 (playPositionMs >= mNextPosMs) || (playPositionMs <= mPrevPosMs))) { 1172 if (!requested) mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED; 1173 registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int) playPositionMs); 1174 mLastReportedPosition = playPositionMs; 1175 if (playPositionMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) { 1176 mNextPosMs = playPositionMs + mPlaybackIntervalMs; 1177 mPrevPosMs = playPositionMs - mPlaybackIntervalMs; 1178 } else { 1179 mNextPosMs = -1; 1180 mPrevPosMs = -1; 1181 } 1182 } 1183 1184 mHandler.removeMessages(MSG_PLAY_INTERVAL_TIMEOUT); 1185 if (mPlayPosChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM && isPlayingState(mCurrentPlayState)) { 1186 Message msg = mHandler.obtainMessage(MSG_PLAY_INTERVAL_TIMEOUT); 1187 long delay = mPlaybackIntervalMs; 1188 if (mNextPosMs != -1) { 1189 delay = mNextPosMs - (playPositionMs > 0 ? playPositionMs : 0); 1190 } 1191 if (DEBUG) Log.d(TAG, "PLAY_INTERVAL_TIMEOUT set for " + delay + "ms from now"); 1192 mHandler.sendMessageDelayed(msg, delay); 1193 } 1194 } 1195 1196 /** 1197 * This is called from AudioService. It will return whether this device supports abs volume. 1198 * NOT USED AT THE MOMENT. 1199 */ 1200 public boolean isAbsoluteVolumeSupported() { 1201 return ((mFeatures & BTRC_FEAT_ABSOLUTE_VOLUME) != 0); 1202 } 1203 1204 /** 1205 * We get this call from AudioService. This will send a message to our handler object, 1206 * requesting our handler to call setVolumeNative() 1207 */ 1208 public void adjustVolume(int direction) { 1209 Message msg = mHandler.obtainMessage(MSG_ADJUST_VOLUME, direction, 0); 1210 mHandler.sendMessage(msg); 1211 } 1212 1213 public void setAbsoluteVolume(int volume) { 1214 if (volume == mLocalVolume) { 1215 if (DEBUG) Log.v(TAG, "setAbsoluteVolume is setting same index, ignore "+volume); 1216 return; 1217 } 1218 1219 mHandler.removeMessages(MSG_ADJUST_VOLUME); 1220 Message msg = mHandler.obtainMessage(MSG_SET_ABSOLUTE_VOLUME, volume, 0); 1221 mHandler.sendMessage(msg); 1222 } 1223 1224 /* Called in the native layer as a btrc_callback to return the volume set on the carkit in the 1225 * case when the volume is change locally on the carkit. This notification is not called when 1226 * the volume is changed from the phone. 1227 * 1228 * This method will send a message to our handler to change the local stored volume and notify 1229 * AudioService to update the UI 1230 */ 1231 private void volumeChangeRequestFromNative(byte[] address, int volume, int ctype) { 1232 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_VOLUME_CHANGE, volume, ctype); 1233 Bundle data = new Bundle(); 1234 data.putByteArray("BdAddress" , address); 1235 msg.setData(data); 1236 mHandler.sendMessage(msg); 1237 } 1238 1239 private void getFolderItemsRequestFromNative( 1240 byte[] address, byte scope, long startItem, long endItem, byte numAttr, int[] attrIds) { 1241 if (DEBUG) Log.v(TAG, "getFolderItemsRequestFromNative: scope=" + scope + ", numAttr=" + numAttr); 1242 AvrcpCmd avrcpCmdobj = new AvrcpCmd(); 1243 AvrcpCmd.FolderItemsCmd folderObj = avrcpCmdobj.new FolderItemsCmd(address, scope, 1244 startItem, endItem, numAttr, attrIds); 1245 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_FOLDER_ITEMS, 0, 0); 1246 msg.obj = folderObj; 1247 mHandler.sendMessage(msg); 1248 } 1249 1250 private void setAddressedPlayerRequestFromNative(byte[] address, int playerId) { 1251 if (DEBUG) Log.v(TAG, "setAddrPlayerRequestFromNative: playerId=" + playerId); 1252 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_SET_ADDR_PLAYER, playerId, 0); 1253 msg.obj = address; 1254 mHandler.sendMessage(msg); 1255 } 1256 1257 private void setBrowsedPlayerRequestFromNative(byte[] address, int playerId) { 1258 if (DEBUG) Log.v(TAG, "setBrPlayerRequestFromNative: playerId=" + playerId); 1259 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_SET_BR_PLAYER, playerId, 0); 1260 msg.obj = address; 1261 mHandler.sendMessage(msg); 1262 } 1263 1264 private void changePathRequestFromNative(byte[] address, byte direction, byte[] folderUid) { 1265 if (DEBUG) Log.v(TAG, "changePathRequestFromNative: direction=" + direction); 1266 Bundle data = new Bundle(); 1267 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_CHANGE_PATH); 1268 data.putByteArray("BdAddress" , address); 1269 data.putByteArray("folderUid" , folderUid); 1270 data.putByte("direction" , direction); 1271 msg.setData(data); 1272 mHandler.sendMessage(msg); 1273 } 1274 1275 private void getItemAttrRequestFromNative(byte[] address, byte scope, byte[] itemUid, int uidCounter, 1276 byte numAttr, int[] attrs) { 1277 if (DEBUG) Log.v(TAG, "getItemAttrRequestFromNative: scope=" + scope + ", numAttr=" + numAttr); 1278 AvrcpCmd avrcpCmdobj = new AvrcpCmd(); 1279 AvrcpCmd.ItemAttrCmd itemAttr = avrcpCmdobj.new ItemAttrCmd(address, scope, 1280 itemUid, uidCounter, numAttr, attrs); 1281 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_ITEM_ATTR); 1282 msg.obj = itemAttr; 1283 mHandler.sendMessage(msg); 1284 } 1285 1286 private void searchRequestFromNative(byte[] address, int charsetId, byte[] searchStr) { 1287 if (DEBUG) Log.v(TAG, "searchRequestFromNative"); 1288 /* Search is not supported */ 1289 if (DEBUG) Log.d(TAG, "search is not supported"); 1290 searchRspNative(address, AvrcpConstants.RSP_SRCH_NOT_SPRTD, 0, 0); 1291 } 1292 1293 private void playItemRequestFromNative(byte[] address, byte scope, int uidCounter, byte[] uid) { 1294 if (DEBUG) Log.v(TAG, "playItemRequestFromNative: scope=" + scope); 1295 Bundle data = new Bundle(); 1296 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_PLAY_ITEM); 1297 data.putByteArray("BdAddress" , address); 1298 data.putByteArray("uid" , uid); 1299 data.putInt("uidCounter" , uidCounter); 1300 data.putByte("scope" , scope); 1301 msg.setData(data); 1302 mHandler.sendMessage(msg); 1303 } 1304 1305 private void addToPlayListRequestFromNative(byte[] address, byte scope, byte[] uid, int uidCounter) { 1306 if (DEBUG) Log.v(TAG, "addToPlayListRequestFromNative: scope=" + scope); 1307 /* add to NowPlaying not supported */ 1308 Log.w(TAG, "Add to NowPlayingList is not supported"); 1309 addToNowPlayingRspNative(address, AvrcpConstants.RSP_INTERNAL_ERR); 1310 } 1311 1312 private void getTotalNumOfItemsRequestFromNative(byte[] address, byte scope) { 1313 if (DEBUG) Log.v(TAG, "getTotalNumOfItemsRequestFromNative: scope=" + scope); 1314 Bundle data = new Bundle(); 1315 Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS); 1316 msg.arg1 = scope; 1317 msg.obj = address; 1318 mHandler.sendMessage(msg); 1319 } 1320 1321 private void notifyVolumeChanged(int volume) { 1322 mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 1323 AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME); 1324 } 1325 1326 private int convertToAudioStreamVolume(int volume) { 1327 // Rescale volume to match AudioSystem's volume 1328 return (int) Math.floor((double) volume*mAudioStreamMax/AVRCP_MAX_VOL); 1329 } 1330 1331 private int convertToAvrcpVolume(int volume) { 1332 return (int) Math.ceil((double) volume*AVRCP_MAX_VOL/mAudioStreamMax); 1333 } 1334 1335 private void blackListCurrentDevice() { 1336 mFeatures &= ~BTRC_FEAT_ABSOLUTE_VOLUME; 1337 mAudioManager.avrcpSupportsAbsoluteVolume(mAddress, isAbsoluteVolumeSupported()); 1338 1339 SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, 1340 Context.MODE_PRIVATE); 1341 SharedPreferences.Editor editor = pref.edit(); 1342 editor.putBoolean(mAddress, true); 1343 editor.apply(); 1344 } 1345 1346 private int modifyRcFeatureFromBlacklist(int feature, String address) { 1347 SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, 1348 Context.MODE_PRIVATE); 1349 if (!pref.contains(address)) { 1350 return feature; 1351 } 1352 if (pref.getBoolean(address, false)) { 1353 feature &= ~BTRC_FEAT_ABSOLUTE_VOLUME; 1354 } 1355 return feature; 1356 } 1357 1358 public void resetBlackList(String address) { 1359 SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, 1360 Context.MODE_PRIVATE); 1361 SharedPreferences.Editor editor = pref.edit(); 1362 editor.remove(address); 1363 editor.apply(); 1364 } 1365 1366 /** 1367 * This is called from A2dpStateMachine to set A2dp audio state. 1368 */ 1369 public void setA2dpAudioState(int state) { 1370 Message msg = mHandler.obtainMessage(MSG_SET_A2DP_AUDIO_STATE, state, 0); 1371 mHandler.sendMessage(msg); 1372 } 1373 1374 private class AvrcpServiceBootReceiver extends BroadcastReceiver { 1375 @Override 1376 public void onReceive(Context context, Intent intent) { 1377 String action = intent.getAction(); 1378 if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 1379 if (DEBUG) Log.d(TAG, "Boot completed, initializing player lists"); 1380 /* initializing media player's list */ 1381 (new BrowsablePlayerListBuilder()).start(); 1382 } 1383 } 1384 } 1385 1386 private class AvrcpServiceBroadcastReceiver extends BroadcastReceiver { 1387 @Override 1388 public void onReceive(Context context, Intent intent) { 1389 String action = intent.getAction(); 1390 if (DEBUG) Log.d(TAG, "AvrcpServiceBroadcastReceiver-> Action: " + action); 1391 1392 if (action.equals(Intent.ACTION_PACKAGE_REMOVED) 1393 || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) { 1394 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 1395 // a package is being removed, not replaced 1396 String packageName = intent.getData().getSchemeSpecificPart(); 1397 if (packageName != null) { 1398 handlePackageModified(packageName, true); 1399 } 1400 } 1401 1402 } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) 1403 || action.equals(Intent.ACTION_PACKAGE_CHANGED)) { 1404 String packageName = intent.getData().getSchemeSpecificPart(); 1405 if (DEBUG) Log.d(TAG,"AvrcpServiceBroadcastReceiver-> packageName: " 1406 + packageName); 1407 if (packageName != null) { 1408 handlePackageModified(packageName, false); 1409 } 1410 } 1411 } 1412 } 1413 1414 private void handlePackageModified(String packageName, boolean removed) { 1415 if (DEBUG) Log.d(TAG, "packageName: " + packageName + " removed: " + removed); 1416 1417 if (removed) { 1418 // old package is removed, updating local browsable player's list 1419 if (isBrowseSupported(packageName)) { 1420 removePackageFromBrowseList(packageName); 1421 } 1422 } else { 1423 // new package has been added. 1424 if (isBrowsableListUpdated(packageName)) { 1425 // Rebuilding browsable players list 1426 (new BrowsablePlayerListBuilder()).start(); 1427 } 1428 } 1429 } 1430 1431 private boolean isBrowsableListUpdated(String newPackageName) { 1432 // getting the browsable media players list from package manager 1433 Intent intent = new Intent("android.media.browse.MediaBrowserService"); 1434 List<ResolveInfo> resInfos = mPackageManager.queryIntentServices(intent, 1435 PackageManager.MATCH_ALL); 1436 for (ResolveInfo resolveInfo : resInfos) { 1437 if (resolveInfo.serviceInfo.packageName.equals(newPackageName)) { 1438 if (DEBUG) 1439 Log.d(TAG, 1440 "isBrowsableListUpdated: package includes MediaBrowserService, true"); 1441 return true; 1442 } 1443 } 1444 1445 // if list has different size 1446 if (resInfos.size() != mBrowsePlayerInfoList.size()) { 1447 if (DEBUG) Log.d(TAG, "isBrowsableListUpdated: browsable list size mismatch, true"); 1448 return true; 1449 } 1450 1451 Log.d(TAG, "isBrowsableListUpdated: false"); 1452 return false; 1453 } 1454 1455 private void removePackageFromBrowseList(String packageName) { 1456 if (DEBUG) Log.d(TAG, "removePackageFromBrowseList: " + packageName); 1457 synchronized (mBrowsePlayerInfoList) { 1458 int browseInfoID = getBrowseId(packageName); 1459 if (browseInfoID != -1) { 1460 mBrowsePlayerInfoList.remove(browseInfoID); 1461 } 1462 } 1463 } 1464 1465 /* 1466 * utility function to get the browse player index from global browsable 1467 * list. It may return -1 if specified package name is not in the list. 1468 */ 1469 private int getBrowseId(String packageName) { 1470 boolean response = false; 1471 int browseInfoID = 0; 1472 synchronized (mBrowsePlayerInfoList) { 1473 for (BrowsePlayerInfo info : mBrowsePlayerInfoList) { 1474 if (info.packageName.equals(packageName)) { 1475 response = true; 1476 break; 1477 } 1478 browseInfoID++; 1479 } 1480 } 1481 1482 if (!response) { 1483 browseInfoID = -1; 1484 } 1485 1486 if (DEBUG) Log.d(TAG, "getBrowseId for packageName: " + packageName + 1487 " , browseInfoID: " + browseInfoID); 1488 return browseInfoID; 1489 } 1490 1491 private void setAddressedPlayer(byte[] bdaddr, int selectedId) { 1492 int status = AvrcpConstants.RSP_NO_ERROR; 1493 1494 synchronized (mMediaPlayerInfoList) { 1495 if (mMediaPlayerInfoList.isEmpty()) { 1496 status = AvrcpConstants.RSP_NO_AVBL_PLAY; 1497 Log.w(TAG, " No Available Players to set, sending response back "); 1498 } else if (!mMediaPlayerInfoList.containsKey(selectedId)) { 1499 status = AvrcpConstants.RSP_INV_PLAYER; 1500 Log.w(TAG, " Invalid Player id: " + selectedId + " to set, sending response back "); 1501 } else if (!isPlayerAlreadyAddressed(selectedId)) { 1502 // register new Media Controller Callback and update the current Ids 1503 if (!updateCurrentController(selectedId, mCurrBrowsePlayerID)) { 1504 status = AvrcpConstants.RSP_INTERNAL_ERR; 1505 Log.e(TAG, "register for new Address player failed: " + mCurrAddrPlayerID); 1506 } 1507 } else { 1508 MediaPlayerInfo info = getAddressedPlayerInfo(); 1509 Log.i(TAG, "addressed player " + info + "is already focused"); 1510 } 1511 } 1512 1513 if (DEBUG) Log.d(TAG, "setAddressedPlayer for selectedId: " + selectedId + 1514 " , status: " + status); 1515 // Sending address player response to remote 1516 setAddressedPlayerRspNative(bdaddr, status); 1517 } 1518 1519 private void setBrowsedPlayer(byte[] bdaddr, int selectedId) { 1520 int status = AvrcpConstants.RSP_NO_ERROR; 1521 1522 // checking for error cases 1523 if (mMediaPlayerInfoList.isEmpty()) { 1524 status = AvrcpConstants.RSP_NO_AVBL_PLAY; 1525 Log.w(TAG, " No Available Players to set, sending response back "); 1526 } else { 1527 // update current browse player id and start browsing service 1528 updateNewIds(mCurrAddrPlayerID, selectedId); 1529 String browsedPackage = getPackageName(selectedId); 1530 1531 if (!isPackageNameValid(browsedPackage)) { 1532 Log.w(TAG, " Invalid package for id:" + mCurrBrowsePlayerID); 1533 status = AvrcpConstants.RSP_INV_PLAYER; 1534 } else if (!isBrowseSupported(browsedPackage)) { 1535 Log.w(TAG, "Browse unsupported for id:" + mCurrBrowsePlayerID 1536 + ", packagename : " + browsedPackage); 1537 status = AvrcpConstants.RSP_PLAY_NOT_BROW; 1538 } else if (!startBrowseService(bdaddr, browsedPackage)) { 1539 Log.e(TAG, "service cannot be started for browse player id:" + mCurrBrowsePlayerID 1540 + ", packagename : " + browsedPackage); 1541 status = AvrcpConstants.RSP_INTERNAL_ERR; 1542 } 1543 } 1544 1545 if (status != AvrcpConstants.RSP_NO_ERROR) { 1546 setBrowsedPlayerRspNative(bdaddr, status, (byte) 0x00, 0, null); 1547 } 1548 1549 if (DEBUG) Log.d(TAG, "setBrowsedPlayer for selectedId: " + selectedId + 1550 " , status: " + status); 1551 } 1552 1553 private MediaSessionManager.OnActiveSessionsChangedListener mActiveSessionListener = 1554 new MediaSessionManager.OnActiveSessionsChangedListener() { 1555 1556 @Override 1557 public void onActiveSessionsChanged( 1558 List<android.media.session.MediaController> newControllers) { 1559 boolean playersChanged = false; 1560 1561 // Update the current players 1562 for (android.media.session.MediaController controller : newControllers) { 1563 addMediaPlayerController(controller); 1564 playersChanged = true; 1565 } 1566 1567 List<android.media.session.MediaController> currentControllers = 1568 getMediaControllers(); 1569 for (android.media.session.MediaController controller : currentControllers) { 1570 if (!newControllers.contains(controller)) { 1571 removeMediaPlayerInfo(controller.getPackageName()); 1572 playersChanged = true; 1573 } 1574 } 1575 1576 if (playersChanged) { 1577 mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP); 1578 if (newControllers.size() > 0 && (mMediaController == null)) { 1579 if (DEBUG) 1580 Log.v(TAG, 1581 "No addressed player but active sessions, taking first."); 1582 setAddressedMediaSessionPackage(newControllers.get(0).getPackageName()); 1583 } 1584 } 1585 } 1586 }; 1587 1588 private void setAddressedMediaSessionPackage(String packageName) { 1589 if (DEBUG) Log.v(TAG, "Setting addressed media session to " + packageName); 1590 // Can't set no player, that handled by onActiveSessionsChanged 1591 if (packageName == null) return; 1592 // No change. 1593 if (getPackageName(mCurrAddrPlayerID).equals(packageName)) return; 1594 // If the player doesn't exist, we need to add it. 1595 if (getMediaPlayerInfo(packageName) == null) { 1596 addMediaPlayerPackage(packageName); 1597 mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP); 1598 } 1599 synchronized (mMediaPlayerInfoList) { 1600 for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { 1601 if (entry.getValue().getPackageName().equals(packageName)) { 1602 int newAddrID = entry.getKey(); 1603 if (DEBUG) Log.v(TAG, "Set addressed #" + newAddrID + " " + entry.getValue()); 1604 updateCurrentController(newAddrID, mCurrBrowsePlayerID); 1605 mHandler.obtainMessage(MSG_ADDRESSED_PLAYER_CHANGED_RSP, newAddrID, 0) 1606 .sendToTarget(); 1607 return; 1608 } 1609 } 1610 } 1611 // We shouldn't ever get here. 1612 Log.e(TAG, "Player info for " + packageName + " doesn't exist!"); 1613 } 1614 1615 private void setActiveMediaSession(MediaSession.Token token) { 1616 android.media.session.MediaController activeController = 1617 new android.media.session.MediaController(mContext, token); 1618 if (DEBUG) Log.v(TAG, "Set active media session " + activeController.getPackageName()); 1619 addMediaPlayerController(activeController); 1620 setAddressedMediaSessionPackage(activeController.getPackageName()); 1621 } 1622 1623 private boolean startBrowseService(byte[] bdaddr, String packageName) { 1624 boolean status = true; 1625 1626 /* creating new instance for Browse Media Player */ 1627 String browseService = getBrowseServiceName(packageName); 1628 if (!browseService.isEmpty()) { 1629 mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).setBrowsed( 1630 packageName, browseService); 1631 } else { 1632 Log.w(TAG, "No Browser service available for " + packageName); 1633 status = false; 1634 } 1635 1636 if (DEBUG) Log.d(TAG, "startBrowseService for packageName: " + packageName + 1637 ", status = " + status); 1638 return status; 1639 } 1640 1641 private String getBrowseServiceName(String packageName) { 1642 String browseServiceName = ""; 1643 1644 // getting the browse service name from browse player info 1645 synchronized (mBrowsePlayerInfoList) { 1646 int browseInfoID = getBrowseId(packageName); 1647 if (browseInfoID != -1) { 1648 browseServiceName = mBrowsePlayerInfoList.get(browseInfoID).serviceClass; 1649 } 1650 } 1651 1652 if (DEBUG) Log.d(TAG, "getBrowseServiceName for packageName: " + packageName + 1653 ", browseServiceName = " + browseServiceName); 1654 return browseServiceName; 1655 } 1656 1657 private class BrowsablePlayerListBuilder extends MediaBrowser.ConnectionCallback { 1658 List<ResolveInfo> mWaiting; 1659 BrowsePlayerInfo mCurrentPlayer; 1660 MediaBrowser mCurrentBrowser; 1661 boolean mPlayersChanged; 1662 1663 public BrowsablePlayerListBuilder() {} 1664 1665 public void start() { 1666 mBrowsePlayerInfoList.clear(); 1667 mPlayersChanged = false; 1668 Intent intent = new Intent(android.service.media.MediaBrowserService.SERVICE_INTERFACE); 1669 mWaiting = mPackageManager.queryIntentServices(intent, PackageManager.MATCH_ALL); 1670 connectNextPlayer(); 1671 } 1672 1673 private void connectNextPlayer() { 1674 if (mWaiting.isEmpty()) { 1675 // Done. Send players changed if needed. 1676 if (mPlayersChanged) { 1677 registerNotificationRspAvalPlayerChangedNative( 1678 AvrcpConstants.NOTIFICATION_TYPE_CHANGED); 1679 } 1680 return; 1681 } 1682 ResolveInfo info = mWaiting.remove(0); 1683 String displayableName = info.loadLabel(mPackageManager).toString(); 1684 String serviceName = info.serviceInfo.name; 1685 String packageName = info.serviceInfo.packageName; 1686 1687 mCurrentPlayer = new BrowsePlayerInfo(packageName, displayableName, serviceName); 1688 mCurrentBrowser = new MediaBrowser( 1689 mContext, new ComponentName(packageName, serviceName), this, null); 1690 if (DEBUG) Log.d(TAG, "Trying to connect to " + serviceName); 1691 mCurrentBrowser.connect(); 1692 } 1693 1694 @Override 1695 public void onConnected() { 1696 Log.d(TAG, "BrowsablePlayerListBuilder: " + mCurrentPlayer.packageName + " OK"); 1697 mBrowsePlayerInfoList.add(mCurrentPlayer); 1698 MediaPlayerInfo info = getMediaPlayerInfo(mCurrentPlayer.packageName); 1699 if (info != null) { 1700 // Refresh the media player entry so it notices we can browse 1701 MediaController controller = info.getMediaController(); 1702 if (controller != null) { 1703 addMediaPlayerController(controller.getWrappedInstance()); 1704 } 1705 // If there's no controller, the entry is already browsable-only. 1706 } else { 1707 addMediaPlayerPackage(mCurrentPlayer.packageName); 1708 } 1709 mPlayersChanged = true; 1710 mCurrentBrowser.disconnect(); 1711 connectNextPlayer(); 1712 } 1713 1714 @Override 1715 public void onConnectionFailed() { 1716 Log.d(TAG, "BrowsablePlayerListBuilder: " + mCurrentPlayer.packageName + " FAIL"); 1717 connectNextPlayer(); 1718 } 1719 } 1720 1721 private void startBrowsedPlayer(int browseId) { 1722 if (browseId < 0 || browseId >= mBrowsePlayerInfoList.size()) return; 1723 BrowsePlayerInfo player = mBrowsePlayerInfoList.get(browseId); 1724 1725 Intent intent = new Intent(); 1726 intent.setComponent(new ComponentName(player.packageName, player.serviceClass)); 1727 Log.i(TAG, "Starting service:" + player.packageName + ", " + player.serviceClass); 1728 try { 1729 mContext.startService(intent); 1730 } catch (SecurityException ex) { 1731 Log.e(TAG, "Can't start " + player.serviceClass + ": " + ex.getMessage()); 1732 } 1733 } 1734 1735 /* Initializes list of media players identified from session manager active sessions */ 1736 private void initMediaPlayersList() { 1737 synchronized (mMediaPlayerInfoList) { 1738 // Clearing old browsable player's list 1739 mMediaPlayerInfoList.clear(); 1740 1741 if (mMediaSessionManager == null) { 1742 if (DEBUG) Log.w(TAG, "initMediaPlayersList: no media session manager!"); 1743 return; 1744 } 1745 1746 List<android.media.session.MediaController> controllers = 1747 mMediaSessionManager.getActiveSessions(null); 1748 if (DEBUG) 1749 Log.v(TAG, "initMediaPlayerInfoList: " + controllers.size() + " controllers"); 1750 /* Initializing all media players */ 1751 for (android.media.session.MediaController controller : controllers) { 1752 addMediaPlayerController(controller); 1753 } 1754 if (controllers.size() > 0) { 1755 mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP); 1756 } 1757 1758 if (mMediaPlayerInfoList.size() > 0) { 1759 // Set the first one as the Addressed Player 1760 updateCurrentController(mMediaPlayerInfoList.firstKey(), -1); 1761 } 1762 } 1763 } 1764 1765 private List<android.media.session.MediaController> getMediaControllers() { 1766 List<android.media.session.MediaController> controllers = 1767 new ArrayList<android.media.session.MediaController>(); 1768 synchronized (mMediaPlayerInfoList) { 1769 for (MediaPlayerInfo info : mMediaPlayerInfoList.values()) { 1770 if (info.getMediaController() != null) { 1771 controllers.add(info.getMediaController().getWrappedInstance()); 1772 } 1773 } 1774 } 1775 return controllers; 1776 } 1777 1778 /** Add (or update) a player to the media player list without a controller */ 1779 private boolean addMediaPlayerPackage(String packageName) { 1780 MediaPlayerInfo info = new MediaPlayerInfo(null, AvrcpConstants.PLAYER_TYPE_AUDIO, 1781 AvrcpConstants.PLAYER_SUBTYPE_NONE, getPlayStateBytes(null), 1782 getFeatureBitMask(packageName), packageName, getAppLabel(packageName)); 1783 return addMediaPlayerInfo(info); 1784 } 1785 1786 /** Add (or update) a player to the media player list given an active controller */ 1787 private boolean addMediaPlayerController(android.media.session.MediaController controller) { 1788 String packageName = controller.getPackageName(); 1789 MediaPlayerInfo info = new MediaPlayerInfo(MediaController.wrap(controller), 1790 AvrcpConstants.PLAYER_TYPE_AUDIO, AvrcpConstants.PLAYER_SUBTYPE_NONE, 1791 getPlayStateBytes(controller.getPlaybackState()), getFeatureBitMask(packageName), 1792 controller.getPackageName(), getAppLabel(packageName)); 1793 return addMediaPlayerInfo(info); 1794 } 1795 1796 /** Add or update a player to the media player list given the MediaPlayerInfo object. 1797 * @return true if an item was updated, false if it was added instead 1798 */ 1799 private boolean addMediaPlayerInfo(MediaPlayerInfo info) { 1800 if (DEBUG) Log.d(TAG, "add " + info.toString()); 1801 int updateId = -1; 1802 boolean updated = false; 1803 synchronized (mMediaPlayerInfoList) { 1804 for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { 1805 if (info.getPackageName().equals(entry.getValue().getPackageName())) { 1806 updateId = entry.getKey(); 1807 updated = true; 1808 break; 1809 } 1810 } 1811 if (updateId == -1) { 1812 // New player 1813 mLastUsedPlayerID++; 1814 updateId = mLastUsedPlayerID; 1815 } else if (updateId == mCurrAddrPlayerID) { 1816 updateCurrentController(mCurrAddrPlayerID, mCurrBrowsePlayerID); 1817 } 1818 mMediaPlayerInfoList.put(updateId, info); 1819 } 1820 return updated; 1821 } 1822 1823 /** Remove all players related to |packageName| from the media player info list */ 1824 private MediaPlayerInfo removeMediaPlayerInfo(String packageName) { 1825 synchronized (mMediaPlayerInfoList) { 1826 int removeKey = -1; 1827 for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { 1828 if (entry.getValue().getPackageName().equals(packageName)) { 1829 removeKey = entry.getKey(); 1830 break; 1831 } 1832 } 1833 if (removeKey != -1) { 1834 return mMediaPlayerInfoList.remove(removeKey); 1835 } 1836 1837 return null; 1838 } 1839 } 1840 1841 /* 1842 * utility function to get the playback state of any media player through 1843 * media controller APIs. 1844 */ 1845 private byte getPlayStateBytes(PlaybackState pbState) { 1846 byte playStateBytes = PLAYSTATUS_STOPPED; 1847 1848 if (pbState != null) { 1849 playStateBytes = (byte)convertPlayStateToBytes(pbState.getState()); 1850 Log.v(TAG, "getPlayBackState: playStateBytes = " + playStateBytes); 1851 } else { 1852 Log.w(TAG, "playState object null, sending playStateBytes = " + playStateBytes); 1853 } 1854 1855 return playStateBytes; 1856 } 1857 1858 /* 1859 * utility function to map framework's play state values to AVRCP spec 1860 * defined play status values 1861 */ 1862 private int convertPlayStateToBytes(int playState) { 1863 switch (playState) { 1864 case PlaybackState.STATE_PLAYING: 1865 case PlaybackState.STATE_BUFFERING: 1866 return PLAYSTATUS_PLAYING; 1867 1868 case PlaybackState.STATE_STOPPED: 1869 case PlaybackState.STATE_NONE: 1870 case PlaybackState.STATE_CONNECTING: 1871 return PLAYSTATUS_STOPPED; 1872 1873 case PlaybackState.STATE_PAUSED: 1874 return PLAYSTATUS_PAUSED; 1875 1876 case PlaybackState.STATE_FAST_FORWARDING: 1877 case PlaybackState.STATE_SKIPPING_TO_NEXT: 1878 case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM: 1879 return PLAYSTATUS_FWD_SEEK; 1880 1881 case PlaybackState.STATE_REWINDING: 1882 case PlaybackState.STATE_SKIPPING_TO_PREVIOUS: 1883 return PLAYSTATUS_REV_SEEK; 1884 1885 case PlaybackState.STATE_ERROR: 1886 default: 1887 return PLAYSTATUS_ERROR; 1888 } 1889 } 1890 1891 /* 1892 * utility function to get the feature bit mask of any media player through 1893 * package name 1894 */ 1895 private short[] getFeatureBitMask(String packageName) { 1896 1897 ArrayList<Short> featureBitsList = new ArrayList<Short>(); 1898 1899 /* adding default feature bits */ 1900 featureBitsList.add(AvrcpConstants.AVRC_PF_PLAY_BIT_NO); 1901 featureBitsList.add(AvrcpConstants.AVRC_PF_STOP_BIT_NO); 1902 featureBitsList.add(AvrcpConstants.AVRC_PF_PAUSE_BIT_NO); 1903 featureBitsList.add(AvrcpConstants.AVRC_PF_REWIND_BIT_NO); 1904 featureBitsList.add(AvrcpConstants.AVRC_PF_FAST_FWD_BIT_NO); 1905 featureBitsList.add(AvrcpConstants.AVRC_PF_FORWARD_BIT_NO); 1906 featureBitsList.add(AvrcpConstants.AVRC_PF_BACKWARD_BIT_NO); 1907 featureBitsList.add(AvrcpConstants.AVRC_PF_ADV_CTRL_BIT_NO); 1908 1909 /* Add/Modify browse player supported features. */ 1910 if (isBrowseSupported(packageName)) { 1911 featureBitsList.add(AvrcpConstants.AVRC_PF_BROWSE_BIT_NO); 1912 featureBitsList.add(AvrcpConstants.AVRC_PF_UID_UNIQUE_BIT_NO); 1913 featureBitsList.add(AvrcpConstants.AVRC_PF_NOW_PLAY_BIT_NO); 1914 featureBitsList.add(AvrcpConstants.AVRC_PF_GET_NUM_OF_ITEMS_BIT_NO); 1915 } 1916 1917 // converting arraylist to array for response 1918 short[] featureBitsArray = new short[featureBitsList.size()]; 1919 1920 for (int i = 0; i < featureBitsList.size(); i++) { 1921 featureBitsArray[i] = featureBitsList.get(i).shortValue(); 1922 } 1923 1924 return featureBitsArray; 1925 } 1926 1927 /** 1928 * Checks the Package name if it supports Browsing or not. 1929 * 1930 * @param packageName - name of the package to get the Id. 1931 * @return true if it supports browsing, else false. 1932 */ 1933 private boolean isBrowseSupported(String packageName) { 1934 synchronized (mBrowsePlayerInfoList) { 1935 /* check if Browsable Player's list contains this package name */ 1936 for (BrowsePlayerInfo info : mBrowsePlayerInfoList) { 1937 if (info.packageName.equals(packageName)) { 1938 if (DEBUG) Log.v(TAG, "isBrowseSupported for " + packageName + ": true"); 1939 return true; 1940 } 1941 } 1942 } 1943 1944 if (DEBUG) Log.v(TAG, "isBrowseSupported for " + packageName + ": false"); 1945 return false; 1946 } 1947 1948 private String getPackageName(int id) { 1949 MediaPlayerInfo player = null; 1950 synchronized (mMediaPlayerInfoList) { 1951 player = mMediaPlayerInfoList.getOrDefault(id, null); 1952 } 1953 1954 if (player == null) { 1955 Log.w(TAG, "No package name for player (" + id + " not valid)"); 1956 return ""; 1957 } 1958 1959 String packageName = player.getPackageName(); 1960 if (DEBUG) Log.v(TAG, "Player " + id + " package: " + packageName); 1961 return packageName; 1962 } 1963 1964 /* from the global object, getting the current browsed player's package name */ 1965 private String getCurrentBrowsedPlayer(byte[] bdaddr) { 1966 String browsedPlayerPackage = ""; 1967 1968 Map<String, BrowsedMediaPlayer> connList = mAvrcpBrowseManager.getConnList(); 1969 String bdaddrStr = new String(bdaddr); 1970 if(connList.containsKey(bdaddrStr)){ 1971 browsedPlayerPackage = connList.get(bdaddrStr).getPackageName(); 1972 } 1973 if (DEBUG) Log.v(TAG, "getCurrentBrowsedPlayerPackage: " + browsedPlayerPackage); 1974 return browsedPlayerPackage; 1975 } 1976 1977 /* Returns the MediaPlayerInfo for the currently addressed media player */ 1978 private MediaPlayerInfo getAddressedPlayerInfo() { 1979 synchronized (mMediaPlayerInfoList) { 1980 return mMediaPlayerInfoList.getOrDefault(mCurrAddrPlayerID, null); 1981 } 1982 } 1983 1984 /* 1985 * Utility function to get the Media player info from package name returns 1986 * null if package name not found in media players list 1987 */ 1988 private MediaPlayerInfo getMediaPlayerInfo(String packageName) { 1989 synchronized (mMediaPlayerInfoList) { 1990 if (mMediaPlayerInfoList.isEmpty()) { 1991 if (DEBUG) Log.v(TAG, "getMediaPlayerInfo: Media players list empty"); 1992 return null; 1993 } 1994 1995 for (MediaPlayerInfo info : mMediaPlayerInfoList.values()) { 1996 if (packageName.equals(info.getPackageName())) { 1997 if (DEBUG) Log.v(TAG, "getMediaPlayerInfo: Found " + packageName); 1998 return info; 1999 } 2000 } 2001 if (DEBUG) Log.w(TAG, "getMediaPlayerInfo: " + packageName + " not found"); 2002 return null; 2003 } 2004 } 2005 2006 /* prepare media list & return the media player list response object */ 2007 private MediaPlayerListRsp prepareMediaPlayerRspObj() { 2008 synchronized (mMediaPlayerInfoList) { 2009 int numPlayers = mMediaPlayerInfoList.size(); 2010 2011 int[] playerIds = new int[numPlayers]; 2012 byte[] playerTypes = new byte[numPlayers]; 2013 int[] playerSubTypes = new int[numPlayers]; 2014 String[] displayableNameArray = new String[numPlayers]; 2015 byte[] playStatusValues = new byte[numPlayers]; 2016 short[] featureBitMaskValues = 2017 new short[numPlayers * AvrcpConstants.AVRC_FEATURE_MASK_SIZE]; 2018 2019 int players = 0; 2020 for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { 2021 MediaPlayerInfo info = entry.getValue(); 2022 playerIds[players] = entry.getKey(); 2023 playerTypes[players] = info.getMajorType(); 2024 playerSubTypes[players] = info.getSubType(); 2025 displayableNameArray[players] = info.getDisplayableName(); 2026 playStatusValues[players] = info.getPlayStatus(); 2027 2028 short[] featureBits = info.getFeatureBitMask(); 2029 for (int numBit = 0; numBit < featureBits.length; numBit++) { 2030 /* gives which octet this belongs to */ 2031 byte octet = (byte) (featureBits[numBit] / 8); 2032 /* gives the bit position within the octet */ 2033 byte bit = (byte) (featureBits[numBit] % 8); 2034 featureBitMaskValues[(players * AvrcpConstants.AVRC_FEATURE_MASK_SIZE) 2035 + octet] |= (1 << bit); 2036 } 2037 2038 /* printLogs */ 2039 if (DEBUG) { 2040 Log.d(TAG, "Player " + playerIds[players] + ": " + displayableNameArray[players] 2041 + " type: " + playerTypes[players] + ", " 2042 + playerSubTypes[players] + " status: " 2043 + playStatusValues[players]); 2044 } 2045 2046 players++; 2047 } 2048 2049 if (DEBUG) Log.d(TAG, "prepareMediaPlayerRspObj: numPlayers = " + numPlayers); 2050 2051 return new MediaPlayerListRsp(AvrcpConstants.RSP_NO_ERROR, sUIDCounter, numPlayers, 2052 AvrcpConstants.BTRC_ITEM_PLAYER, playerIds, playerTypes, playerSubTypes, 2053 playStatusValues, featureBitMaskValues, displayableNameArray); 2054 } 2055 } 2056 2057 /* build media player list and send it to remote. */ 2058 private void handleMediaPlayerListRsp(AvrcpCmd.FolderItemsCmd folderObj) { 2059 MediaPlayerListRsp rspObj = null; 2060 synchronized (mMediaPlayerInfoList) { 2061 int numPlayers = mMediaPlayerInfoList.size(); 2062 if (numPlayers == 0) { 2063 mediaPlayerListRspNative(folderObj.mAddress, AvrcpConstants.RSP_NO_AVBL_PLAY, 2064 (short) 0, (byte) 0, 0, null, null, null, null, null, null); 2065 return; 2066 } 2067 if (folderObj.mStartItem >= numPlayers) { 2068 Log.i(TAG, "handleMediaPlayerListRsp: start = " + folderObj.mStartItem 2069 + " > num of items = " + numPlayers); 2070 mediaPlayerListRspNative(folderObj.mAddress, AvrcpConstants.RSP_INV_RANGE, 2071 (short) 0, (byte) 0, 0, null, null, null, null, null, null); 2072 return; 2073 } 2074 rspObj = prepareMediaPlayerRspObj(); 2075 } 2076 if (DEBUG) Log.d(TAG, "handleMediaPlayerListRsp: sending " + rspObj.mNumItems + " players"); 2077 mediaPlayerListRspNative(folderObj.mAddress, rspObj.mStatus, rspObj.mUIDCounter, 2078 rspObj.itemType, rspObj.mNumItems, rspObj.mPlayerIds, rspObj.mPlayerTypes, 2079 rspObj.mPlayerSubTypes, rspObj.mPlayStatusValues, rspObj.mFeatureBitMaskValues, 2080 rspObj.mPlayerNameList); 2081 } 2082 2083 /* unregister to the old controller, update new IDs and register to the new controller */ 2084 private boolean updateCurrentController(int addrId, int browseId) { 2085 boolean registerRsp = true; 2086 2087 updateNewIds(addrId, browseId); 2088 2089 MediaController newController = null; 2090 MediaPlayerInfo info = getAddressedPlayerInfo(); 2091 if (info != null) { 2092 newController = info.getMediaController(); 2093 if (newController == null) { 2094 // Browsable player, try to start it, which will trigger an update via 2095 // MesiaSessionManager 2096 startBrowsedPlayer(getBrowseId(info.getPackageName())); 2097 } 2098 } 2099 2100 if (DEBUG) 2101 Log.d(TAG, "updateCurrentController: " + mMediaController + " to " + newController); 2102 if (mMediaController == null || newController == null 2103 || (mMediaController.getWrappedInstance() != newController.getWrappedInstance())) { 2104 if (mMediaController != null) mMediaController.unregisterCallback(mMediaControllerCb); 2105 if (newController != null) { 2106 mMediaController = newController; 2107 mMediaController.registerCallback(mMediaControllerCb, mHandler); 2108 updateMetadata(mMediaController.getMetadata()); 2109 mAddressedMediaPlayer.updateNowPlayingList(mMediaController.getQueue()); 2110 } else { 2111 updateMetadata(null); 2112 mAddressedMediaPlayer.updateNowPlayingList(null); 2113 registerRsp = false; 2114 } 2115 } 2116 return registerRsp; 2117 } 2118 2119 /* Handle getfolderitems for scope = VFS, Search, NowPlayingList */ 2120 private void handleGetFolderItemBrowseResponse(AvrcpCmd.FolderItemsCmd folderObj, byte[] bdaddr) { 2121 int status = AvrcpConstants.RSP_NO_ERROR; 2122 2123 /* Browsed player is already set */ 2124 if (folderObj.mScope == AvrcpConstants.BTRC_SCOPE_FILE_SYSTEM) { 2125 if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) == null) { 2126 Log.e(TAG, "handleGetFolderItemBrowseResponse: no browsed player set for " 2127 + Utils.getAddressStringFromByte(bdaddr)); 2128 getFolderItemsRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR, (short) 0, 2129 (byte) 0x00, 0, null, null, null, null, null, null, null, null); 2130 return; 2131 } 2132 mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).getFolderItemsVFS(folderObj); 2133 return; 2134 } 2135 if (folderObj.mScope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) { 2136 mAddressedMediaPlayer.getFolderItemsNowPlaying(bdaddr, folderObj, mMediaController); 2137 return; 2138 } 2139 2140 /* invalid scope */ 2141 Log.e(TAG, "handleGetFolderItemBrowseResponse: unknown scope " + folderObj.mScope); 2142 getFolderItemsRspNative(bdaddr, AvrcpConstants.RSP_INV_SCOPE, (short) 0, (byte) 0x00, 0, 2143 null, null, null, null, null, null, null, null); 2144 } 2145 2146 /* utility function to update the global values of current Addressed and browsed player */ 2147 private void updateNewIds(int addrId, int browseId) { 2148 mCurrAddrPlayerID = addrId; 2149 mCurrBrowsePlayerID = browseId; 2150 2151 if (DEBUG) Log.v(TAG, "Updated CurrentIds: AddrPlayerID:" + mCurrAddrPlayerID + " to " 2152 + addrId + ", BrowsePlayerID:" + mCurrBrowsePlayerID + " to " + browseId); 2153 } 2154 2155 /* Getting the application's displayable name from package name */ 2156 private String getAppLabel(String packageName) { 2157 ApplicationInfo appInfo = null; 2158 try { 2159 appInfo = mPackageManager.getApplicationInfo(packageName, 0); 2160 } catch (NameNotFoundException e) { 2161 e.printStackTrace(); 2162 } 2163 2164 return (String) (appInfo != null ? mPackageManager 2165 .getApplicationLabel(appInfo) : "Unknown"); 2166 } 2167 2168 private void handlePlayItemResponse(byte[] bdaddr, byte[] uid, byte scope) { 2169 if (scope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) { 2170 mAddressedMediaPlayer.playItem(bdaddr, uid, mMediaController); 2171 } 2172 else { 2173 if(!isAddrPlayerSameAsBrowsed(bdaddr)) { 2174 Log.w(TAG, "Remote requesting play item on uid which may not be recognized by" + 2175 "current addressed player"); 2176 playItemRspNative(bdaddr, AvrcpConstants.RSP_INV_ITEM); 2177 } 2178 2179 if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) { 2180 mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).playItem(uid, scope); 2181 } else { 2182 Log.e(TAG, "handlePlayItemResponse: Remote requested playitem " + 2183 "before setbrowsedplayer"); 2184 playItemRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR); 2185 } 2186 } 2187 } 2188 2189 private void handleGetItemAttr(AvrcpCmd.ItemAttrCmd itemAttr) { 2190 if(itemAttr.mScope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) { 2191 mAddressedMediaPlayer.getItemAttr(itemAttr.mAddress, itemAttr, mMediaController); 2192 } 2193 else { 2194 if (mAvrcpBrowseManager.getBrowsedMediaPlayer(itemAttr.mAddress) != null) 2195 mAvrcpBrowseManager.getBrowsedMediaPlayer(itemAttr.mAddress).getItemAttr(itemAttr); 2196 else { 2197 Log.e(TAG, "Could not get attributes. mBrowsedMediaPlayer is null"); 2198 getItemAttrRspNative(itemAttr.mAddress, AvrcpConstants.RSP_INTERNAL_ERR, 2199 (byte) 0, null, null); 2200 } 2201 } 2202 } 2203 2204 private void handleGetTotalNumOfItemsResponse(byte[] bdaddr, byte scope) { 2205 // for scope as media player list 2206 if (scope == AvrcpConstants.BTRC_SCOPE_PLAYER_LIST) { 2207 int numPlayers = 0; 2208 synchronized (mMediaPlayerInfoList) { 2209 numPlayers = mMediaPlayerInfoList.size(); 2210 } 2211 if (DEBUG) Log.d(TAG, "handleGetTotalNumOfItemsResponse: " + numPlayers + " players."); 2212 getTotalNumOfItemsRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, numPlayers); 2213 } else if (scope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) { 2214 mAddressedMediaPlayer.getTotalNumOfItems(bdaddr, mMediaController); 2215 } else { 2216 // for FileSystem browsing scopes as VFS, Now Playing 2217 if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) { 2218 mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).getTotalNumOfItems(scope); 2219 } else { 2220 Log.e(TAG, "Could not get Total NumOfItems. mBrowsedMediaPlayer is null"); 2221 getTotalNumOfItemsRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR, 0, 0); 2222 } 2223 } 2224 2225 } 2226 2227 /* check if browsed player and addressed player are same */ 2228 private boolean isAddrPlayerSameAsBrowsed(byte[] bdaddr) { 2229 String browsedPlayer = getCurrentBrowsedPlayer(bdaddr); 2230 2231 if (!isPackageNameValid(browsedPlayer)) { 2232 Log.w(TAG, "Browsed player name empty"); 2233 return false; 2234 } 2235 2236 MediaPlayerInfo info = getAddressedPlayerInfo(); 2237 String packageName = (info == null) ? "<none>" : info.getPackageName(); 2238 if (info == null || !packageName.equals(browsedPlayer)) { 2239 if (DEBUG) Log.d(TAG, browsedPlayer + " is not addressed player " + packageName); 2240 return false; 2241 } 2242 return true; 2243 } 2244 2245 /* checks if package name is not null or empty */ 2246 private boolean isPackageNameValid(String browsedPackage) { 2247 boolean isValid = (browsedPackage != null && browsedPackage.length() > 0); 2248 if (DEBUG) Log.d(TAG, "isPackageNameValid: browsedPackage = " + browsedPackage + 2249 "isValid = " + isValid); 2250 return isValid; 2251 } 2252 2253 /* checks if selected addressed player is already addressed */ 2254 private boolean isPlayerAlreadyAddressed(int selectedId) { 2255 // checking if selected ID is same as the current addressed player id 2256 boolean isAddressed = (mCurrAddrPlayerID == selectedId); 2257 if (DEBUG) Log.d(TAG, "isPlayerAlreadyAddressed: isAddressed = " + isAddressed); 2258 return isAddressed; 2259 } 2260 2261 public void dump(StringBuilder sb) { 2262 sb.append("AVRCP:\n"); 2263 ProfileService.println(sb, "mMediaAttributes: " + mMediaAttributes); 2264 ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags); 2265 ProfileService.println(sb, "mTracksPlayed: " + mTracksPlayed); 2266 ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState); 2267 ProfileService.println(sb, "mLastStateUpdate: " + mLastStateUpdate); 2268 ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT); 2269 ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT); 2270 ProfileService.println(sb, "mSongLengthMs: " + mSongLengthMs); 2271 ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs); 2272 ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT); 2273 ProfileService.println(sb, "mNextPosMs: " + mNextPosMs); 2274 ProfileService.println(sb, "mPrevPosMs: " + mPrevPosMs); 2275 ProfileService.println(sb, "mSkipStartTime: " + mSkipStartTime); 2276 ProfileService.println(sb, "mFeatures: " + mFeatures); 2277 ProfileService.println(sb, "mRemoteVolume: " + mRemoteVolume); 2278 ProfileService.println(sb, "mLastRemoteVolume: " + mLastRemoteVolume); 2279 ProfileService.println(sb, "mLastDirection: " + mLastDirection); 2280 ProfileService.println(sb, "mVolumeStep: " + mVolumeStep); 2281 ProfileService.println(sb, "mAudioStreamMax: " + mAudioStreamMax); 2282 ProfileService.println(sb, "mVolCmdAdjustInProgress: " + mVolCmdAdjustInProgress); 2283 ProfileService.println(sb, "mVolCmdSetInProgress: " + mVolCmdSetInProgress); 2284 ProfileService.println(sb, "mAbsVolRetryTimes: " + mAbsVolRetryTimes); 2285 ProfileService.println(sb, "mSkipAmount: " + mSkipAmount); 2286 ProfileService.println(sb, "mVolumeMapping: " + mVolumeMapping.toString()); 2287 if (mMediaController != null) 2288 ProfileService.println(sb, "mMediaSession pkg: " + mMediaController.getPackageName()); 2289 2290 ProfileService.println(sb, "\nMedia Players:"); 2291 synchronized (mMediaPlayerInfoList) { 2292 for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) { 2293 int key = entry.getKey(); 2294 ProfileService.println(sb, ((mCurrAddrPlayerID == key) ? " *#" : " #") 2295 + entry.getKey() + ": " + entry.getValue()); 2296 } 2297 } 2298 2299 ProfileService.println(sb, "Passthrough operations: "); 2300 for (MediaKeyLog log : mPassthroughLogs) { 2301 ProfileService.println(sb, " " + log); 2302 } 2303 for (MediaKeyLog log : mPassthroughPending) { 2304 ProfileService.println(sb, " " + log); 2305 } 2306 } 2307 2308 public class AvrcpBrowseManager { 2309 Map<String, BrowsedMediaPlayer> connList = new HashMap<String, BrowsedMediaPlayer>(); 2310 private AvrcpMediaRspInterface mMediaInterface; 2311 private Context mContext; 2312 2313 public AvrcpBrowseManager(Context context, AvrcpMediaRspInterface mediaInterface) { 2314 mContext = context; 2315 mMediaInterface = mediaInterface; 2316 } 2317 2318 public void cleanup() { 2319 Iterator entries = connList.entrySet().iterator(); 2320 while (entries.hasNext()) { 2321 Map.Entry entry = (Map.Entry) entries.next(); 2322 BrowsedMediaPlayer browsedMediaPlayer = (BrowsedMediaPlayer) entry.getValue(); 2323 if (browsedMediaPlayer != null) { 2324 browsedMediaPlayer.cleanup(); 2325 } 2326 } 2327 // clean up the map 2328 connList.clear(); 2329 } 2330 2331 // get the a free media player interface based on the passed bd address 2332 // if the no items is found for the passed media player then it assignes a 2333 // available media player interface 2334 public BrowsedMediaPlayer getBrowsedMediaPlayer(byte[] bdaddr) { 2335 BrowsedMediaPlayer mediaPlayer; 2336 String bdaddrStr = new String(bdaddr); 2337 if (connList.containsKey(bdaddrStr)) { 2338 mediaPlayer = connList.get(bdaddrStr); 2339 } else { 2340 mediaPlayer = new BrowsedMediaPlayer(bdaddr, mContext, mMediaInterface); 2341 connList.put(bdaddrStr, mediaPlayer); 2342 } 2343 return mediaPlayer; 2344 } 2345 2346 // clears the details pertaining to passed bdaddres 2347 public boolean clearBrowsedMediaPlayer(byte[] bdaddr) { 2348 String bdaddrStr = new String(bdaddr); 2349 if (connList.containsKey(bdaddrStr)) { 2350 connList.remove(bdaddrStr); 2351 return true; 2352 } 2353 return false; 2354 } 2355 2356 public Map<String, BrowsedMediaPlayer> getConnList() { 2357 return connList; 2358 } 2359 2360 /* Helper function to convert colon separated bdaddr to byte string */ 2361 private byte[] hexStringToByteArray(String s) { 2362 int len = s.length(); 2363 byte[] data = new byte[len / 2]; 2364 for (int i = 0; i < len; i += 2) { 2365 data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) 2366 + Character.digit(s.charAt(i+1), 16)); 2367 } 2368 return data; 2369 } 2370 } 2371 2372 /* 2373 * private class which handles responses from AvrcpMediaManager. Maps responses to native 2374 * responses. This class implements the AvrcpMediaRspInterface interface. 2375 */ 2376 private class AvrcpMediaRsp implements AvrcpMediaRspInterface { 2377 private static final String TAG = "AvrcpMediaRsp"; 2378 2379 public void setAddrPlayerRsp(byte[] address, int rspStatus) { 2380 if (!setAddressedPlayerRspNative(address, rspStatus)) { 2381 Log.e(TAG, "setAddrPlayerRsp failed!"); 2382 } 2383 } 2384 2385 public void setBrowsedPlayerRsp(byte[] address, int rspStatus, byte depth, int numItems, 2386 String[] textArray) { 2387 if (!setBrowsedPlayerRspNative(address, rspStatus, depth, numItems, textArray)) { 2388 Log.e(TAG, "setBrowsedPlayerRsp failed!"); 2389 } 2390 } 2391 2392 public void mediaPlayerListRsp(byte[] address, int rspStatus, MediaPlayerListRsp rspObj) { 2393 if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) { 2394 if (!mediaPlayerListRspNative(address, rspStatus, sUIDCounter, rspObj.itemType, 2395 rspObj.mNumItems, rspObj.mPlayerIds, rspObj.mPlayerTypes, 2396 rspObj.mPlayerSubTypes, rspObj.mPlayStatusValues, 2397 rspObj.mFeatureBitMaskValues, rspObj.mPlayerNameList)) 2398 Log.e(TAG, "mediaPlayerListRsp failed!"); 2399 } else { 2400 Log.e(TAG, "mediaPlayerListRsp: rspObj is null"); 2401 if (!mediaPlayerListRspNative(address, rspStatus, sUIDCounter, (byte) 0x00, 0, null, 2402 null, null, null, null, null)) 2403 Log.e(TAG, "mediaPlayerListRsp failed!"); 2404 } 2405 } 2406 2407 public void folderItemsRsp(byte[] address, int rspStatus, FolderItemsRsp rspObj) { 2408 if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) { 2409 if (!getFolderItemsRspNative(address, rspStatus, sUIDCounter, rspObj.mScope, 2410 rspObj.mNumItems, rspObj.mFolderTypes, rspObj.mPlayable, rspObj.mItemTypes, 2411 rspObj.mItemUid, rspObj.mDisplayNames, rspObj.mAttributesNum, 2412 rspObj.mAttrIds, rspObj.mAttrValues)) 2413 Log.e(TAG, "getFolderItemsRspNative failed!"); 2414 } else { 2415 Log.e(TAG, "folderItemsRsp: rspObj is null or rspStatus is error:" + rspStatus); 2416 if (!getFolderItemsRspNative(address, rspStatus, sUIDCounter, (byte) 0x00, 0, 2417 null, null, null, null, null, null, null, null)) 2418 Log.e(TAG, "getFolderItemsRspNative failed!"); 2419 } 2420 2421 } 2422 2423 public void changePathRsp(byte[] address, int rspStatus, int numItems) { 2424 if (!changePathRspNative(address, rspStatus, numItems)) 2425 Log.e(TAG, "changePathRspNative failed!"); 2426 } 2427 2428 public void getItemAttrRsp(byte[] address, int rspStatus, ItemAttrRsp rspObj) { 2429 if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) { 2430 if (!getItemAttrRspNative(address, rspStatus, rspObj.mNumAttr, 2431 rspObj.mAttributesIds, rspObj.mAttributesArray)) 2432 Log.e(TAG, "getItemAttrRspNative failed!"); 2433 } else { 2434 Log.e(TAG, "getItemAttrRsp: rspObj is null or rspStatus is error:" + rspStatus); 2435 if (!getItemAttrRspNative(address, rspStatus, (byte) 0x00, null, null)) 2436 Log.e(TAG, "getItemAttrRspNative failed!"); 2437 } 2438 } 2439 2440 public void playItemRsp(byte[] address, int rspStatus) { 2441 if (!playItemRspNative(address, rspStatus)) { 2442 Log.e(TAG, "playItemRspNative failed!"); 2443 } 2444 } 2445 2446 public void getTotalNumOfItemsRsp(byte[] address, int rspStatus, int uidCounter, 2447 int numItems) { 2448 if (!getTotalNumOfItemsRspNative(address, rspStatus, sUIDCounter, numItems)) { 2449 Log.e(TAG, "getTotalNumOfItemsRspNative failed!"); 2450 } 2451 } 2452 2453 public void addrPlayerChangedRsp(int type, int playerId, int uidCounter) { 2454 if (!registerNotificationRspAddrPlayerChangedNative(type, playerId, sUIDCounter)) { 2455 Log.e(TAG, "registerNotificationRspAddrPlayerChangedNative failed!"); 2456 } 2457 } 2458 2459 public void avalPlayerChangedRsp(byte[] address, int type) { 2460 if (!registerNotificationRspAvalPlayerChangedNative(type)) { 2461 Log.e(TAG, "registerNotificationRspAvalPlayerChangedNative failed!"); 2462 } 2463 } 2464 2465 public void uidsChangedRsp(byte[] address, int type, int uidCounter) { 2466 if (!registerNotificationRspUIDsChangedNative(type, sUIDCounter)) { 2467 Log.e(TAG, "registerNotificationRspUIDsChangedNative failed!"); 2468 } 2469 } 2470 2471 public void nowPlayingChangedRsp(int type) { 2472 if (!registerNotificationRspNowPlayingChangedNative(type)) { 2473 Log.e(TAG, "registerNotificationRspNowPlayingChangedNative failed!"); 2474 } 2475 } 2476 2477 public void trackChangedRsp(int type, byte[] uid) { 2478 if (!registerNotificationRspTrackChangeNative(type, uid)) { 2479 Log.e(TAG, "registerNotificationRspTrackChangeNative failed!"); 2480 } 2481 } 2482 } 2483 2484 /* getters for some private variables */ 2485 public AvrcpBrowseManager getAvrcpBrowseManager() { 2486 return mAvrcpBrowseManager; 2487 } 2488 2489 /* PASSTHROUGH COMMAND MANAGEMENT */ 2490 2491 void handlePassthroughCmd(int op, int state) { 2492 int code = avrcpPassthroughToKeyCode(op); 2493 if (code == KeyEvent.KEYCODE_UNKNOWN) { 2494 Log.w(TAG, "Ignoring passthrough of unknown key " + op + " state " + state); 2495 return; 2496 } 2497 int action = KeyEvent.ACTION_DOWN; 2498 if (state == AvrcpConstants.KEY_STATE_RELEASE) action = KeyEvent.ACTION_UP; 2499 KeyEvent event = new KeyEvent(action, code); 2500 if (!KeyEvent.isMediaKey(code)) { 2501 Log.w(TAG, "Passthrough non-media key " + op + " (code " + code + ") state " + state); 2502 } 2503 mMediaSessionManager.dispatchMediaKeyEvent(event); 2504 addKeyPending(event); 2505 } 2506 2507 private int avrcpPassthroughToKeyCode(int operation) { 2508 switch (operation) { 2509 case BluetoothAvrcp.PASSTHROUGH_ID_UP: 2510 return KeyEvent.KEYCODE_DPAD_UP; 2511 case BluetoothAvrcp.PASSTHROUGH_ID_DOWN: 2512 return KeyEvent.KEYCODE_DPAD_DOWN; 2513 case BluetoothAvrcp.PASSTHROUGH_ID_LEFT: 2514 return KeyEvent.KEYCODE_DPAD_LEFT; 2515 case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT: 2516 return KeyEvent.KEYCODE_DPAD_RIGHT; 2517 case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT_UP: 2518 return KeyEvent.KEYCODE_DPAD_UP_RIGHT; 2519 case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT_DOWN: 2520 return KeyEvent.KEYCODE_DPAD_DOWN_RIGHT; 2521 case BluetoothAvrcp.PASSTHROUGH_ID_LEFT_UP: 2522 return KeyEvent.KEYCODE_DPAD_UP_LEFT; 2523 case BluetoothAvrcp.PASSTHROUGH_ID_LEFT_DOWN: 2524 return KeyEvent.KEYCODE_DPAD_DOWN_LEFT; 2525 case BluetoothAvrcp.PASSTHROUGH_ID_0: 2526 return KeyEvent.KEYCODE_NUMPAD_0; 2527 case BluetoothAvrcp.PASSTHROUGH_ID_1: 2528 return KeyEvent.KEYCODE_NUMPAD_1; 2529 case BluetoothAvrcp.PASSTHROUGH_ID_2: 2530 return KeyEvent.KEYCODE_NUMPAD_2; 2531 case BluetoothAvrcp.PASSTHROUGH_ID_3: 2532 return KeyEvent.KEYCODE_NUMPAD_3; 2533 case BluetoothAvrcp.PASSTHROUGH_ID_4: 2534 return KeyEvent.KEYCODE_NUMPAD_4; 2535 case BluetoothAvrcp.PASSTHROUGH_ID_5: 2536 return KeyEvent.KEYCODE_NUMPAD_5; 2537 case BluetoothAvrcp.PASSTHROUGH_ID_6: 2538 return KeyEvent.KEYCODE_NUMPAD_6; 2539 case BluetoothAvrcp.PASSTHROUGH_ID_7: 2540 return KeyEvent.KEYCODE_NUMPAD_7; 2541 case BluetoothAvrcp.PASSTHROUGH_ID_8: 2542 return KeyEvent.KEYCODE_NUMPAD_8; 2543 case BluetoothAvrcp.PASSTHROUGH_ID_9: 2544 return KeyEvent.KEYCODE_NUMPAD_9; 2545 case BluetoothAvrcp.PASSTHROUGH_ID_DOT: 2546 return KeyEvent.KEYCODE_NUMPAD_DOT; 2547 case BluetoothAvrcp.PASSTHROUGH_ID_ENTER: 2548 return KeyEvent.KEYCODE_NUMPAD_ENTER; 2549 case BluetoothAvrcp.PASSTHROUGH_ID_CLEAR: 2550 return KeyEvent.KEYCODE_CLEAR; 2551 case BluetoothAvrcp.PASSTHROUGH_ID_CHAN_UP: 2552 return KeyEvent.KEYCODE_CHANNEL_UP; 2553 case BluetoothAvrcp.PASSTHROUGH_ID_CHAN_DOWN: 2554 return KeyEvent.KEYCODE_CHANNEL_DOWN; 2555 case BluetoothAvrcp.PASSTHROUGH_ID_PREV_CHAN: 2556 return KeyEvent.KEYCODE_LAST_CHANNEL; 2557 case BluetoothAvrcp.PASSTHROUGH_ID_INPUT_SEL: 2558 return KeyEvent.KEYCODE_TV_INPUT; 2559 case BluetoothAvrcp.PASSTHROUGH_ID_DISP_INFO: 2560 return KeyEvent.KEYCODE_INFO; 2561 case BluetoothAvrcp.PASSTHROUGH_ID_HELP: 2562 return KeyEvent.KEYCODE_HELP; 2563 case BluetoothAvrcp.PASSTHROUGH_ID_PAGE_UP: 2564 return KeyEvent.KEYCODE_PAGE_UP; 2565 case BluetoothAvrcp.PASSTHROUGH_ID_PAGE_DOWN: 2566 return KeyEvent.KEYCODE_PAGE_DOWN; 2567 case BluetoothAvrcp.PASSTHROUGH_ID_POWER: 2568 return KeyEvent.KEYCODE_POWER; 2569 case BluetoothAvrcp.PASSTHROUGH_ID_VOL_UP: 2570 return KeyEvent.KEYCODE_VOLUME_UP; 2571 case BluetoothAvrcp.PASSTHROUGH_ID_VOL_DOWN: 2572 return KeyEvent.KEYCODE_VOLUME_DOWN; 2573 case BluetoothAvrcp.PASSTHROUGH_ID_MUTE: 2574 return KeyEvent.KEYCODE_MUTE; 2575 case BluetoothAvrcp.PASSTHROUGH_ID_PLAY: 2576 return KeyEvent.KEYCODE_MEDIA_PLAY; 2577 case BluetoothAvrcp.PASSTHROUGH_ID_STOP: 2578 return KeyEvent.KEYCODE_MEDIA_STOP; 2579 case BluetoothAvrcp.PASSTHROUGH_ID_PAUSE: 2580 return KeyEvent.KEYCODE_MEDIA_PAUSE; 2581 case BluetoothAvrcp.PASSTHROUGH_ID_RECORD: 2582 return KeyEvent.KEYCODE_MEDIA_RECORD; 2583 case BluetoothAvrcp.PASSTHROUGH_ID_REWIND: 2584 return KeyEvent.KEYCODE_MEDIA_REWIND; 2585 case BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR: 2586 return KeyEvent.KEYCODE_MEDIA_FAST_FORWARD; 2587 case BluetoothAvrcp.PASSTHROUGH_ID_EJECT: 2588 return KeyEvent.KEYCODE_MEDIA_EJECT; 2589 case BluetoothAvrcp.PASSTHROUGH_ID_FORWARD: 2590 return KeyEvent.KEYCODE_MEDIA_NEXT; 2591 case BluetoothAvrcp.PASSTHROUGH_ID_BACKWARD: 2592 return KeyEvent.KEYCODE_MEDIA_PREVIOUS; 2593 case BluetoothAvrcp.PASSTHROUGH_ID_F1: 2594 return KeyEvent.KEYCODE_F1; 2595 case BluetoothAvrcp.PASSTHROUGH_ID_F2: 2596 return KeyEvent.KEYCODE_F2; 2597 case BluetoothAvrcp.PASSTHROUGH_ID_F3: 2598 return KeyEvent.KEYCODE_F3; 2599 case BluetoothAvrcp.PASSTHROUGH_ID_F4: 2600 return KeyEvent.KEYCODE_F4; 2601 case BluetoothAvrcp.PASSTHROUGH_ID_F5: 2602 return KeyEvent.KEYCODE_F5; 2603 // Fallthrough for all unknown key mappings 2604 case BluetoothAvrcp.PASSTHROUGH_ID_SELECT: 2605 case BluetoothAvrcp.PASSTHROUGH_ID_ROOT_MENU: 2606 case BluetoothAvrcp.PASSTHROUGH_ID_SETUP_MENU: 2607 case BluetoothAvrcp.PASSTHROUGH_ID_CONT_MENU: 2608 case BluetoothAvrcp.PASSTHROUGH_ID_FAV_MENU: 2609 case BluetoothAvrcp.PASSTHROUGH_ID_EXIT: 2610 case BluetoothAvrcp.PASSTHROUGH_ID_SOUND_SEL: 2611 case BluetoothAvrcp.PASSTHROUGH_ID_ANGLE: 2612 case BluetoothAvrcp.PASSTHROUGH_ID_SUBPICT: 2613 case BluetoothAvrcp.PASSTHROUGH_ID_VENDOR: 2614 default: 2615 return KeyEvent.KEYCODE_UNKNOWN; 2616 } 2617 } 2618 2619 private void addKeyPending(KeyEvent event) { 2620 synchronized (mPassthroughPending) { 2621 mPassthroughPending.add(new MediaKeyLog(System.currentTimeMillis(), event)); 2622 } 2623 } 2624 2625 private void recordKeyDispatched(KeyEvent event, String packageName) { 2626 long time = System.currentTimeMillis(); 2627 Log.v(TAG, "recordKeyDispatched: " + event + " dispatched to " + packageName); 2628 synchronized (mPassthroughPending) { 2629 Iterator<MediaKeyLog> pending = mPassthroughPending.iterator(); 2630 while (pending.hasNext()) { 2631 MediaKeyLog log = pending.next(); 2632 if (log.addDispatch(time, event, packageName)) { 2633 mPassthroughDispatched++; 2634 mPassthroughLogs.add(log); 2635 pending.remove(); 2636 return; 2637 } 2638 } 2639 } 2640 } 2641 2642 private final MediaSessionManager.Callback mButtonDispatchCallback = 2643 new MediaSessionManager.Callback() { 2644 @Override 2645 public void onMediaKeyEventDispatched(KeyEvent event, MediaSession.Token token) { 2646 // Get the package name 2647 android.media.session.MediaController controller = 2648 new android.media.session.MediaController(mContext, token); 2649 String targetPackage = controller.getPackageName(); 2650 recordKeyDispatched(event, targetPackage); 2651 } 2652 2653 @Override 2654 public void onMediaKeyEventDispatched(KeyEvent event, ComponentName receiver) { 2655 recordKeyDispatched(event, receiver.getPackageName()); 2656 } 2657 2658 @Override 2659 public void onAddressedPlayerChanged(MediaSession.Token token) { 2660 setActiveMediaSession(token); 2661 } 2662 2663 @Override 2664 public void onAddressedPlayerChanged(ComponentName receiver) { 2665 // We only get this if there isn't an active media session. 2666 // We can still get a passthrough. 2667 setAddressedMediaSessionPackage(receiver.getPackageName()); 2668 } 2669 }; 2670 2671 // Do not modify without updating the HAL bt_rc.h files. 2672 2673 // match up with btrc_play_status_t enum of bt_rc.h 2674 final static int PLAYSTATUS_STOPPED = 0; 2675 final static int PLAYSTATUS_PLAYING = 1; 2676 final static int PLAYSTATUS_PAUSED = 2; 2677 final static int PLAYSTATUS_FWD_SEEK = 3; 2678 final static int PLAYSTATUS_REV_SEEK = 4; 2679 final static int PLAYSTATUS_ERROR = 255; 2680 2681 // match up with btrc_media_attr_t enum of bt_rc.h 2682 final static int MEDIA_ATTR_TITLE = 1; 2683 final static int MEDIA_ATTR_ARTIST = 2; 2684 final static int MEDIA_ATTR_ALBUM = 3; 2685 final static int MEDIA_ATTR_TRACK_NUM = 4; 2686 final static int MEDIA_ATTR_NUM_TRACKS = 5; 2687 final static int MEDIA_ATTR_GENRE = 6; 2688 final static int MEDIA_ATTR_PLAYING_TIME = 7; 2689 2690 // match up with btrc_event_id_t enum of bt_rc.h 2691 final static int EVT_PLAY_STATUS_CHANGED = 1; 2692 final static int EVT_TRACK_CHANGED = 2; 2693 final static int EVT_TRACK_REACHED_END = 3; 2694 final static int EVT_TRACK_REACHED_START = 4; 2695 final static int EVT_PLAY_POS_CHANGED = 5; 2696 final static int EVT_BATT_STATUS_CHANGED = 6; 2697 final static int EVT_SYSTEM_STATUS_CHANGED = 7; 2698 final static int EVT_APP_SETTINGS_CHANGED = 8; 2699 final static int EVENT_NOW_PLAYING_CONTENT_CHANGED = 9; 2700 final static int EVT_AVBL_PLAYERS_CHANGED = 0xa; 2701 final static int EVT_ADDR_PLAYER_CHANGED = 0xb; 2702 final static int EVENT_UIDS_CHANGED = 0x0c; 2703 2704 private native static void classInitNative(); 2705 private native void initNative(); 2706 private native void cleanupNative(); 2707 private native boolean getPlayStatusRspNative(byte[] address, int playStatus, int songLen, 2708 int songPos); 2709 private native boolean getElementAttrRspNative(byte[] address, byte numAttr, int[] attrIds, 2710 String[] textArray); 2711 private native boolean registerNotificationRspPlayStatusNative(int type, int playStatus); 2712 private native boolean registerNotificationRspTrackChangeNative(int type, byte[] track); 2713 private native boolean registerNotificationRspPlayPosNative(int type, int playPos); 2714 private native boolean setVolumeNative(int volume); 2715 private native boolean sendPassThroughCommandNative(int keyCode, int keyState); 2716 private native boolean setAddressedPlayerRspNative(byte[] address, int rspStatus); 2717 private native boolean setBrowsedPlayerRspNative(byte[] address, int rspStatus, byte depth, 2718 int numItems, String[] textArray); 2719 private native boolean mediaPlayerListRspNative(byte[] address, int rsStatus, int uidCounter, 2720 byte item_type, int numItems, int[] playerIds, byte[] playerTypes, int[] playerSubTypes, 2721 byte[] playStatusValues, short[] featureBitMaskValues, String[] textArray); 2722 private native boolean getFolderItemsRspNative(byte[] address, int rspStatus, short uidCounter, 2723 byte scope, int numItems, byte[] folderTypes, byte[] playable, byte[] itemTypes, 2724 byte[] itemUidArray, String[] textArray, int[] AttributesNum, int[] AttributesIds, 2725 String[] attributesArray); 2726 private native boolean changePathRspNative(byte[] address, int rspStatus, int numItems); 2727 private native boolean getItemAttrRspNative(byte[] address, int rspStatus, byte numAttr, 2728 int[] attrIds, String[] textArray); 2729 private native boolean playItemRspNative(byte[] address, int rspStatus); 2730 private native boolean getTotalNumOfItemsRspNative(byte[] address, int rspStatus, 2731 int uidCounter, int numItems); 2732 private native boolean searchRspNative(byte[] address, int rspStatus, int uidCounter, 2733 int numItems); 2734 private native boolean addToNowPlayingRspNative(byte[] address, int rspStatus); 2735 private native boolean registerNotificationRspAddrPlayerChangedNative(int type, 2736 int playerId, int uidCounter); 2737 private native boolean registerNotificationRspAvalPlayerChangedNative(int type); 2738 private native boolean registerNotificationRspUIDsChangedNative(int type, int uidCounter); 2739 private native boolean registerNotificationRspNowPlayingChangedNative(int type); 2740 2741} 2742