Home | History | Annotate | Download | only in avrcp
      1 /*
      2  * Copyright (C) 2015 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.BluetoothDevice;
     20 import android.bluetooth.BluetoothAvrcpPlayerSettings;
     21 import com.android.bluetooth.Utils;
     22 import java.util.ArrayList;
     23 import java.util.Arrays;
     24 import java.util.List;
     25 import java.util.HashMap;
     26 import android.util.Log;
     27 import java.nio.charset.Charset;
     28 import java.nio.ByteBuffer;
     29 import android.media.session.PlaybackState;
     30 import android.media.MediaMetadata;
     31 /**
     32  * Provides helper classes used by other AvrcpControllerClasses.
     33  */
     34 class AvrcpUtils {
     35 
     36     private static final String TAG = "AvrcpUtils";
     37     /*
     38      * First 2 apis are utility functions to converts values from AvrcpPlayerSettings defined
     39      * in BluetoothAvrcpPlayerSettings to BT spec defined Id and Vals.
     40      */
     41     public static int mapAttribIdValtoAvrcpPlayerSetting( byte attribId, byte attribVal) {
     42         if(AvrcpControllerConstants.VDBG) Log.d(TAG, "attribId: " + attribId + " attribVal: " + attribVal);
     43         if (attribId == AvrcpControllerConstants.ATTRIB_EQUALIZER_STATUS) {
     44             switch(attribVal) {
     45             case AvrcpControllerConstants.EQUALIZER_STATUS_OFF:
     46                 return BluetoothAvrcpPlayerSettings.STATE_OFF;
     47             case AvrcpControllerConstants.EQUALIZER_STATUS_ON:
     48                 return BluetoothAvrcpPlayerSettings.STATE_ON;
     49             }
     50         }
     51         else if (attribId == AvrcpControllerConstants.ATTRIB_REPEAT_STATUS) {
     52             switch(attribVal) {
     53             case AvrcpControllerConstants.REPEAT_STATUS_ALL_TRACK_REPEAT:
     54                 return BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK;
     55             case AvrcpControllerConstants.REPEAT_STATUS_GROUP_REPEAT:
     56                 return BluetoothAvrcpPlayerSettings.STATE_GROUP;
     57             case AvrcpControllerConstants.REPEAT_STATUS_OFF:
     58                 return BluetoothAvrcpPlayerSettings.STATE_OFF;
     59             case AvrcpControllerConstants.REPEAT_STATUS_SINGLE_TRACK_REPEAT:
     60                 return BluetoothAvrcpPlayerSettings.STATE_SINGLE_TRACK;
     61             }
     62         }
     63         else if (attribId == AvrcpControllerConstants.ATTRIB_SCAN_STATUS) {
     64             switch(attribVal) {
     65             case AvrcpControllerConstants.SCAN_STATUS_ALL_TRACK_SCAN:
     66                 return BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK;
     67             case AvrcpControllerConstants.SCAN_STATUS_GROUP_SCAN:
     68                 return BluetoothAvrcpPlayerSettings.STATE_GROUP;
     69             case AvrcpControllerConstants.SCAN_STATUS_OFF:
     70                 return BluetoothAvrcpPlayerSettings.STATE_OFF;
     71             }
     72         }
     73         else if (attribId == AvrcpControllerConstants.ATTRIB_SHUFFLE_STATUS) {
     74             switch(attribVal) {
     75             case AvrcpControllerConstants.SHUFFLE_STATUS_ALL_TRACK_SHUFFLE:
     76                 return BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK;
     77             case AvrcpControllerConstants.SHUFFLE_STATUS_GROUP_SHUFFLE:
     78                 return BluetoothAvrcpPlayerSettings.STATE_GROUP;
     79             case AvrcpControllerConstants.SHUFFLE_STATUS_OFF:
     80                 return BluetoothAvrcpPlayerSettings.STATE_OFF;
     81             }
     82         }
     83         return BluetoothAvrcpPlayerSettings.STATE_INVALID;
     84     }
     85     public static int mapAvrcpPlayerSettingstoBTAttribVal(int mSetting, int mSettingVal) {
     86         if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER) {
     87             switch(mSettingVal) {
     88             case BluetoothAvrcpPlayerSettings.STATE_OFF:
     89                 return AvrcpControllerConstants.EQUALIZER_STATUS_OFF;
     90             case BluetoothAvrcpPlayerSettings.STATE_ON:
     91                 return AvrcpControllerConstants.EQUALIZER_STATUS_ON;
     92             }
     93         }
     94         else if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_REPEAT) {
     95             switch(mSettingVal) {
     96             case BluetoothAvrcpPlayerSettings.STATE_OFF:
     97                 return AvrcpControllerConstants.REPEAT_STATUS_OFF;
     98             case BluetoothAvrcpPlayerSettings.STATE_SINGLE_TRACK:
     99                 return AvrcpControllerConstants.REPEAT_STATUS_SINGLE_TRACK_REPEAT;
    100             case BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK:
    101                 return AvrcpControllerConstants.REPEAT_STATUS_ALL_TRACK_REPEAT;
    102             case BluetoothAvrcpPlayerSettings.STATE_GROUP:
    103                 return AvrcpControllerConstants.REPEAT_STATUS_GROUP_REPEAT;
    104             }
    105         }
    106         else if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE) {
    107             switch(mSettingVal) {
    108             case BluetoothAvrcpPlayerSettings.STATE_OFF:
    109                 return AvrcpControllerConstants.SHUFFLE_STATUS_OFF;
    110             case BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK:
    111                 return AvrcpControllerConstants.SHUFFLE_STATUS_ALL_TRACK_SHUFFLE;
    112             case BluetoothAvrcpPlayerSettings.STATE_GROUP:
    113                 return AvrcpControllerConstants.SHUFFLE_STATUS_GROUP_SHUFFLE;
    114             }
    115         }
    116         else if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_SCAN) {
    117             switch(mSettingVal) {
    118             case BluetoothAvrcpPlayerSettings.STATE_OFF:
    119                 return AvrcpControllerConstants.SCAN_STATUS_OFF;
    120             case BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK:
    121                 return AvrcpControllerConstants.SCAN_STATUS_ALL_TRACK_SCAN;
    122             case BluetoothAvrcpPlayerSettings.STATE_GROUP:
    123                 return AvrcpControllerConstants.SCAN_STATUS_GROUP_SCAN;
    124             }
    125         }
    126         return AvrcpControllerConstants.STATUS_INVALID;
    127     }
    128     /*
    129      * This api converts btPlayStatus to PlaybackState
    130      */
    131     public static PlaybackState mapBtPlayStatustoPlayBackState(byte btPlayStatus, long btPlayPos) {
    132         int mState = PlaybackState.STATE_NONE;
    133         long position = btPlayPos;
    134         float speed = 1;
    135         switch(btPlayStatus) {
    136             case AvrcpControllerConstants.PLAY_STATUS_STOPPED:
    137                 mState = PlaybackState.STATE_STOPPED;
    138                 position = 0;
    139                 speed = 0;
    140             break;
    141             case AvrcpControllerConstants.PLAY_STATUS_PLAYING:
    142                 mState = PlaybackState.STATE_PLAYING;
    143             break;
    144             case AvrcpControllerConstants.PLAY_STATUS_PAUSED:
    145                 mState = PlaybackState.STATE_PAUSED;
    146                 speed = 0;
    147             break;
    148             case AvrcpControllerConstants.PLAY_STATUS_FWD_SEEK:
    149                 mState = PlaybackState.STATE_FAST_FORWARDING;
    150                 speed = 3;
    151             break;
    152             case AvrcpControllerConstants.PLAY_STATUS_REV_SEEK:
    153                 mState = PlaybackState.STATE_REWINDING;
    154                 speed = -3;
    155             break;
    156         }
    157         return new PlaybackState.Builder().setState(mState, position, speed).build();
    158     }
    159     /*
    160      * This api converts meta info into MediaMetaData
    161      */
    162     public static MediaMetadata getMediaMetaData(TrackInfo mTrackInfo) {
    163         if(AvrcpControllerConstants.VDBG) Log.d(TAG, " TrackInfo " + mTrackInfo.toString());
    164         MediaMetadata.Builder mMetaDataBuilder = new MediaMetadata.Builder();
    165         mMetaDataBuilder.putString(MediaMetadata.METADATA_KEY_ARTIST,
    166                 mTrackInfo.mArtistName);
    167         mMetaDataBuilder.putString(MediaMetadata.METADATA_KEY_TITLE,
    168                 mTrackInfo.mTrackTitle);
    169         mMetaDataBuilder.putString(MediaMetadata.METADATA_KEY_ALBUM,
    170                 mTrackInfo.mAlbumTitle);
    171         mMetaDataBuilder.putString(MediaMetadata.METADATA_KEY_GENRE,
    172                 mTrackInfo.mGenre);
    173         mMetaDataBuilder.putLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER,
    174                 mTrackInfo.mTrackNum);
    175         mMetaDataBuilder.putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS,
    176                 mTrackInfo.mTotalTracks);
    177         mMetaDataBuilder.putLong(MediaMetadata.METADATA_KEY_DURATION,
    178                 mTrackInfo.mTrackLen);
    179         mMetaDataBuilder.putString(MediaMetadata.METADATA_KEY_MEDIA_ID,
    180                 String.valueOf(mTrackInfo.mItemUid));
    181         return mMetaDataBuilder.build();
    182     }
    183     /*
    184      * Display Apis
    185      */
    186     public static String displayMetaData(MediaMetadata mMetaData) {
    187         StringBuffer sb = new StringBuffer();
    188         /* this will only show artist, title and album */
    189         sb.append(mMetaData.getDescription().toString() + " ");
    190         if(mMetaData.containsKey(MediaMetadata.METADATA_KEY_GENRE))
    191             sb.append(mMetaData.getString(MediaMetadata.METADATA_KEY_GENRE) + " ");
    192         if(mMetaData.containsKey(MediaMetadata.METADATA_KEY_MEDIA_ID))
    193             sb.append(mMetaData.getString(MediaMetadata.METADATA_KEY_MEDIA_ID) + " ");
    194         if(mMetaData.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER))
    195             sb.append(Long.toString(mMetaData.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER)) + " ");
    196         if(mMetaData.containsKey(MediaMetadata.METADATA_KEY_NUM_TRACKS))
    197             sb.append(Long.toString(mMetaData.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS)) + " ");
    198         if(mMetaData.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER))
    199             sb.append(Long.toString(mMetaData.getLong(MediaMetadata.METADATA_KEY_DURATION)) + " ");
    200         if(mMetaData.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER))
    201             sb.append(Long.toString(mMetaData.getLong(MediaMetadata.METADATA_KEY_DURATION)) + " ");
    202         return sb.toString();
    203     }
    204     public static String displayBluetoothAvrcpSettings(BluetoothAvrcpPlayerSettings mSett) {
    205         StringBuffer sb =  new StringBuffer();
    206         int supportedSetting = mSett.getSettings();
    207         if(AvrcpControllerConstants.VDBG) Log.d(TAG," setting: " + supportedSetting);
    208         if((supportedSetting & BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER) != 0) {
    209             sb.append(" EQ : ");
    210             sb.append(Integer.toString(mSett.getSettingValue(BluetoothAvrcpPlayerSettings.
    211                                                              SETTING_EQUALIZER)));
    212         }
    213         if((supportedSetting & BluetoothAvrcpPlayerSettings.SETTING_REPEAT) != 0) {
    214             sb.append(" REPEAT : ");
    215             sb.append(Integer.toString(mSett.getSettingValue(BluetoothAvrcpPlayerSettings.
    216                                                              SETTING_REPEAT)));
    217         }
    218         if((supportedSetting & BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE) != 0) {
    219             sb.append(" SHUFFLE : ");
    220             sb.append(Integer.toString(mSett.getSettingValue(BluetoothAvrcpPlayerSettings.
    221                                                              SETTING_SHUFFLE)));
    222         }
    223         if((supportedSetting & BluetoothAvrcpPlayerSettings.SETTING_SCAN) != 0) {
    224             sb.append(" SCAN : ");
    225             sb.append(Integer.toString(mSett.getSettingValue(BluetoothAvrcpPlayerSettings.
    226                                                              SETTING_SCAN)));
    227         }
    228         return sb.toString();
    229     }
    230 }
    231 /*
    232  * Contains information about remote device
    233  */
    234 class RemoteDevice {
    235     BluetoothDevice mBTDevice;
    236     int mRemoteFeatures;
    237     int mBatteryStatus;
    238     int mSystemStatus;
    239     int mAbsVolNotificationState;
    240     int mNotificationLabel;
    241     boolean mFirstAbsVolCmdRecvd;
    242 
    243     public void cleanup() {
    244         mBTDevice = null;
    245         mRemoteFeatures = AvrcpControllerConstants.BTRC_FEAT_NONE;
    246         mBatteryStatus = AvrcpControllerConstants.BATT_POWER_UNDEFINED;
    247         mSystemStatus = AvrcpControllerConstants.SYSTEM_STATUS_UNDEFINED;
    248         mAbsVolNotificationState = AvrcpControllerConstants.DEFER_VOLUME_CHANGE_RSP;
    249         mNotificationLabel = AvrcpControllerConstants.VOLUME_LABEL_UNDEFINED;
    250         mFirstAbsVolCmdRecvd = false;
    251     }
    252 
    253     public RemoteDevice(BluetoothDevice mDevice) {
    254         mBTDevice = mDevice;
    255         mRemoteFeatures = AvrcpControllerConstants.BTRC_FEAT_NONE;
    256         mBatteryStatus = AvrcpControllerConstants.BATT_POWER_UNDEFINED;
    257         mSystemStatus = AvrcpControllerConstants.SYSTEM_STATUS_UNDEFINED;
    258         mAbsVolNotificationState = AvrcpControllerConstants.DEFER_VOLUME_CHANGE_RSP;
    259         mNotificationLabel = AvrcpControllerConstants.VOLUME_LABEL_UNDEFINED;
    260         mFirstAbsVolCmdRecvd = false;
    261     }
    262 
    263     public boolean isBrowsingSupported() {
    264         if((mRemoteFeatures & AvrcpControllerConstants.BTRC_FEAT_BROWSE) != 0)
    265             return true;
    266         else
    267            return false;
    268     }
    269     public boolean isMetaDataSupported() {
    270         if((mRemoteFeatures & AvrcpControllerConstants.BTRC_FEAT_METADATA) != 0)
    271             return true;
    272         else
    273            return false;
    274     }
    275 }
    276 
    277 /*
    278  * Base Class for Media Item
    279  */
    280 class MediaItem {
    281     /*
    282      * This is a combination of locaiton and item. Spec Snippet
    283      * In VFS if same item is in different location it may have same uid.
    284      * In Now Playing same item should have differnt UID
    285      * Can never be 0, used only for GetElementAttributes
    286      * TODO: UID counter, which is used for database aware player
    287      */
    288     double mItemUid;
    289 }
    290 
    291 /*
    292  * Contains information Player Application Setting
    293  */
    294 class PlayerApplicationSettings {
    295     public byte attr_Id;
    296     public byte attr_val;
    297     public byte [] supported_values;
    298     public String attr_text;
    299     public String [] supported_values_text;// This is to keep displayable text in UTF-8
    300 }
    301 /*
    302  * Contains information about remote player
    303  */
    304 class PlayerInfo {
    305     private static final String TAG = "PlayerInfo";
    306     byte mPlayStatus;
    307     long mPlayTime;
    308     /*
    309      * 2 byte player id to identify player.
    310      * In 1.3 this value will be set to zero
    311      */
    312     char mPlayerId;
    313     ArrayList<PlayerApplicationSettings> mPlayerAppSetting;
    314     private void resetPlayer() {
    315         mPlayStatus = AvrcpControllerConstants.PLAY_STATUS_STOPPED;
    316         mPlayTime   = AvrcpControllerConstants.PLAYING_TIME_INVALID;
    317         mPlayerId   = 0;
    318         mPlayerAppSetting = new ArrayList<PlayerApplicationSettings>();
    319     }
    320     public PlayerInfo() {
    321         resetPlayer();
    322     }
    323     public void setSupportedPlayerAppSetting (ByteBuffer bb) {
    324         /* ByteBuffer has to be of the following format
    325          * id, num_values, values[]
    326          */
    327         while(bb.hasRemaining()) {
    328             PlayerApplicationSettings plAppSetting = new PlayerApplicationSettings();
    329             plAppSetting.attr_Id = bb.get();
    330             byte numSupportedVals = bb.get();
    331             plAppSetting.supported_values = new byte[numSupportedVals];
    332             for (int i = 0; i<numSupportedVals; i++) {
    333                 plAppSetting.supported_values[i] = bb.get();
    334             }
    335             mPlayerAppSetting.add(plAppSetting);
    336         }
    337     }
    338     public void updatePlayerAppSetting(ByteBuffer bb) {
    339         /* ByteBuffer has to be of the following format
    340          * <id, value>
    341          */
    342         if(mPlayerAppSetting.isEmpty())
    343             return;
    344         while(bb.hasRemaining()) {
    345             byte attribId = bb.get();
    346             for(PlayerApplicationSettings plAppSetting: mPlayerAppSetting) {
    347                 if(plAppSetting.attr_Id == attribId)
    348                     plAppSetting.attr_val = bb.get();
    349             }
    350         }
    351     }
    352 
    353     public BluetoothAvrcpPlayerSettings getSupportedPlayerAppSetting() {
    354         /*
    355          * Here we create PlayerAppSetting
    356          * based on BluetoothAvrcpPlayerSettings
    357          */
    358         int supportedSettings = 0; // Player App Setting used by BluetoothAvrcpPlayerSettings.
    359         for(PlayerApplicationSettings plAppSetting: mPlayerAppSetting) {
    360             switch(plAppSetting.attr_Id) {
    361             case AvrcpControllerConstants.ATTRIB_EQUALIZER_STATUS:
    362                 supportedSettings |= BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER;
    363                 break;
    364             case AvrcpControllerConstants.ATTRIB_REPEAT_STATUS:
    365                 supportedSettings |= BluetoothAvrcpPlayerSettings.SETTING_REPEAT;
    366                 break;
    367             case AvrcpControllerConstants.ATTRIB_SCAN_STATUS:
    368                 supportedSettings |= BluetoothAvrcpPlayerSettings.SETTING_SCAN;
    369                 break;
    370             case AvrcpControllerConstants.ATTRIB_SHUFFLE_STATUS:
    371                 supportedSettings |= BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE;
    372                 break;
    373             }
    374         }
    375         BluetoothAvrcpPlayerSettings mAvrcpPlayerAppSetting = new
    376                                   BluetoothAvrcpPlayerSettings(supportedSettings);
    377         for(PlayerApplicationSettings plAppSetting: mPlayerAppSetting) {
    378             switch(plAppSetting.attr_Id) {
    379             case AvrcpControllerConstants.ATTRIB_EQUALIZER_STATUS:
    380                 mAvrcpPlayerAppSetting.addSettingValue(BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER,
    381                            AvrcpUtils.mapAttribIdValtoAvrcpPlayerSetting(plAppSetting.attr_Id,
    382                                 plAppSetting.attr_val));
    383                 break;
    384             case AvrcpControllerConstants.ATTRIB_REPEAT_STATUS:
    385                 mAvrcpPlayerAppSetting.addSettingValue(BluetoothAvrcpPlayerSettings.SETTING_REPEAT,
    386                         AvrcpUtils.mapAttribIdValtoAvrcpPlayerSetting(plAppSetting.attr_Id,
    387                                 plAppSetting.attr_val));
    388                 break;
    389             case AvrcpControllerConstants.ATTRIB_SCAN_STATUS:
    390                 mAvrcpPlayerAppSetting.addSettingValue(BluetoothAvrcpPlayerSettings.SETTING_SCAN,
    391                         AvrcpUtils.mapAttribIdValtoAvrcpPlayerSetting(plAppSetting.attr_Id,
    392                                 plAppSetting.attr_val));
    393                 break;
    394             case AvrcpControllerConstants.ATTRIB_SHUFFLE_STATUS:
    395                 mAvrcpPlayerAppSetting.addSettingValue(BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE,
    396                         AvrcpUtils.mapAttribIdValtoAvrcpPlayerSetting(plAppSetting.attr_Id,
    397                                 plAppSetting.attr_val));
    398                 break;
    399             }
    400         }
    401         return mAvrcpPlayerAppSetting;
    402     }
    403     public byte getCurrentPlayerAppSettingValue(byte mPlayerAppAttrId) {
    404         for(PlayerApplicationSettings plAppSetting: mPlayerAppSetting) {
    405             if(mPlayerAppAttrId == plAppSetting.attr_Id)
    406                 return plAppSetting.attr_val;
    407         }
    408         return 0;
    409     }
    410     /*
    411      * Checks if current setting is supported by remote.
    412      * input would be in form of flattened strucuture <id,val>
    413      */
    414     public boolean isPlayerAppSettingSupported(byte numAttributes, byte[] playerAppSetting) {
    415         for( int i = 0; (i < 2*numAttributes);) {
    416             byte id = playerAppSetting[i++];
    417             byte val = playerAppSetting[i++];
    418             boolean found = false;
    419             for(PlayerApplicationSettings plAppSetting: mPlayerAppSetting) {
    420                 if(plAppSetting.attr_Id == id) {
    421                     for(int j = 0; j < plAppSetting.supported_values.length; j++) {
    422                         if(val == plAppSetting.supported_values[j]) {
    423                             found = true;
    424                             break;
    425                         }
    426                     }
    427                 }
    428             }
    429             if(!found)
    430                 return false;
    431         }
    432         return true;
    433     }
    434 }
    435 
    436 /*
    437  * Contains information about track
    438  */
    439 class TrackInfo extends MediaItem {
    440     String mArtistName;
    441     String mTrackTitle;
    442     String mAlbumTitle;
    443     String mGenre;
    444     long mTrackNum; // number of audio file on original recording.
    445     long mTotalTracks;// total number of tracks on original recording
    446     long mTrackLen;// full length of AudioFile.
    447     /* In case of 1.3 we have to set itemUid explicitly to 0 */
    448 
    449     /* reset it to default values */
    450     private void resetTrackInfo() {
    451         mArtistName = AvrcpControllerConstants.ARTIST_NAME_INVALID;;
    452         mTrackTitle = AvrcpControllerConstants.TITLE_INVALID;;
    453         mAlbumTitle = AvrcpControllerConstants.ALBUM_NAME_INVALID;
    454         mGenre      = AvrcpControllerConstants.GENRE_INVALID;
    455         mTrackNum   = AvrcpControllerConstants.TRACK_NUM_INVALID;
    456         mTotalTracks = AvrcpControllerConstants.TOTAL_TRACK_TIME_INVALID;
    457         mTrackLen = AvrcpControllerConstants.TOTAL_TRACK_TIME_INVALID;
    458     }
    459     public TrackInfo() {
    460         resetTrackInfo();
    461     }
    462     public TrackInfo(int mTrackId, byte mNumAttributes, int[] mAttribIds, String[] mAttribs) {
    463         mItemUid = mTrackId;
    464         resetTrackInfo();
    465         for (int i = 0; i < mNumAttributes; i++) {
    466             switch(mAttribIds[i]) {
    467             case AvrcpControllerConstants.MEDIA_ATTRIBUTE_TITLE:
    468                 mTrackTitle = mAttribs[i];
    469                 break;
    470             case AvrcpControllerConstants.MEDIA_ATTRIBUTE_ARTIST_NAME:
    471                 mArtistName = mAttribs[i];
    472                 break;
    473             case AvrcpControllerConstants.MEDIA_ATTRIBUTE_ALBUM_NAME:
    474                 mAlbumTitle = mAttribs[i];
    475                 break;
    476             case AvrcpControllerConstants.MEDIA_ATTRIBUTE_TRACK_NUMBER:
    477                 if(!mAttribs[i].isEmpty())
    478                     mTrackNum = Long.valueOf(mAttribs[i]);
    479                 break;
    480             case AvrcpControllerConstants.MEDIA_ATTRIBUTE_TOTAL_TRACK_NUMBER:
    481                 if(!mAttribs[i].isEmpty())
    482                     mTotalTracks = Long.valueOf(mAttribs[i]);
    483                 break;
    484             case AvrcpControllerConstants.MEDIA_ATTRIBUTE_GENRE:
    485                 mGenre = mAttribs[i];
    486                 break;
    487             case AvrcpControllerConstants.MEDIA_ATTRIBUTE_PLAYING_TIME:
    488                 if(!mAttribs[i].isEmpty())
    489                     mTrackLen = Long.valueOf(mAttribs[i]);
    490                 break;
    491             }
    492         }
    493     }
    494     public String toString() {
    495         return "Metadata [artist=" + mArtistName + " trackTitle= " + mTrackTitle +
    496                 " albumTitle= " + mAlbumTitle + " genre= " +mGenre+" trackNum= "+
    497                 Long.toString(mTrackNum) + " track_len : "+ Long.toString(mTrackLen) +
    498                 " TotalTracks " + Long.toString(mTotalTracks) + "]";
    499     }
    500 }
    501