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