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