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