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