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