Home | History | Annotate | Download | only in avrcp
      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 {
     71         classInitNative();
     72     }
     73 
     74     public AvrcpControllerService() {
     75         initNative();
     76     }
     77 
     78     protected String getName() {
     79         return TAG;
     80     }
     81 
     82     protected IProfileServiceBinder initBinder() {
     83         return new BluetoothAvrcpControllerBinder(this);
     84     }
     85 
     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 
     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     }
    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 
    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 
    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 
    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 
    176     private static synchronized void clearAvrcpControllerService() {
    177         sAvrcpControllerService = null;
    178     }
    179 
    180     public List<BluetoothDevice> getConnectedDevices() {
    181         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    182         return mConnectedDevices;
    183     }
    184 
    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 
    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 
    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 
    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 
    297     public void startAvrcpUpdates() {
    298         mHandler.obtainMessage(
    299             AvrcpControllerConstants.MESSAGE_START_METADATA_BROADCASTS).sendToTarget();
    300     }
    301 
    302     public void stopAvrcpUpdates() {
    303         mHandler.obtainMessage(
    304             AvrcpControllerConstants.MESSAGE_STOP_METADATA_BROADCASTS).sendToTarget();
    305     }
    306 
    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     }
    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     }
    321     public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) {
    322         if (DBG) Log.d(TAG, "getPlayerApplicationSetting ");
    323         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    324         return getCurrentPlayerAppSetting();
    325     }
    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 
    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 
    399         BluetoothAvrcpControllerBinder(AvrcpControllerService svc) {
    400             mService = svc;
    401         }
    402 
    403         public boolean cleanup()  {
    404             mService = null;
    405             return true;
    406         }
    407 
    408         public List<BluetoothDevice> getConnectedDevices() {
    409             AvrcpControllerService service = getService();
    410             if (service == null) return new ArrayList<BluetoothDevice>(0);
    411             return service.getConnectedDevices();
    412         }
    413 
    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 
    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 
    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
    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
    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
    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
    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
    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 
    474     private String utf8ToString(byte[] input)
    475     {
    476         Charset UTF8_CHARSET = Charset.forName("UTF-8");
    477         return new String(input,UTF8_CHARSET);
    478     }
    479     private int asciiToInt(int len, byte[] array)
    480     {
    481         return Integer.parseInt(utf8ToString(array));
    482     }
    483     private BluetoothAvrcpPlayerSettings getCurrentPlayerAppSetting() {
    484         if((mRemoteMediaPlayers == null) || (mRemoteMediaPlayers.getAddressedPlayer() == null))
    485             return null;
    486         return mRemoteMediaPlayers.getAddressedPlayer().getSupportedPlayerAppSetting();
    487     }
    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     }
    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     }
    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     }
    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     }
    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 
    537         private AvrcpMessageHandler(Looper looper) {
    538             super(looper);
    539         }
    540 
    541         @Override
    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 
    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 
    806     private void handlePassthroughRsp(int id, int keyState) {
    807         Log.d(TAG, "passthrough response received as: key: " + id + " state: " + keyState);
    808     }
    809 
    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 
    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     }
    849     private void setPlayerAppSettingRsp(byte[] address, byte accepted) {
    850               /* TODO do we need to do anything here */
    851     }
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    936     private void handleGroupNavigationRsp(int id, int keyState) {
    937         Log.d(TAG, "group navigation response received as: key: "
    938                                 + id + " state: " + keyState);
    939     }
    940 
    941     private byte[] getByteAddress(BluetoothDevice device) {
    942         return Utils.getBytesFromAddress(device.getAddress());
    943     }
    944 
    945     @Override
    946     public void dump(StringBuilder sb) {
    947         super.dump(sb);
    948     }
    949 
    950     private native static void classInitNative();
    951     private native void initNative();
    952     private native void cleanupNative();
    953     private native boolean sendPassThroughCommandNative(byte[] address, int keyCode, int keyState);
    954     private native boolean sendGroupNavigationCommandNative(byte[] address, int keyCode,
    955                                                                                      int keyState);
    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 */
    959     private native void sendAbsVolRspNative(byte[] address, int absVol, int label);
    960     /* This api is used to inform remote for any volume level changes */
    961     private native void sendRegisterAbsVolRspNative(byte[] address, byte rspType, int absVol,
    962                                                     int label);
    963 }
    964