• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothAvrcpController;
21 import android.bluetooth.BluetoothAvrcpPlayerSettings;
22 import android.bluetooth.BluetoothDevice;
23 import android.bluetooth.BluetoothProfile;
24 import android.bluetooth.IBluetoothAvrcpController;
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.media.MediaMetadata;
30 import android.media.session.PlaybackState;
31 import android.os.Handler;
32 import android.os.HandlerThread;
33 import android.os.Looper;
34 import android.os.Message;
35 import android.util.Log;
36 import android.media.AudioManager;
37 import com.android.bluetooth.a2dpsink.A2dpSinkService;
38 import com.android.bluetooth.btservice.ProfileService;
39 import com.android.bluetooth.Utils;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.List;
43 import java.util.HashMap;
44 import java.nio.charset.Charset;
45 import java.nio.ByteBuffer;
46 /**
47  * Provides Bluetooth AVRCP Controller profile, as a service in the Bluetooth application.
48  * @hide
49  */
50 public class AvrcpControllerService extends ProfileService {
51     private static final boolean DBG = AvrcpControllerConstants.DBG;
52     private static final boolean VDBG = AvrcpControllerConstants.VDBG;
53     private static final String TAG = "AvrcpControllerService";
54 
55 /*
56  *  Messages handled by mHandler
57  */
58 
59     RemoteDevice mAvrcpRemoteDevice;
60     RemoteMediaPlayers mRemoteMediaPlayers;
61     NowPlaying mRemoteNowPlayingList;
62 
63     private AvrcpMessageHandler mHandler;
64     private static AvrcpControllerService sAvrcpControllerService;
65     private static AudioManager mAudioManager;
66 
67     private final ArrayList<BluetoothDevice> mConnectedDevices
68             = new ArrayList<BluetoothDevice>();
69 
70     static {
classInitNative()71         classInitNative();
72     }
73 
AvrcpControllerService()74     public AvrcpControllerService() {
75         initNative();
76     }
77 
getName()78     protected String getName() {
79         return TAG;
80     }
81 
initBinder()82     protected IProfileServiceBinder initBinder() {
83         return new BluetoothAvrcpControllerBinder(this);
84     }
85 
start()86     protected boolean start() {
87         HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler");
88         thread.start();
89         Looper looper = thread.getLooper();
90         mHandler = new AvrcpMessageHandler(looper);
91 
92         setAvrcpControllerService(this);
93         mAudioManager = (AudioManager)sAvrcpControllerService.
94                                   getSystemService(Context.AUDIO_SERVICE);
95         return true;
96     }
97 
resetRemoteData()98     protected void resetRemoteData() {
99         try {
100             unregisterReceiver(mBroadcastReceiver);
101         }
102         catch (IllegalArgumentException e) {
103             Log.e(TAG,"Receiver not registered");
104         }
105         if(mAvrcpRemoteDevice != null) {
106             mAvrcpRemoteDevice.cleanup();
107             mAvrcpRemoteDevice = null;
108         }
109         if(mRemoteMediaPlayers != null) {
110             mRemoteMediaPlayers.cleanup();
111             mRemoteMediaPlayers = null;
112         }
113         if(mRemoteNowPlayingList != null) {
114             mRemoteNowPlayingList.cleanup();
115             mRemoteNowPlayingList = null;
116         }
117     }
stop()118     protected boolean stop() {
119         if (mHandler != null) {
120             mHandler.removeCallbacksAndMessages(null);
121             Looper looper = mHandler.getLooper();
122             if (looper != null) {
123                 looper.quit();
124             }
125         }
126         resetRemoteData();
127         return true;
128     }
129 
cleanup()130     protected boolean cleanup() {
131         if (mHandler != null) {
132             mHandler.removeCallbacksAndMessages(null);
133             Looper looper = mHandler.getLooper();
134             if (looper != null) looper.quit();
135         }
136         resetRemoteData();
137         clearAvrcpControllerService();
138         cleanupNative();
139 
140         return true;
141     }
142 
143     //API Methods
144 
getAvrcpControllerService()145     public static synchronized AvrcpControllerService getAvrcpControllerService(){
146         if (sAvrcpControllerService != null && sAvrcpControllerService.isAvailable()) {
147             if (DBG) Log.d(TAG, "getAvrcpControllerService(): returning "
148                     + sAvrcpControllerService);
149             return sAvrcpControllerService;
150         }
151         if (DBG)  {
152             if (sAvrcpControllerService == null) {
153                 Log.d(TAG, "getAvrcpControllerService(): service is NULL");
154             } else if (!(sAvrcpControllerService.isAvailable())) {
155                 Log.d(TAG,"getAvrcpControllerService(): service is not available");
156             }
157         }
158         return null;
159     }
160 
setAvrcpControllerService(AvrcpControllerService instance)161     private static synchronized void setAvrcpControllerService(AvrcpControllerService instance) {
162         if (instance != null && instance.isAvailable()) {
163             if (DBG) Log.d(TAG, "setAvrcpControllerService(): set to: " + sAvrcpControllerService);
164             sAvrcpControllerService = instance;
165         } else {
166             if (DBG)  {
167                 if (sAvrcpControllerService == null) {
168                     Log.d(TAG, "setAvrcpControllerService(): service not available");
169                 } else if (!sAvrcpControllerService.isAvailable()) {
170                     Log.d(TAG,"setAvrcpControllerService(): service is cleaning up");
171                 }
172             }
173         }
174     }
175 
clearAvrcpControllerService()176     private static synchronized void clearAvrcpControllerService() {
177         sAvrcpControllerService = null;
178     }
179 
getConnectedDevices()180     public List<BluetoothDevice> getConnectedDevices() {
181         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
182         return mConnectedDevices;
183     }
184 
getDevicesMatchingConnectionStates(int[] states)185     List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
186         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
187         for (int i = 0; i < states.length; i++) {
188             if (states[i] == BluetoothProfile.STATE_CONNECTED) {
189                 return mConnectedDevices;
190             }
191         }
192         return new ArrayList<BluetoothDevice>();
193     }
194 
getConnectionState(BluetoothDevice device)195     int getConnectionState(BluetoothDevice device) {
196         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
197         return (mConnectedDevices.contains(device) ? BluetoothProfile.STATE_CONNECTED
198                                                 : BluetoothProfile.STATE_DISCONNECTED);
199     }
200 
sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState)201     public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) {
202         Log.v(TAG, "sendGroupNavigationCmd keyCode: " + keyCode + " keyState: " + keyState);
203         if (device == null) {
204             throw new NullPointerException("device == null");
205         }
206         if (!(mConnectedDevices.contains(device))) {
207             for (BluetoothDevice cdevice : mConnectedDevices) {
208                 Log.e(TAG, "Device: " + cdevice);
209             }
210             Log.e(TAG," Device does not match " + device);
211             return;
212         }
213         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
214         Message msg = mHandler.obtainMessage(AvrcpControllerConstants.
215                 MESSAGE_SEND_GROUP_NAVIGATION_CMD,keyCode, keyState, device);
216         mHandler.sendMessage(msg);
217     }
218 
sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState)219     public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
220         Log.v(TAG, "sendPassThroughCmd keyCode: " + keyCode + " keyState: " + keyState);
221         if (device == null) {
222             throw new NullPointerException("device == null");
223         }
224         if (!(mConnectedDevices.contains(device))) {
225             Log.d(TAG," Device does not match");
226             return;
227         }
228         if ((mAvrcpRemoteDevice == null)||
229             (mAvrcpRemoteDevice.mRemoteFeatures == AvrcpControllerConstants.BTRC_FEAT_NONE)||
230             (mRemoteMediaPlayers == null) ||
231             (mRemoteMediaPlayers.getAddressedPlayer() == null)){
232             Log.d(TAG," Device connected but PlayState not present ");
233             enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
234             Message msg = mHandler.obtainMessage(AvrcpControllerConstants.MESSAGE_SEND_PASS_THROUGH_CMD,
235                     keyCode, keyState, device);
236             mHandler.sendMessage(msg);
237             return;
238         }
239         boolean sendCommand = false;
240         switch(keyCode) {
241             case BluetoothAvrcpController.PASS_THRU_CMD_ID_PLAY:
242                 sendCommand  = (mRemoteMediaPlayers.getPlayStatus() ==
243                                        AvrcpControllerConstants.PLAY_STATUS_STOPPED)||
244                                (mRemoteMediaPlayers.getPlayStatus() ==
245                                        AvrcpControllerConstants.PLAY_STATUS_PAUSED) ||
246                                 (mRemoteMediaPlayers.getPlayStatus() ==
247                                        AvrcpControllerConstants.PLAY_STATUS_PLAYING);
248                 break;
249             case BluetoothAvrcpController.PASS_THRU_CMD_ID_PAUSE:
250             /*
251              * allowing pause command in pause state to handle A2DP Sink Concurrency
252              * If call is ongoing and Start is initiated from remote, we will send pause again
253              * If acquireFocus fails, we will send Pause again
254              * To Stop sending multiple Pause, check in application.
255              */
256                 sendCommand  = (mRemoteMediaPlayers.getPlayStatus() ==
257                                        AvrcpControllerConstants.PLAY_STATUS_PLAYING)||
258                                (mRemoteMediaPlayers.getPlayStatus() ==
259                                        AvrcpControllerConstants.PLAY_STATUS_FWD_SEEK)||
260                                (mRemoteMediaPlayers.getPlayStatus() ==
261                                        AvrcpControllerConstants.PLAY_STATUS_STOPPED)||
262                                (mRemoteMediaPlayers.getPlayStatus() ==
263                                        AvrcpControllerConstants.PLAY_STATUS_PAUSED)||
264                                (mRemoteMediaPlayers.getPlayStatus() ==
265                                        AvrcpControllerConstants.PLAY_STATUS_REV_SEEK);
266                 break;
267             case BluetoothAvrcpController.PASS_THRU_CMD_ID_STOP:
268                 sendCommand  = (mRemoteMediaPlayers.getPlayStatus() ==
269                                        AvrcpControllerConstants.PLAY_STATUS_PLAYING)||
270                                (mRemoteMediaPlayers.getPlayStatus() ==
271                                        AvrcpControllerConstants.PLAY_STATUS_FWD_SEEK)||
272                                (mRemoteMediaPlayers.getPlayStatus() ==
273                                        AvrcpControllerConstants.PLAY_STATUS_REV_SEEK)||
274                                (mRemoteMediaPlayers.getPlayStatus() ==
275                                        AvrcpControllerConstants.PLAY_STATUS_STOPPED)||
276                                (mRemoteMediaPlayers.getPlayStatus() ==
277                                        AvrcpControllerConstants.PLAY_STATUS_PAUSED);
278                 break;
279             case BluetoothAvrcpController.PASS_THRU_CMD_ID_BACKWARD:
280             case BluetoothAvrcpController.PASS_THRU_CMD_ID_FORWARD:
281             case BluetoothAvrcpController.PASS_THRU_CMD_ID_FF:
282             case BluetoothAvrcpController.PASS_THRU_CMD_ID_REWIND:
283                 sendCommand = true; // we can send this command in all states
284                 break;
285         }
286         if (sendCommand) {
287             enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
288             Message msg = mHandler.obtainMessage(AvrcpControllerConstants.MESSAGE_SEND_PASS_THROUGH_CMD,
289                 keyCode, keyState, device);
290             mHandler.sendMessage(msg);
291         }
292         else {
293             Log.e(TAG," Not in right state, don't send Pass Thru cmd ");
294         }
295     }
296 
startAvrcpUpdates()297     public void startAvrcpUpdates() {
298         mHandler.obtainMessage(
299             AvrcpControllerConstants.MESSAGE_START_METADATA_BROADCASTS).sendToTarget();
300     }
301 
stopAvrcpUpdates()302     public void stopAvrcpUpdates() {
303         mHandler.obtainMessage(
304             AvrcpControllerConstants.MESSAGE_STOP_METADATA_BROADCASTS).sendToTarget();
305     }
306 
getMetaData(BluetoothDevice device)307     public MediaMetadata getMetaData(BluetoothDevice device) {
308         Log.d(TAG, "getMetaData = ");
309         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
310         if((mRemoteNowPlayingList != null) && (mRemoteNowPlayingList.getCurrentTrack() != null)) {
311             return getCurrentMetaData(AvrcpControllerConstants.AVRCP_SCOPE_NOW_PLAYING, 0);
312         }
313         else
314             return null;
315     }
getPlaybackState(BluetoothDevice device)316     public PlaybackState getPlaybackState(BluetoothDevice device) {
317         if (DBG) Log.d(TAG, "getPlayBackState device = "+ device);
318         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
319         return getCurrentPlayBackState();
320     }
getPlayerSettings(BluetoothDevice device)321     public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) {
322         if (DBG) Log.d(TAG, "getPlayerApplicationSetting ");
323         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
324         return getCurrentPlayerAppSetting();
325     }
setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting)326     public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) {
327         if ((mAvrcpRemoteDevice == null)||(mRemoteMediaPlayers == null)) {
328             return false;
329         }
330         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
331         /*
332          * We have to extract values from BluetoothAvrcpPlayerSettings
333          */
334         int mSettings = plAppSetting.getSettings();
335         int numAttributes = 0;
336         /* calculate number of attributes in request */
337         while(mSettings > 0) {
338             numAttributes += ((mSettings & 0x01)!= 0)?1: 0;
339             mSettings = mSettings >> 1;
340         }
341         byte[] attribArray = new byte [2*numAttributes];
342         mSettings = plAppSetting.getSettings();
343         /*
344          * Now we will flatten it <id, val>
345          */
346         int i = 0;
347         if((mSettings & BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER) != 0) {
348             attribArray[i++] = AvrcpControllerConstants.ATTRIB_EQUALIZER_STATUS;
349             attribArray[i++] = (byte)AvrcpUtils.mapAvrcpPlayerSettingstoBTAttribVal(
350                     BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER, plAppSetting.
351                     getSettingValue(BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER));
352         }
353         if((mSettings & BluetoothAvrcpPlayerSettings.SETTING_REPEAT) != 0) {
354             attribArray[i++] = AvrcpControllerConstants.ATTRIB_REPEAT_STATUS;
355             attribArray[i++] = (byte)AvrcpUtils.mapAvrcpPlayerSettingstoBTAttribVal(
356                     BluetoothAvrcpPlayerSettings.SETTING_REPEAT, plAppSetting.
357                     getSettingValue(BluetoothAvrcpPlayerSettings.SETTING_REPEAT));
358         }
359         if((mSettings & BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE) != 0) {
360             attribArray[i++] = AvrcpControllerConstants.ATTRIB_SHUFFLE_STATUS;
361             attribArray[i++] = (byte)AvrcpUtils.mapAvrcpPlayerSettingstoBTAttribVal(
362                     BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE, plAppSetting.
363                     getSettingValue(BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE));
364         }
365         if((mSettings & BluetoothAvrcpPlayerSettings.SETTING_SCAN) != 0) {
366             attribArray[i++] = AvrcpControllerConstants.ATTRIB_SCAN_STATUS;
367             attribArray[i++] = (byte)AvrcpUtils.mapAvrcpPlayerSettingstoBTAttribVal(
368                     BluetoothAvrcpPlayerSettings.SETTING_SCAN, plAppSetting.
369                     getSettingValue(BluetoothAvrcpPlayerSettings.SETTING_SCAN));
370         }
371         boolean isSettingSupported = mRemoteMediaPlayers.getAddressedPlayer().
372                                    isPlayerAppSettingSupported((byte)numAttributes, attribArray);
373         if(isSettingSupported) {
374             ByteBuffer bb = ByteBuffer.wrap(attribArray, 0, (2*numAttributes));
375              Message msg = mHandler.obtainMessage(AvrcpControllerConstants.
376                 MESSAGE_SEND_SET_CURRENT_PLAYER_APPLICATION_SETTINGS, numAttributes, 0, bb);
377             mHandler.sendMessage(msg);
378         }
379         return isSettingSupported;
380     }
381 
382     //Binder object: Must be static class or memory leak may occur
383     private static class BluetoothAvrcpControllerBinder extends IBluetoothAvrcpController.Stub
384         implements IProfileServiceBinder {
385         private AvrcpControllerService mService;
386 
getService()387         private AvrcpControllerService getService() {
388             if (!Utils.checkCaller()) {
389                 Log.w(TAG,"AVRCP call not allowed for non-active user");
390                 return null;
391             }
392 
393             if (mService != null && mService.isAvailable()) {
394                 return mService;
395             }
396             return null;
397         }
398 
BluetoothAvrcpControllerBinder(AvrcpControllerService svc)399         BluetoothAvrcpControllerBinder(AvrcpControllerService svc) {
400             mService = svc;
401         }
402 
cleanup()403         public boolean cleanup()  {
404             mService = null;
405             return true;
406         }
407 
getConnectedDevices()408         public List<BluetoothDevice> getConnectedDevices() {
409             AvrcpControllerService service = getService();
410             if (service == null) return new ArrayList<BluetoothDevice>(0);
411             return service.getConnectedDevices();
412         }
413 
getDevicesMatchingConnectionStates(int[] states)414         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
415             AvrcpControllerService service = getService();
416             if (service == null) return new ArrayList<BluetoothDevice>(0);
417             return service.getDevicesMatchingConnectionStates(states);
418         }
419 
getConnectionState(BluetoothDevice device)420         public int getConnectionState(BluetoothDevice device) {
421             AvrcpControllerService service = getService();
422             if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
423             return service.getConnectionState(device);
424         }
425 
sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState)426         public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
427             Log.v(TAG,"Binder Call: sendPassThroughCmd");
428             AvrcpControllerService service = getService();
429             if (service == null) return;
430             service.sendPassThroughCmd(device, keyCode, keyState);
431         }
432 
433         @Override
sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState)434         public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) {
435             Log.v(TAG,"Binder Call: sendGroupNavigationCmd");
436             AvrcpControllerService service = getService();
437             if (service == null) return;
438             service.sendGroupNavigationCmd(device, keyCode, keyState);
439         }
440 
441         @Override
getPlayerSettings(BluetoothDevice device)442         public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) {
443             Log.v(TAG,"Binder Call: getPlayerApplicationSetting ");
444             AvrcpControllerService service = getService();
445             if (service == null) return null;
446             return service.getPlayerSettings(device);
447         }
448 
449         @Override
getMetadata(BluetoothDevice device)450         public MediaMetadata getMetadata(BluetoothDevice device) {
451             Log.v(TAG,"Binder Call: getMetaData ");
452             AvrcpControllerService service = getService();
453             if (service == null) return null;
454             return service.getMetaData(device);
455         }
456 
457         @Override
getPlaybackState(BluetoothDevice device)458         public PlaybackState getPlaybackState(BluetoothDevice device) {
459             Log.v(TAG,"Binder Call: getPlaybackState");
460             AvrcpControllerService service = getService();
461             if (service == null) return null;
462             return service.getPlaybackState(device);
463         }
464 
465         @Override
setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting)466         public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) {
467             Log.v(TAG,"Binder Call: setPlayerApplicationSetting " );
468             AvrcpControllerService service = getService();
469             if (service == null) return false;
470             return service.setPlayerApplicationSetting(plAppSetting);
471         }
472     };
473 
utf8ToString(byte[] input)474     private String utf8ToString(byte[] input)
475     {
476         Charset UTF8_CHARSET = Charset.forName("UTF-8");
477         return new String(input,UTF8_CHARSET);
478     }
asciiToInt(int len, byte[] array)479     private int asciiToInt(int len, byte[] array)
480     {
481         return Integer.parseInt(utf8ToString(array));
482     }
getCurrentPlayerAppSetting()483     private BluetoothAvrcpPlayerSettings getCurrentPlayerAppSetting() {
484         if((mRemoteMediaPlayers == null) || (mRemoteMediaPlayers.getAddressedPlayer() == null))
485             return null;
486         return mRemoteMediaPlayers.getAddressedPlayer().getSupportedPlayerAppSetting();
487     }
getCurrentPlayBackState()488     private PlaybackState getCurrentPlayBackState() {
489         if ((mRemoteMediaPlayers == null) || (mRemoteMediaPlayers.getAddressedPlayer() == null)) {
490             return new PlaybackState.Builder().setState(PlaybackState.STATE_ERROR,
491                                                         PlaybackState.PLAYBACK_POSITION_UNKNOWN,
492                                                         0).build();
493         }
494         return AvrcpUtils.mapBtPlayStatustoPlayBackState(
495                 mRemoteMediaPlayers.getAddressedPlayer().mPlayStatus,
496                 mRemoteMediaPlayers.getAddressedPlayer().mPlayTime);
497     }
getCurrentMetaData(int scope, int trackId)498     private MediaMetadata getCurrentMetaData(int scope, int trackId) {
499         /* if scope is now playing */
500         if(scope == AvrcpControllerConstants.AVRCP_SCOPE_NOW_PLAYING) {
501             if((mRemoteNowPlayingList == null) || (mRemoteNowPlayingList.
502                                                            getTrackFromId(trackId) == null))
503                 return null;
504             TrackInfo mNowPlayingTrack = mRemoteNowPlayingList.getTrackFromId(trackId);
505             return AvrcpUtils.getMediaMetaData(mNowPlayingTrack);
506         }
507         /* if scope is now playing */
508         else if(scope == AvrcpControllerConstants.AVRCP_SCOPE_VFS) {
509             /* TODO for browsing */
510         }
511         return null;
512     }
broadcastMetaDataChanged(MediaMetadata mMetaData)513     private void broadcastMetaDataChanged(MediaMetadata mMetaData) {
514         Intent intent = new Intent(BluetoothAvrcpController.ACTION_TRACK_EVENT);
515         intent.putExtra(BluetoothAvrcpController.EXTRA_METADATA, mMetaData);
516         if(DBG) Log.d(TAG," broadcastMetaDataChanged = " +
517                                                    AvrcpUtils.displayMetaData(mMetaData));
518         sendBroadcast(intent, ProfileService.BLUETOOTH_PERM);
519     }
broadcastPlayBackStateChanged(PlaybackState state)520     private void broadcastPlayBackStateChanged(PlaybackState state) {
521         Intent intent = new Intent(BluetoothAvrcpController.ACTION_TRACK_EVENT);
522         intent.putExtra(BluetoothAvrcpController.EXTRA_PLAYBACK, state);
523         if(DBG) Log.d(TAG," broadcastPlayBackStateChanged = " + state.toString());
524         sendBroadcast(intent, ProfileService.BLUETOOTH_PERM);
525     }
broadcastPlayerAppSettingChanged(BluetoothAvrcpPlayerSettings mPlAppSetting)526     private void broadcastPlayerAppSettingChanged(BluetoothAvrcpPlayerSettings mPlAppSetting) {
527         Intent intent = new Intent(BluetoothAvrcpController.ACTION_PLAYER_SETTING);
528         intent.putExtra(BluetoothAvrcpController.EXTRA_PLAYER_SETTING, mPlAppSetting);
529         if(DBG) Log.d(TAG," broadcastPlayerAppSettingChanged = " +
530                 AvrcpUtils.displayBluetoothAvrcpSettings(mPlAppSetting));
531         sendBroadcast(intent, ProfileService.BLUETOOTH_PERM);
532     }
533     /** Handles Avrcp messages. */
534     private final class AvrcpMessageHandler extends Handler {
535         private boolean mBroadcastMetadata = false;
536 
AvrcpMessageHandler(Looper looper)537         private AvrcpMessageHandler(Looper looper) {
538             super(looper);
539         }
540 
541         @Override
handleMessage(Message msg)542         public void handleMessage(Message msg) {
543             Log.d(TAG," HandleMessage: "+ AvrcpControllerConstants.dumpMessageString(msg.what) +
544                   " Remote Connected " + !mConnectedDevices.isEmpty());
545             A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService();
546             switch (msg.what) {
547             case AvrcpControllerConstants.MESSAGE_STOP_METADATA_BROADCASTS:
548                 // Any messages hence forth about play pos/play status/song info will be ignored.
549                 if(mRemoteMediaPlayers != null) {
550                     // Mock the current state to *look like* it is paused. The remote play state is
551                     // still cached in mRemoteMediaPlayers and will be restored when the
552                     // startAvrcpUpdates is called again.
553                     broadcastPlayBackStateChanged(AvrcpUtils.mapBtPlayStatustoPlayBackState
554                             ((byte) AvrcpControllerConstants.PLAY_STATUS_PAUSED,
555                              mRemoteMediaPlayers.getAddressedPlayer().mPlayTime));
556                 }
557                 mBroadcastMetadata = false;
558                 break;
559             case AvrcpControllerConstants.MESSAGE_START_METADATA_BROADCASTS:
560                 // Any messages hence forth about play pos/play status/song info will be sent.
561                 if(mRemoteMediaPlayers != null) {
562                     broadcastPlayBackStateChanged(getCurrentPlayBackState());
563                     broadcastMetaDataChanged(
564                         getCurrentMetaData(AvrcpControllerConstants.AVRCP_SCOPE_NOW_PLAYING, 0));
565                 }
566                 mBroadcastMetadata = true;
567                 break;
568             case AvrcpControllerConstants.MESSAGE_SEND_PASS_THROUGH_CMD:
569                 BluetoothDevice device = (BluetoothDevice)msg.obj;
570                 sendPassThroughCommandNative(getByteAddress(device), msg.arg1, msg.arg2);
571                 if((a2dpSinkService != null)&&(!mConnectedDevices.isEmpty())) {
572                     Log.d(TAG," inform AVRCP Commands to A2DP Sink ");
573                     a2dpSinkService.informAvrcpPassThroughCmd(device, msg.arg1, msg.arg2);
574                 }
575                 break;
576             case AvrcpControllerConstants.MESSAGE_SEND_GROUP_NAVIGATION_CMD:
577                 BluetoothDevice peerDevice = (BluetoothDevice)msg.obj;
578                 sendGroupNavigationCommandNative(getByteAddress(peerDevice), msg.arg1, msg.arg2);
579                 break;
580             case AvrcpControllerConstants.MESSAGE_SEND_SET_CURRENT_PLAYER_APPLICATION_SETTINGS:
581                 byte numAttributes = (byte)msg.arg1;
582                 ByteBuffer bbRsp = (ByteBuffer)msg.obj;
583                 byte[] attributeIds = new byte [numAttributes];
584                 byte[] attributeVals = new byte [numAttributes];
585                 for(int i = 0; (bbRsp.hasRemaining())&&(i < numAttributes); i++) {
586                     attributeIds[i] = bbRsp.get();
587                     attributeVals[i] = bbRsp.get();
588                 }
589                 setPlayerApplicationSettingValuesNative(getByteAddress(mAvrcpRemoteDevice.mBTDevice),
590                         numAttributes, attributeIds, attributeVals);
591                 break;
592 
593             case AvrcpControllerConstants.MESSAGE_PROCESS_CONNECTION_CHANGE:
594                 int newState = msg.arg1;
595                 int oldState = msg.arg2;
596                 BluetoothDevice rtDevice =  (BluetoothDevice)msg.obj;
597                 if ((newState == BluetoothProfile.STATE_CONNECTED) &&
598                     (oldState == BluetoothProfile.STATE_DISCONNECTED)) {
599                     /* We create RemoteDevice and MediaPlayerList here
600                      * Now playing list after RC features
601                      */
602                     if(mAvrcpRemoteDevice == null){
603                         mAvrcpRemoteDevice =  new RemoteDevice(rtDevice);
604                         /* Remote will have a player irrespective of AVRCP Version
605                          * Create a Default player, we will add entries in case Browsing
606                          * is supported by remote
607                          */
608                         if(mRemoteMediaPlayers == null) {
609                             mRemoteMediaPlayers = new RemoteMediaPlayers(mAvrcpRemoteDevice);
610                             PlayerInfo mPlayer = new PlayerInfo();
611                             mPlayer.mPlayerId = 0;
612                             mRemoteMediaPlayers.addPlayer(mPlayer);
613                             mRemoteMediaPlayers.setAddressedPlayer(mPlayer);
614                         }
615                     }
616                 }
617                 else if ((newState == BluetoothProfile.STATE_DISCONNECTED) &&
618                         (oldState == BluetoothProfile.STATE_CONNECTED)) /* connection down */
619                 {
620                     resetRemoteData();
621                     mHandler.removeCallbacksAndMessages(null);
622                 }
623                 /*
624                  * Send intent now
625                  */
626                 Intent intent = new Intent(BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED);
627                 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, oldState);
628                 intent.putExtra(BluetoothProfile.EXTRA_STATE, newState);
629                 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, rtDevice);
630 //              intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
631                 sendBroadcast(intent, ProfileService.BLUETOOTH_PERM);
632                 break;
633             case AvrcpControllerConstants.MESSAGE_PROCESS_RC_FEATURES:
634                 if(mAvrcpRemoteDevice == null)
635                     break;
636                 mAvrcpRemoteDevice.mRemoteFeatures = msg.arg1;
637                 /* in case of AVRCP version < 1.3, no need to add track info */
638                 if(mAvrcpRemoteDevice.isMetaDataSupported()) {
639                     if(mRemoteNowPlayingList == null)
640                         mRemoteNowPlayingList = new NowPlaying(mAvrcpRemoteDevice);
641                     TrackInfo mTrack = new TrackInfo();
642                     /* First element of NowPlayingList will be current Track
643                      * for 1.3 this will be the only song
644                      * for >= 1.4, others songs will have non-zero UID
645                      */
646                     mTrack.mItemUid = 0;
647                     mRemoteNowPlayingList.addTrack(mTrack);
648                     mRemoteNowPlayingList.setCurrTrack(mTrack);
649                 }
650                 break;
651             case AvrcpControllerConstants.MESSAGE_PROCESS_SET_ABS_VOL_CMD:
652                 mAvrcpRemoteDevice.mAbsVolNotificationState =
653                                          AvrcpControllerConstants.DEFER_VOLUME_CHANGE_RSP;
654                 setAbsVolume(msg.arg1, msg.arg2);
655                 break;
656             case AvrcpControllerConstants.MESSAGE_PROCESS_REGISTER_ABS_VOL_NOTIFICATION:
657                 /* start BroadcastReceiver now */
658                 IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
659                 mAvrcpRemoteDevice.mNotificationLabel = msg.arg1;
660                 mAvrcpRemoteDevice.mAbsVolNotificationState =
661                         AvrcpControllerConstants.SEND_VOLUME_CHANGE_RSP;
662                 registerReceiver(mBroadcastReceiver, filter);
663                 int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
664                 int currIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
665                 int percentageVol = ((currIndex* AvrcpControllerConstants.ABS_VOL_BASE)/maxVolume);
666                 Log.d(TAG," Sending Interim Response = "+ percentageVol + " label " + msg.arg1);
667                 sendRegisterAbsVolRspNative(getByteAddress(mAvrcpRemoteDevice.mBTDevice),
668                         (byte)AvrcpControllerConstants.NOTIFICATION_RSP_TYPE_INTERIM, percentageVol,
669                         mAvrcpRemoteDevice.mNotificationLabel);
670                 break;
671             case AvrcpControllerConstants.MESSAGE_PROCESS_TRACK_CHANGED:
672                 if(mRemoteNowPlayingList != null) {
673                     mRemoteNowPlayingList.updateCurrentTrack((TrackInfo)msg.obj);
674 
675                     if (!mBroadcastMetadata) {
676                         Log.d(TAG, "Metadata is not broadcasted, ignoring.");
677                         return;
678                     }
679 
680                     broadcastMetaDataChanged(AvrcpUtils.getMediaMetaData
681                                        (mRemoteNowPlayingList.getCurrentTrack()));
682                 }
683                 break;
684             case AvrcpControllerConstants.MESSAGE_PROCESS_PLAY_POS_CHANGED:
685                 if(mRemoteMediaPlayers != null) {
686                     mRemoteMediaPlayers.getAddressedPlayer().mPlayTime = msg.arg2;
687 
688                     if (!mBroadcastMetadata) {
689                         Log.d(TAG, "Metadata is not broadcasted, ignoring.");
690                         return;
691                     }
692 
693                     broadcastPlayBackStateChanged(AvrcpUtils.mapBtPlayStatustoPlayBackState
694                             (mRemoteMediaPlayers.getAddressedPlayer().mPlayStatus,
695                                     mRemoteMediaPlayers.getAddressedPlayer().mPlayTime));
696                 }
697                 if(mRemoteNowPlayingList != null) {
698                     mRemoteNowPlayingList.getCurrentTrack().mTrackLen = msg.arg1;
699                 }
700                 break;
701             case AvrcpControllerConstants.MESSAGE_PROCESS_PLAY_STATUS_CHANGED:
702                 if(mRemoteMediaPlayers != null) {
703                     int status = msg.arg1;
704                     mRemoteMediaPlayers.getAddressedPlayer().mPlayStatus = (byte) status;
705                     if (status == AvrcpControllerConstants.PLAY_STATUS_PLAYING) {
706                         a2dpSinkService.informTGStatePlaying(mConnectedDevices.get(0), true);
707                     } else if (status == AvrcpControllerConstants.PLAY_STATUS_PAUSED ||
708                                status == AvrcpControllerConstants.PLAY_STATUS_STOPPED) {
709                         a2dpSinkService.informTGStatePlaying(mConnectedDevices.get(0), false);
710                     }
711 
712                     if (mBroadcastMetadata) {
713                         broadcastPlayBackStateChanged(AvrcpUtils.mapBtPlayStatustoPlayBackState
714                                 (mRemoteMediaPlayers.getAddressedPlayer().mPlayStatus,
715                                  mRemoteMediaPlayers.getAddressedPlayer().mPlayTime));
716                     } else {
717                         Log.d(TAG, "Metadata is not broadcasted, ignoring.");
718                         return;
719                     }
720                 }
721                 break;
722             case AvrcpControllerConstants.MESSAGE_PROCESS_SUPPORTED_PLAYER_APP_SETTING:
723                 if(mRemoteMediaPlayers != null)
724                     mRemoteMediaPlayers.getAddressedPlayer().
725                                            setSupportedPlayerAppSetting((ByteBuffer)msg.obj);
726                 break;
727             case AvrcpControllerConstants.MESSAGE_PROCESS_PLAYER_APP_SETTING_CHANGED:
728                 if(mRemoteMediaPlayers != null) {
729                     mRemoteMediaPlayers.getAddressedPlayer().
730                                            updatePlayerAppSetting((ByteBuffer)msg.obj);
731                     broadcastPlayerAppSettingChanged(getCurrentPlayerAppSetting());
732                 }
733                 break;
734             }
735         }
736     }
737 
setAbsVolume(int absVol, int label)738     private void setAbsVolume(int absVol, int label)
739     {
740         int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
741         int currIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
742         if (mAvrcpRemoteDevice.mFirstAbsVolCmdRecvd) {
743             int newIndex = (maxVolume*absVol)/AvrcpControllerConstants.ABS_VOL_BASE;
744             Log.d(TAG," setAbsVolume ="+absVol + " maxVol = " + maxVolume + " cur = " + currIndex +
745                                               " new = "+newIndex);
746             /*
747              * In some cases change in percentage is not sufficient enough to warrant
748              * change in index values which are in range of 0-15. For such cases
749              * no action is required
750              */
751             if (newIndex != currIndex) {
752                 mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, newIndex,
753                                                      AudioManager.FLAG_SHOW_UI);
754             }
755         }
756         else {
757             mAvrcpRemoteDevice.mFirstAbsVolCmdRecvd = true;
758             absVol = (currIndex*AvrcpControllerConstants.ABS_VOL_BASE)/maxVolume;
759             Log.d(TAG," SetAbsVol recvd for first time, respond with " + absVol);
760         }
761         sendAbsVolRspNative(getByteAddress(mAvrcpRemoteDevice.mBTDevice), absVol, label);
762     }
763 
764     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
765         @Override
766         public void onReceive(Context context, Intent intent) {
767             String action = intent.getAction();
768             if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
769                 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
770                 if (streamType == AudioManager.STREAM_MUSIC) {
771                     int streamValue = intent
772                             .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
773                     int streamPrevValue = intent.getIntExtra(
774                             AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1);
775                     if (streamValue != -1 && streamValue != streamPrevValue) {
776                         if ((mAvrcpRemoteDevice == null)
777                             ||((mAvrcpRemoteDevice.mRemoteFeatures &
778                                     AvrcpControllerConstants.BTRC_FEAT_ABSOLUTE_VOLUME) == 0)
779                             ||(mConnectedDevices.isEmpty()))
780                             return;
781                         if(mAvrcpRemoteDevice.mAbsVolNotificationState ==
782                                 AvrcpControllerConstants.SEND_VOLUME_CHANGE_RSP) {
783                             int maxVol = mAudioManager.
784                                                   getStreamMaxVolume(AudioManager.STREAM_MUSIC);
785                             int currIndex = mAudioManager.
786                                                   getStreamVolume(AudioManager.STREAM_MUSIC);
787                             int percentageVol = ((currIndex*
788                                             AvrcpControllerConstants.ABS_VOL_BASE)/maxVol);
789                             Log.d(TAG," Abs Vol Notify Rsp Changed vol = "+ percentageVol);
790                             sendRegisterAbsVolRspNative(getByteAddress(mAvrcpRemoteDevice.mBTDevice),
791                                 (byte)AvrcpControllerConstants.NOTIFICATION_RSP_TYPE_CHANGED,
792                                     percentageVol, mAvrcpRemoteDevice.mNotificationLabel);
793                         }
794                         else if (mAvrcpRemoteDevice.mAbsVolNotificationState ==
795                                 AvrcpControllerConstants.DEFER_VOLUME_CHANGE_RSP) {
796                             Log.d(TAG," Don't Complete Notification Rsp. ");
797                             mAvrcpRemoteDevice.mAbsVolNotificationState =
798                                               AvrcpControllerConstants.SEND_VOLUME_CHANGE_RSP;
799                         }
800                     }
801                 }
802             }
803         }
804     };
805 
handlePassthroughRsp(int id, int keyState)806     private void handlePassthroughRsp(int id, int keyState) {
807         Log.d(TAG, "passthrough response received as: key: " + id + " state: " + keyState);
808     }
809 
onConnectionStateChanged(boolean connected, byte[] address)810     private void onConnectionStateChanged(boolean connected, byte[] address) {
811         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
812             (Utils.getAddressStringFromByte(address));
813         Log.d(TAG, "onConnectionStateChanged " + connected + " " + device+ " size "+
814                     mConnectedDevices.size());
815         if (device == null)
816             return;
817         int oldState = (mConnectedDevices.contains(device) ? BluetoothProfile.STATE_CONNECTED
818                                                         : BluetoothProfile.STATE_DISCONNECTED);
819         int newState = (connected ? BluetoothProfile.STATE_CONNECTED
820                                   : BluetoothProfile.STATE_DISCONNECTED);
821 
822         if (connected && oldState == BluetoothProfile.STATE_DISCONNECTED) {
823             /* AVRCPControllerService supports single connection */
824             if(mConnectedDevices.size() > 0) {
825                 Log.d(TAG,"A Connection already exists, returning");
826                 return;
827             }
828             mConnectedDevices.add(device);
829             Message msg =  mHandler.obtainMessage(
830                     AvrcpControllerConstants.MESSAGE_PROCESS_CONNECTION_CHANGE, newState,
831                         oldState, device);
832             mHandler.sendMessage(msg);
833         } else if (!connected && oldState == BluetoothProfile.STATE_CONNECTED) {
834             mConnectedDevices.remove(device);
835             Message msg =  mHandler.obtainMessage(
836                     AvrcpControllerConstants.MESSAGE_PROCESS_CONNECTION_CHANGE, newState,
837                         oldState, device);
838             mHandler.sendMessage(msg);
839         }
840     }
841 
getRcFeatures(byte[] address, int features)842     private void getRcFeatures(byte[] address, int features) {
843         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
844                 (Utils.getAddressStringFromByte(address));
845         Message msg = mHandler.obtainMessage(
846                 AvrcpControllerConstants.MESSAGE_PROCESS_RC_FEATURES, features, 0, device);
847         mHandler.sendMessage(msg);
848     }
setPlayerAppSettingRsp(byte[] address, byte accepted)849     private void setPlayerAppSettingRsp(byte[] address, byte accepted) {
850               /* TODO do we need to do anything here */
851     }
handleRegisterNotificationAbsVol(byte[] address, byte label)852     private void handleRegisterNotificationAbsVol(byte[] address, byte label)
853     {
854         Log.d(TAG,"handleRegisterNotificationAbsVol ");
855         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
856                 (Utils.getAddressStringFromByte(address));
857         if (!mConnectedDevices.contains(device))
858             return;
859         Message msg = mHandler.obtainMessage(AvrcpControllerConstants.
860                 MESSAGE_PROCESS_REGISTER_ABS_VOL_NOTIFICATION, label, 0);
861         mHandler.sendMessage(msg);
862     }
863 
handleSetAbsVolume(byte[] address, byte absVol, byte label)864     private void handleSetAbsVolume(byte[] address, byte absVol, byte label)
865     {
866         Log.d(TAG,"handleSetAbsVolume ");
867         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
868                 (Utils.getAddressStringFromByte(address));
869         if (!mConnectedDevices.contains(device))
870             return;
871         Message msg = mHandler.obtainMessage(
872                 AvrcpControllerConstants.MESSAGE_PROCESS_SET_ABS_VOL_CMD, absVol, label);
873         mHandler.sendMessage(msg);
874     }
875 
onTrackChanged(byte[] address, byte numAttributes, int[] attributes, String[] attribVals)876     private void onTrackChanged(byte[] address, byte numAttributes, int[] attributes,
877                                                String[] attribVals)
878     {
879         Log.d(TAG,"onTrackChanged ");
880         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
881                 (Utils.getAddressStringFromByte(address));
882         if (!mConnectedDevices.contains(device))
883             return;
884         TrackInfo mTrack = new TrackInfo(0, numAttributes, attributes, attribVals);
885         Message msg = mHandler.obtainMessage(AvrcpControllerConstants.
886                 MESSAGE_PROCESS_TRACK_CHANGED, numAttributes, 0, mTrack);
887         mHandler.sendMessage(msg);
888     }
889 
onPlayPositionChanged(byte[] address, int songLen, int currSongPosition)890     private void onPlayPositionChanged(byte[] address, int songLen, int currSongPosition) {
891         Log.d(TAG,"onPlayPositionChanged ");
892         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
893                 (Utils.getAddressStringFromByte(address));
894         if (!mConnectedDevices.contains(device))
895             return;
896         Message msg = mHandler.obtainMessage(AvrcpControllerConstants.
897                 MESSAGE_PROCESS_PLAY_POS_CHANGED, songLen, currSongPosition);
898         mHandler.sendMessage(msg);
899     }
900 
onPlayStatusChanged(byte[] address, byte playStatus)901     private void onPlayStatusChanged(byte[] address, byte playStatus) {
902         if(DBG) Log.d(TAG,"onPlayStatusChanged " + playStatus);
903         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
904                 (Utils.getAddressStringFromByte(address));
905         if (!mConnectedDevices.contains(device))
906             return;
907         Message msg = mHandler.obtainMessage(AvrcpControllerConstants.
908                 MESSAGE_PROCESS_PLAY_STATUS_CHANGED, playStatus, 0);
909         mHandler.sendMessage(msg);
910     }
911 
handlePlayerAppSetting(byte[] address, byte[] playerAttribRsp, int rspLen)912     private void handlePlayerAppSetting(byte[] address, byte[] playerAttribRsp, int rspLen) {
913         Log.d(TAG,"handlePlayerAppSetting rspLen = " + rspLen);
914         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
915                 (Utils.getAddressStringFromByte(address));
916         if (!mConnectedDevices.contains(device))
917             return;
918         ByteBuffer bb = ByteBuffer.wrap(playerAttribRsp, 0, rspLen);
919         Message msg = mHandler.obtainMessage(AvrcpControllerConstants.
920                 MESSAGE_PROCESS_SUPPORTED_PLAYER_APP_SETTING, 0, 0, bb);
921         mHandler.sendMessage(msg);
922     }
923 
onPlayerAppSettingChanged(byte[] address, byte[] playerAttribRsp, int rspLen)924     private void onPlayerAppSettingChanged(byte[] address, byte[] playerAttribRsp, int rspLen) {
925         Log.d(TAG,"onPlayerAppSettingChanged ");
926         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
927                 (Utils.getAddressStringFromByte(address));
928         if (!mConnectedDevices.contains(device))
929             return;
930         ByteBuffer bb = ByteBuffer.wrap(playerAttribRsp, 0, rspLen);
931         Message msg = mHandler.obtainMessage(AvrcpControllerConstants.
932                 MESSAGE_PROCESS_PLAYER_APP_SETTING_CHANGED, 0, 0, bb);
933         mHandler.sendMessage(msg);
934     }
935 
handleGroupNavigationRsp(int id, int keyState)936     private void handleGroupNavigationRsp(int id, int keyState) {
937         Log.d(TAG, "group navigation response received as: key: "
938                                 + id + " state: " + keyState);
939     }
940 
getByteAddress(BluetoothDevice device)941     private byte[] getByteAddress(BluetoothDevice device) {
942         return Utils.getBytesFromAddress(device.getAddress());
943     }
944 
945     @Override
dump(StringBuilder sb)946     public void dump(StringBuilder sb) {
947         super.dump(sb);
948     }
949 
classInitNative()950     private native static void classInitNative();
initNative()951     private native void initNative();
cleanupNative()952     private native void cleanupNative();
sendPassThroughCommandNative(byte[] address, int keyCode, int keyState)953     private native boolean sendPassThroughCommandNative(byte[] address, int keyCode, int keyState);
sendGroupNavigationCommandNative(byte[] address, int keyCode, int keyState)954     private native boolean sendGroupNavigationCommandNative(byte[] address, int keyCode,
955                                                                                      int keyState);
setPlayerApplicationSettingValuesNative(byte[] address, byte numAttrib, byte[] atttibIds, byte[]attribVal)956     private native void setPlayerApplicationSettingValuesNative(byte[] address, byte numAttrib,
957                                                     byte[] atttibIds, byte[]attribVal);
958     /* This api is used to send response to SET_ABS_VOL_CMD */
sendAbsVolRspNative(byte[] address, int absVol, int label)959     private native void sendAbsVolRspNative(byte[] address, int absVol, int label);
960     /* This api is used to inform remote for any volume level changes */
sendRegisterAbsVolRspNative(byte[] address, byte rspType, int absVol, int label)961     private native void sendRegisterAbsVolRspNative(byte[] address, byte rspType, int absVol,
962                                                     int label);
963 }
964