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