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