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