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