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