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