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