1c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu/*
2e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah * Copyright (C) 2016 The Android Open Source Project
3c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu *
4c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * Licensed under the Apache License, Version 2.0 (the "License");
5c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * you may not use this file except in compliance with the License.
6c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * You may obtain a copy of the License at
7c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu *
8c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu *      http://www.apache.org/licenses/LICENSE-2.0
9c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu *
10c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * Unless required by applicable law or agreed to in writing, software
11c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * distributed under the License is distributed on an "AS IS" BASIS,
12c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * See the License for the specific language governing permissions and
14c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * limitations under the License.
15c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu */
16c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
17066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodpackage com.android.bluetooth.avrcp;
18c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
19de5340b6cbe5e8bd62658131e87c551d0fc7a182Marie Janssenimport android.annotation.NonNull;
200c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssenimport android.annotation.Nullable;
21188f205b5f093850d4cc627917a21204be36c56aZhihai Xuimport android.bluetooth.BluetoothA2dp;
22066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.bluetooth.BluetoothAvrcp;
23e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.bluetooth.BluetoothDevice;
24e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.BroadcastReceiver;
25e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.ComponentName;
26c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.content.Context;
27e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.Intent;
28e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.IntentFilter;
29e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.pm.ApplicationInfo;
30e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.pm.PackageManager;
31e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.pm.PackageManager.NameNotFoundException;
32e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.pm.ResolveInfo;
3311798b011c962b602217b479130d413f3b30f19aLiejun Taoimport android.content.res.Resources;
3411798b011c962b602217b479130d413f3b30f19aLiejun Taoimport android.content.SharedPreferences;
35c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.AudioManager;
3676aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavovimport android.media.AudioPlaybackConfiguration;
373b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssenimport android.media.MediaDescription;
380e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssenimport android.media.MediaMetadata;
393843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssenimport android.media.browse.MediaBrowser;
40e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.media.session.MediaSession;
41e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.media.session.MediaSession.QueueItem;
420e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssenimport android.media.session.MediaSessionManager;
430e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssenimport android.media.session.PlaybackState;
44e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.os.Bundle;
45c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Handler;
46c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.HandlerThread;
47c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Looper;
48c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Message;
49aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport android.os.SystemClock;
500427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panickerimport android.os.UserManager;
51c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.util.Log;
52881675b362bde18acbbcf69c513175addca4a8baZhenye Zhuimport android.view.KeyEvent;
536e29e12add362546784126119f26f04fc760f021RoboErik
54c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.bluetooth.btservice.ProfileService;
55e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport com.android.bluetooth.R;
56aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport com.android.bluetooth.Utils;
576e29e12add362546784126119f26f04fc760f021RoboErik
58c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.ArrayList;
590c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssenimport java.util.Collections;
6011798b011c962b602217b479130d413f3b30f19aLiejun Taoimport java.util.HashMap;
617c12b34b98d717fdfe68f5e8c94b7a01ef372f8bMarie Janssenimport java.util.HashSet;
62e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport java.util.Iterator;
63c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.List;
64e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport java.util.Map;
657c12b34b98d717fdfe68f5e8c94b7a01ef372f8bMarie Janssenimport java.util.Set;
66351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssenimport java.util.SortedMap;
67351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssenimport java.util.TreeMap;
68e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
69e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah/******************************************************************************
70e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah * support Bluetooth AVRCP profile. support metadata, play status, event
71e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah * notifications, address player selection and browse feature implementation.
72e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah ******************************************************************************/
73eb7b90f5b93db1230a5b64caa3d8d05a642e33a6Marie Janssen
74066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodpublic final class Avrcp {
751b70ec148be773651d5ad00e3ce0d28b3a63306dAjay Panicker    private static final boolean DEBUG = true;
76c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private static final String TAG = "Avrcp";
7711798b011c962b602217b479130d413f3b30f19aLiejun Tao    private static final String ABSOLUTE_VOLUME_BLACKLIST = "absolute_volume_blacklist";
78c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
79c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Context mContext;
80c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private final AudioManager mAudioManager;
81c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private AvrcpMessageHandler mHandler;
8276aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov    private Handler mAudioManagerPlaybackHandler;
8376aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov    private AudioManagerPlaybackListener mAudioManagerPlaybackCb;
840e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen    private MediaSessionManager mMediaSessionManager;
85de5340b6cbe5e8bd62658131e87c551d0fc7a182Marie Janssen    private @Nullable MediaController mMediaController;
860e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen    private MediaControllerListener mMediaControllerCb;
873b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen    private MediaAttributes mMediaAttributes;
88d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen    private long mLastQueueId;
89e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private PackageManager mPackageManager;
90c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mTransportControlFlags;
91de5340b6cbe5e8bd62658131e87c551d0fc7a182Marie Janssen    private @NonNull PlaybackState mCurrentPlayState;
9293f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen    private int mA2dpState;
9376aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov    private boolean mAudioManagerIsPlaying;
94c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mPlayStatusChangedNT;
953211ee063dc32e07ab00d94312637dd7c27d2bbaAjay Panicker    private byte mReportedPlayStatus;
96c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mTrackChangedNT;
97f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    private int mPlayPosChangedNT;
98b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    private int mAddrPlayerChangedNT;
99b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    private int mReportedPlayerID;
1003616b7ce7be6abaca5eef876e055155f9e8a3b1fAjay Panicker    private int mNowPlayingListChangedNT;
101aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPlaybackIntervalMs;
102fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen    private long mLastReportedPosition;
103aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mNextPosMs;
104aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPrevPosMs;
10517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mFeatures;
10611798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mRemoteVolume;
10711798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLastRemoteVolume;
10811798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mInitialRemoteVolume;
10911798b011c962b602217b479130d413f3b30f19aLiejun Tao
11011798b011c962b602217b479130d413f3b30f19aLiejun Tao    /* Local volume in audio index 0-15 */
11111798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLocalVolume;
11211798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLastLocalVolume;
11311798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mAbsVolThreshold;
11411798b011c962b602217b479130d413f3b30f19aLiejun Tao
11511798b011c962b602217b479130d413f3b30f19aLiejun Tao    private String mAddress;
11611798b011c962b602217b479130d413f3b30f19aLiejun Tao    private HashMap<Integer, Integer> mVolumeMapping;
11711798b011c962b602217b479130d413f3b30f19aLiejun Tao
11817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mLastDirection;
1192e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private final int mVolumeStep;
1202e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private final int mAudioStreamMax;
12111798b011c962b602217b479130d413f3b30f19aLiejun Tao    private boolean mVolCmdAdjustInProgress;
12211798b011c962b602217b479130d413f3b30f19aLiejun Tao    private boolean mVolCmdSetInProgress;
12317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mAbsVolRetryTimes;
124351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen
125d89304c6be6e1c332008dcbeab08889881064454Marie Janssen    private static final int NO_PLAYER_ID = 0;
126d89304c6be6e1c332008dcbeab08889881064454Marie Janssen
127e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private int mCurrAddrPlayerID;
128e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private int mCurrBrowsePlayerID;
129351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    private int mLastUsedPlayerID;
130e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private AvrcpMediaRsp mAvrcpMediaRsp;
131e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
132e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* UID counter to be shared across different files. */
133b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    static short sUIDCounter = AvrcpConstants.DEFAULT_UID_COUNTER;
134ace834feb02adabd61f628c4471147aea02d939cJohn Du
13517675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* BTRC features */
13617675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_METADATA = 0x01;
13717675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02;
13817675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_BROWSE = 0x04;
13917675906064bb72fdcca75baa56cdf8bb8968d01John Du
14017675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* AVRC response codes, from avrc_defs */
14117675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_NOT_IMPL = 8;
14217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_ACCEPT = 9;
14317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_REJ = 10;
14417675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_IN_TRANS = 11;
14517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_IMPL_STBL = 12;
14617675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_CHANGED = 13;
14717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_INTERIM = 15;
14817675906064bb72fdcca75baa56cdf8bb8968d01John Du
149e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* AVRC request commands from Native */
150e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_RC_FEATURES = 1;
151e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_PLAY_STATUS = 2;
152e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_ELEM_ATTRS = 3;
153e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_REGISTER_NOTIFICATION = 4;
154e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_VOLUME_CHANGE = 5;
155e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_FOLDER_ITEMS = 6;
156e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_SET_ADDR_PLAYER = 7;
157e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_SET_BR_PLAYER = 8;
158e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_CHANGE_PATH = 9;
159e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_PLAY_ITEM = 10;
160e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_ITEM_ATTR = 11;
161e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS = 12;
162e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_PASS_THROUGH = 13;
163e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
164e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* other AVRC messages */
165e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_PLAY_INTERVAL_TIMEOUT = 14;
166e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_ADJUST_VOLUME = 15;
167e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_SET_ABSOLUTE_VOLUME = 16;
168e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_ABS_VOL_TIMEOUT = 17;
169b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    private static final int MSG_SET_A2DP_AUDIO_STATE = 18;
17085ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen    private static final int MSG_NOW_PLAYING_CHANGED_RSP = 19;
171bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
17217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int CMD_TIMEOUT_DELAY = 2000;
173f8201e1c6bf7fadc0a332151a652325a7f31255aLiejun Tao    private static final int MAX_ERROR_RETRY_TIMES = 6;
17417675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRCP_MAX_VOL = 127;
17517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRCP_BASE_VOLUME_STEP = 1;
176ace834feb02adabd61f628c4471147aea02d939cJohn Du
177e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Communicates with MediaPlayer to fetch media content */
178e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private BrowsedMediaPlayer mBrowsedMediaPlayer;
179e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
180bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    /* Addressed player handling */
181e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private AddressedMediaPlayer mAddressedMediaPlayer;
182e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
183e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* List of Media player instances, useful for retrieving MediaPlayerList or MediaPlayerInfo */
184351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    private SortedMap<Integer, MediaPlayerInfo> mMediaPlayerInfoList;
18585ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen    private boolean mAvailablePlayerViewChanged;
186e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
187e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* List of media players which supports browse */
188241af80129d66d60eea6e77e8962b7123e1c61c5Marie Janssen    private List<BrowsePlayerInfo> mBrowsePlayerInfoList;
189e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
190e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Manage browsed players */
191e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private AvrcpBrowseManager mAvrcpBrowseManager;
192e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
193e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Broadcast receiver for device connections intent broadcasts */
194e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private final BroadcastReceiver mAvrcpReceiver = new AvrcpServiceBroadcastReceiver();
1950427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker    private final BroadcastReceiver mBootReceiver = new AvrcpServiceBootReceiver();
196e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
197bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    /* Recording passthrough key dispatches */
198bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    static private final int PASSTHROUGH_LOG_MAX_SIZE = DEBUG ? 50 : 10;
199bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    private EvictingQueue<MediaKeyLog> mPassthroughLogs; // Passthorugh keys dispatched
2000c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen    private List<MediaKeyLog> mPassthroughPending; // Passthrough keys sent not dispatched yet
201bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    private int mPassthroughDispatched; // Number of keys dispatched
202bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
203bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    private class MediaKeyLog {
204bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        private long mTimeSent;
205bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        private long mTimeProcessed;
206bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        private String mPackage;
207bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        private KeyEvent mEvent;
208bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
209bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        public MediaKeyLog(long time, KeyEvent event) {
210bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            mEvent = event;
211bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            mTimeSent = time;
212bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        }
213bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
214bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        public boolean addDispatch(long time, KeyEvent event, String packageName) {
215bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            if (mPackage != null) return false;
216bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            if (event.getAction() != mEvent.getAction()) return false;
217bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            if (event.getKeyCode() != mEvent.getKeyCode()) return false;
218bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            mPackage = packageName;
219bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            mTimeProcessed = time;
220bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            return true;
221bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        }
222bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
223bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        public String toString() {
224bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            StringBuilder sb = new StringBuilder();
225bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            sb.append(android.text.format.DateFormat.format("MM-dd HH:mm:ss", mTimeSent));
226bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            sb.append(" " + mEvent.toString());
227bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            if (mPackage == null) {
228bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                sb.append(" (undispatched)");
229bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            } else {
230bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                sb.append(" to " + mPackage);
231bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                sb.append(" in " + (mTimeProcessed - mTimeSent) + "ms");
232bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            }
233bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            return sb.toString();
234bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        }
235bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    }
236bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
237c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    static {
238c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        classInitNative();
239c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
240c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
241c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Avrcp(Context context) {
2423b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        mMediaAttributes = new MediaAttributes(null);
243d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen        mLastQueueId = MediaSession.QueueItem.UNKNOWN_ID;
2440e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        mCurrentPlayState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build();
245b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        mReportedPlayStatus = PLAYSTATUS_ERROR;
24693f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen        mA2dpState = BluetoothA2dp.STATE_NOT_PLAYING;
24776aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        mAudioManagerIsPlaying = false;
248e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
249e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
250e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
251b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        mAddrPlayerChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
2523616b7ce7be6abaca5eef876e055155f9e8a3b1fAjay Panicker        mNowPlayingListChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
253b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        mPlaybackIntervalMs = 0L;
254fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        mLastReportedPosition = -1;
2553635a926bd7316a55b288a54d409a1070a9c19e8Marie Janssen        mNextPosMs = -1;
2563635a926bd7316a55b288a54d409a1070a9c19e8Marie Janssen        mPrevPosMs = -1;
25717675906064bb72fdcca75baa56cdf8bb8968d01John Du        mFeatures = 0;
25811798b011c962b602217b479130d413f3b30f19aLiejun Tao        mRemoteVolume = -1;
25911798b011c962b602217b479130d413f3b30f19aLiejun Tao        mInitialRemoteVolume = -1;
26011798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLastRemoteVolume = -1;
26117675906064bb72fdcca75baa56cdf8bb8968d01John Du        mLastDirection = 0;
26211798b011c962b602217b479130d413f3b30f19aLiejun Tao        mVolCmdAdjustInProgress = false;
26311798b011c962b602217b479130d413f3b30f19aLiejun Tao        mVolCmdSetInProgress = false;
26417675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAbsVolRetryTimes = 0;
26511798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLocalVolume = -1;
26611798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLastLocalVolume = -1;
26711798b011c962b602217b479130d413f3b30f19aLiejun Tao        mAbsVolThreshold = 0;
26811798b011c962b602217b479130d413f3b30f19aLiejun Tao        mVolumeMapping = new HashMap<Integer, Integer>();
269d89304c6be6e1c332008dcbeab08889881064454Marie Janssen        mCurrAddrPlayerID = NO_PLAYER_ID;
270b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        mReportedPlayerID = mCurrAddrPlayerID;
271b3436e976055f684050be9afdadc73645316806aMarie Janssen        mCurrBrowsePlayerID = 0;
272c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mContext = context;
273351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        mLastUsedPlayerID = 0;
274e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAddressedMediaPlayer = null;
275c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
276c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        initNative();
277c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
278e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mMediaSessionManager = (MediaSessionManager) context.getSystemService(
279e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Context.MEDIA_SESSION_SERVICE);
280c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
2812e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mAudioStreamMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
2822e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mVolumeStep = Math.max(AVRCP_BASE_VOLUME_STEP, AVRCP_MAX_VOL/mAudioStreamMax);
283e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
28411798b011c962b602217b479130d413f3b30f19aLiejun Tao        Resources resources = context.getResources();
28511798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (resources != null) {
28611798b011c962b602217b479130d413f3b30f19aLiejun Tao            mAbsVolThreshold = resources.getInteger(R.integer.a2dp_absolute_volume_initial_threshold);
2879ef4a582ed78ae48b867012ea53ba3cec79a31f7Pavlin Radoslavov
2889ef4a582ed78ae48b867012ea53ba3cec79a31f7Pavlin Radoslavov            // Update the threshold if the threshold_percent is valid
2899ef4a582ed78ae48b867012ea53ba3cec79a31f7Pavlin Radoslavov            int threshold_percent =
2909ef4a582ed78ae48b867012ea53ba3cec79a31f7Pavlin Radoslavov                    resources.getInteger(R.integer.a2dp_absolute_volume_initial_threshold_percent);
2919ef4a582ed78ae48b867012ea53ba3cec79a31f7Pavlin Radoslavov            if (threshold_percent >= 0 && threshold_percent <= 100) {
2929ef4a582ed78ae48b867012ea53ba3cec79a31f7Pavlin Radoslavov                mAbsVolThreshold = (threshold_percent * mAudioStreamMax) / 100;
2939ef4a582ed78ae48b867012ea53ba3cec79a31f7Pavlin Radoslavov            }
29411798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
295e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
296e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // Register for package removal intent broadcasts for media button receiver persistence
297e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        IntentFilter pkgFilter = new IntentFilter();
298e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
299e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
300e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
301e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
302e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addDataScheme("package");
303e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        context.registerReceiver(mAvrcpReceiver, pkgFilter);
3040427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker
3050427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        IntentFilter bootFilter = new IntentFilter();
306eb829bbfa257c84c4f8fa589b54791e3f413b486Ajay Panicker        bootFilter.addAction(Intent.ACTION_USER_UNLOCKED);
3070427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        context.registerReceiver(mBootReceiver, bootFilter);
308c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
309c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
310676768272f84bc3fef9068b6286b6f38cb1e8962Marie Janssen    private synchronized void start() {
311c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler");
312c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        thread.start();
313c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Looper looper = thread.getLooper();
314c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler = new AvrcpMessageHandler(looper);
31576aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        mAudioManagerPlaybackHandler = new Handler(looper);
31676aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        mAudioManagerPlaybackCb = new AudioManagerPlaybackListener();
3179d4035307b85e78f10fba961e225ca09bfb7d0c7Jakub Pawlowski        mMediaControllerCb = new MediaControllerListener();
318e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAvrcpMediaRsp = new AvrcpMediaRsp();
319351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        mMediaPlayerInfoList = new TreeMap<Integer, MediaPlayerInfo>();
32085ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen        mAvailablePlayerViewChanged = false;
321241af80129d66d60eea6e77e8962b7123e1c61c5Marie Janssen        mBrowsePlayerInfoList = Collections.synchronizedList(new ArrayList<BrowsePlayerInfo>());
322bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        mPassthroughDispatched = 0;
323bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        mPassthroughLogs = new EvictingQueue<MediaKeyLog>(PASSTHROUGH_LOG_MAX_SIZE);
3240c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        mPassthroughPending = Collections.synchronizedList(new ArrayList<MediaKeyLog>());
325f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen        if (mMediaSessionManager != null) {
326f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen            mMediaSessionManager.addOnActiveSessionsChangedListener(mActiveSessionListener, null,
327f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen                    mHandler);
328bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            mMediaSessionManager.setCallback(mButtonDispatchCallback, null);
329f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen        }
330e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mPackageManager = mContext.getApplicationContext().getPackageManager();
331e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
332e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* create object to communicate with addressed player */
333e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAddressedMediaPlayer = new AddressedMediaPlayer(mAvrcpMediaRsp);
334e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
335e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* initialize BrowseMananger which manages Browse commands and response */
336e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAvrcpBrowseManager = new AvrcpBrowseManager(mContext, mAvrcpMediaRsp);
3370427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker
338bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        initMediaPlayersList();
33911bf73ff614f48a41dc379763bc007f271197b26Ajay Panicker
3400427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        UserManager manager = UserManager.get(mContext);
3410427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        if (manager == null || manager.isUserUnlocked()) {
3420427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker            if (DEBUG) Log.d(TAG, "User already unlocked, initializing player lists");
3433843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            // initialize browsable player list and build media player list
3441111f243441532aefeadf322a9ab9800e330007bAjay Panicker            buildBrowsablePlayerList();
3450427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        }
34676aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov
34776aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        mAudioManager.registerAudioPlaybackCallback(
34876aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                mAudioManagerPlaybackCb, mAudioManagerPlaybackHandler);
349c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
350c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
351066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    public static Avrcp make(Context context) {
352c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (DEBUG) Log.v(TAG, "make");
353c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Avrcp ar = new Avrcp(context);
354c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ar.start();
355c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return ar;
356c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
357c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
358676768272f84bc3fef9068b6286b6f38cb1e8962Marie Janssen    public synchronized void doQuit() {
359e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "doQuit");
36076aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        if (mAudioManager != null) {
36176aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            mAudioManager.unregisterAudioPlaybackCallback(mAudioManagerPlaybackCb);
36276aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        }
363676768272f84bc3fef9068b6286b6f38cb1e8962Marie Janssen        if (mMediaController != null) mMediaController.unregisterCallback(mMediaControllerCb);
364579be982d9d3ffa93c38fe27589db8eae80d1d34Marie Janssen        if (mMediaSessionManager != null) {
365579be982d9d3ffa93c38fe27589db8eae80d1d34Marie Janssen            mMediaSessionManager.setCallback(null, null);
366579be982d9d3ffa93c38fe27589db8eae80d1d34Marie Janssen            mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveSessionListener);
367579be982d9d3ffa93c38fe27589db8eae80d1d34Marie Janssen        }
368579be982d9d3ffa93c38fe27589db8eae80d1d34Marie Janssen
36976aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        mAudioManagerPlaybackHandler.removeCallbacksAndMessages(null);
370c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.removeCallbacksAndMessages(null);
371c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Looper looper = mHandler.getLooper();
372c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (looper != null) {
373c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            looper.quit();
374c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
375e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
37676aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        mAudioManagerPlaybackHandler = null;
377e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler = null;
378e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mContext.unregisterReceiver(mAvrcpReceiver);
3790427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        mContext.unregisterReceiver(mBootReceiver);
380e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
381e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAddressedMediaPlayer.cleanup();
382e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAvrcpBrowseManager.cleanup();
383c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
384c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
385c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    public void cleanup() {
386e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "cleanup");
387c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        cleanupNative();
38811798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (mVolumeMapping != null)
38911798b011c962b602217b479130d413f3b30f19aLiejun Tao            mVolumeMapping.clear();
390c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
391c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
39276aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov    private class AudioManagerPlaybackListener extends AudioManager.AudioPlaybackCallback {
39376aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        @Override
39476aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
39576aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            super.onPlaybackConfigChanged(configs);
39676aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            boolean isPlaying = false;
39776aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            for (AudioPlaybackConfiguration config : configs) {
39876aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                if (DEBUG) {
39976aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                    Log.d(TAG,
40076aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                            "AudioManager Player: "
40176aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                                    + AudioPlaybackConfiguration.toLogFriendlyString(config));
40276aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                }
40376aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                if (config.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
40476aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                    isPlaying = true;
40576aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                    break;
40676aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                }
40776aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            }
40876aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            if (DEBUG) Log.d(TAG, "AudioManager isPlaying: " + isPlaying);
40976aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            if (mAudioManagerIsPlaying != isPlaying) {
41076aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                mAudioManagerIsPlaying = isPlaying;
41176aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                updateCurrentMediaState();
41276aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            }
41376aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        }
41476aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov    }
41576aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov
4160e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen    private class MediaControllerListener extends MediaController.Callback {
4170e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        @Override
4180e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        public void onMetadataChanged(MediaMetadata metadata) {
419de5340b6cbe5e8bd62658131e87c551d0fc7a182Marie Janssen            if (DEBUG) Log.v(TAG, "onMetadataChanged");
42067c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            updateCurrentMediaState();
421c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
422bc10e7d58aa55da25c18d8056a0254a2b736146aZhihai Xu        @Override
423e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public synchronized void onPlaybackStateChanged(PlaybackState state) {
424351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen            if (DEBUG) Log.v(TAG, "onPlaybackStateChanged: state " + state.toString());
425093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker
42667c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            updateCurrentMediaState();
427c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
428c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
429c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
4300e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        public void onSessionDestroyed() {
4310e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            Log.v(TAG, "MediaController session destroyed");
43286582543b9cd70a617e84c049c03b466653e9641Marie Janssen            synchronized (Avrcp.this) {
43386582543b9cd70a617e84c049c03b466653e9641Marie Janssen                if (mMediaController != null)
43486582543b9cd70a617e84c049c03b466653e9641Marie Janssen                    removeMediaController(mMediaController.getWrappedInstance());
435d89304c6be6e1c332008dcbeab08889881064454Marie Janssen            }
436c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
437c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
438c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
439e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void onQueueChanged(List<MediaSession.QueueItem> queue) {
440e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (queue == null) {
441e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.v(TAG, "onQueueChanged: received null queue");
442e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return;
443e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
4442b903c7262c9b8c0493e36b93b37831e7e075bfcMarie Janssen
445e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Log.v(TAG, "onQueueChanged: NowPlaying list changed, Queue Size = "+ queue.size());
446093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            mHandler.sendEmptyMessage(MSG_NOW_PLAYING_CHANGED_RSP);
447c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
448c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
449c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
450c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    /** Handles Avrcp messages. */
451c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private final class AvrcpMessageHandler extends Handler {
452c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        private AvrcpMessageHandler(Looper looper) {
453c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            super(looper);
454c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
455c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
456c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
457c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public void handleMessage(Message msg) {
458c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            switch (msg.what) {
459e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_RC_FEATURES:
460e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            {
46117675906064bb72fdcca75baa56cdf8bb8968d01John Du                String address = (String) msg.obj;
46217675906064bb72fdcca75baa56cdf8bb8968d01John Du                mFeatures = msg.arg1;
46311798b011c962b602217b479130d413f3b30f19aLiejun Tao                mFeatures = modifyRcFeatureFromBlacklist(mFeatures, address);
4642167443fa83241273d2ccb36b72f0906e3c5338aPavlin Radoslavov                if (DEBUG) {
4652167443fa83241273d2ccb36b72f0906e3c5338aPavlin Radoslavov                    Log.v(TAG,
4662167443fa83241273d2ccb36b72f0906e3c5338aPavlin Radoslavov                            "MSG_NATIVE_REQ_GET_RC_FEATURES: address=" + address
4672167443fa83241273d2ccb36b72f0906e3c5338aPavlin Radoslavov                                    + ", features=" + msg.arg1 + ", mFeatures=" + mFeatures);
4682167443fa83241273d2ccb36b72f0906e3c5338aPavlin Radoslavov                }
46917675906064bb72fdcca75baa56cdf8bb8968d01John Du                mAudioManager.avrcpSupportsAbsoluteVolume(address, isAbsoluteVolumeSupported());
47011798b011c962b602217b479130d413f3b30f19aLiejun Tao                mLastLocalVolume = -1;
47111798b011c962b602217b479130d413f3b30f19aLiejun Tao                mRemoteVolume = -1;
47211798b011c962b602217b479130d413f3b30f19aLiejun Tao                mLocalVolume = -1;
47311798b011c962b602217b479130d413f3b30f19aLiejun Tao                mInitialRemoteVolume = -1;
47411798b011c962b602217b479130d413f3b30f19aLiejun Tao                mAddress = address;
47511798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mVolumeMapping != null)
47611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolumeMapping.clear();
47717675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
478e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
47917675906064bb72fdcca75baa56cdf8bb8968d01John Du
480e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_PLAY_STATUS:
481e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            {
482e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] address = (byte[]) msg.obj;
483b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                int btstate = getBluetoothPlayState(mCurrentPlayState);
484303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                int length = (int) mMediaAttributes.getLength();
485303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                int position = (int) getPlayPosition();
486303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                if (DEBUG)
487303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                    Log.v(TAG, "MSG_NATIVE_REQ_GET_PLAY_STATUS, responding with state " + btstate
488303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                                    + " len " + length + " pos " + position);
489303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                getPlayStatusRspNative(address, btstate, length, position);
490c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
491e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
492c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
493e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_ELEM_ATTRS:
494e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            {
495c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                String[] textArray;
496e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                AvrcpCmd.ElementAttrCmd elem = (AvrcpCmd.ElementAttrCmd) msg.obj;
497e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte numAttr = elem.mNumAttr;
498e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                int[] attrIds = elem.mAttrIDs;
499e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_ELEM_ATTRS:numAttr=" + numAttr);
500c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                textArray = new String[numAttr];
501303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                StringBuilder responseDebug = new StringBuilder();
502303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                responseDebug.append("getElementAttr response: ");
503c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                for (int i = 0; i < numAttr; ++i) {
5043b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    textArray[i] = mMediaAttributes.getString(attrIds[i]);
505029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                    responseDebug.append("[" + attrIds[i] + "=");
506029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                    if (attrIds[i] == AvrcpConstants.ATTRID_TITLE
507029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                            || attrIds[i] == AvrcpConstants.ATTRID_ARTIST
508029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                            || attrIds[i] == AvrcpConstants.ATTRID_ALBUM) {
509029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                        responseDebug.append(Utils.ellipsize(textArray[i]) + "] ");
510029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                    } else {
511029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                        responseDebug.append(textArray[i] + "] ");
512029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                    }
513c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                }
514303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                Log.v(TAG, responseDebug.toString());
515e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] bdaddr = elem.mAddress;
516e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                getElementAttrRspNative(bdaddr, numAttr, attrIds, textArray);
517c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
518e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
519c1124a7c6679f612b80926a19084655f9a71580aMarie Janssen
520e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_REGISTER_NOTIFICATION:
521e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_REGISTER_NOTIFICATION:event=" + msg.arg1 +
522e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        " param=" + msg.arg2);
523e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                processRegisterNotification((byte[]) msg.obj, msg.arg1, msg.arg2);
524c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
525c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
526a7cf67c3e381792a7648b02d61b0fce75c4cc210Marie Janssen            case MSG_NOW_PLAYING_CHANGED_RSP:
527a7cf67c3e381792a7648b02d61b0fce75c4cc210Marie Janssen                if (DEBUG) Log.v(TAG, "MSG_NOW_PLAYING_CHANGED_RSP");
528a7cf67c3e381792a7648b02d61b0fce75c4cc210Marie Janssen                removeMessages(MSG_NOW_PLAYING_CHANGED_RSP);
52967c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                updateCurrentMediaState();
530a7cf67c3e381792a7648b02d61b0fce75c4cc210Marie Janssen                break;
531a7cf67c3e381792a7648b02d61b0fce75c4cc210Marie Janssen
532e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_PLAY_INTERVAL_TIMEOUT:
533f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                sendPlayPosNotificationRsp(false);
534aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                break;
535aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
536e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_VOLUME_CHANGE:
53711798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (!isAbsoluteVolumeSupported()) {
538303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                    if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_VOLUME_CHANGE ignored, not supported");
53911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
54011798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
541303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                byte absVol = (byte) ((byte) msg.arg1 & 0x7f); // discard MSB as it is RFD
542303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                if (DEBUG)
543303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                    Log.v(TAG, "MSG_NATIVE_REQ_VOLUME_CHANGE: volume=" + absVol + " ctype="
544303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen                                    + msg.arg2);
54511798b011c962b602217b479130d413f3b30f19aLiejun Tao
54611798b011c962b602217b479130d413f3b30f19aLiejun Tao                boolean volAdj = false;
54717675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (msg.arg2 == AVRC_RSP_ACCEPT || msg.arg2 == AVRC_RSP_REJ) {
54811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mVolCmdAdjustInProgress == false && mVolCmdSetInProgress == false) {
54917675906064bb72fdcca75baa56cdf8bb8968d01John Du                        Log.e(TAG, "Unsolicited response, ignored");
55017675906064bb72fdcca75baa56cdf8bb8968d01John Du                        break;
55117675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
552e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    removeMessages(MSG_ABS_VOL_TIMEOUT);
55311798b011c962b602217b479130d413f3b30f19aLiejun Tao
55411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    volAdj = mVolCmdAdjustInProgress;
55511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolCmdAdjustInProgress = false;
55611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolCmdSetInProgress = false;
55717675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes = 0;
55817675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
55911798b011c962b602217b479130d413f3b30f19aLiejun Tao
56011798b011c962b602217b479130d413f3b30f19aLiejun Tao                // convert remote volume to local volume
56111798b011c962b602217b479130d413f3b30f19aLiejun Tao                int volIndex = convertToAudioStreamVolume(absVol);
56211798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mInitialRemoteVolume == -1) {
56311798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mInitialRemoteVolume = absVol;
56411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mAbsVolThreshold > 0 && mAbsVolThreshold < mAudioStreamMax && volIndex > mAbsVolThreshold) {
56511798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.v(TAG, "remote inital volume too high " + volIndex + ">" + mAbsVolThreshold);
566e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        Message msg1 = mHandler.obtainMessage(MSG_SET_ABSOLUTE_VOLUME, mAbsVolThreshold , 0);
56711798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mHandler.sendMessage(msg1);
56811798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mRemoteVolume = absVol;
56911798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLocalVolume = volIndex;
57011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        break;
57111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
57211798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
57311798b011c962b602217b479130d413f3b30f19aLiejun Tao
5740e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                if (mLocalVolume != volIndex && (msg.arg2 == AVRC_RSP_ACCEPT ||
5750e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                                                 msg.arg2 == AVRC_RSP_CHANGED ||
5760e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                                                 msg.arg2 == AVRC_RSP_INTERIM)) {
57711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    /* If the volume has successfully changed */
57811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mLocalVolume = volIndex;
57911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mLastLocalVolume != -1 && msg.arg2 == AVRC_RSP_ACCEPT) {
58011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (mLastLocalVolume != volIndex) {
58111798b011c962b602217b479130d413f3b30f19aLiejun Tao                            /* remote volume changed more than requested due to
58211798b011c962b602217b479130d413f3b30f19aLiejun Tao                             * local and remote has different volume steps */
58311798b011c962b602217b479130d413f3b30f19aLiejun Tao                            if (DEBUG) Log.d(TAG, "Remote returned volume does not match desired volume "
584e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                                    + mLastLocalVolume + " vs " + volIndex);
58511798b011c962b602217b479130d413f3b30f19aLiejun Tao                            mLastLocalVolume = mLocalVolume;
58611798b011c962b602217b479130d413f3b30f19aLiejun Tao                        }
58711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
58811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    // remember the remote volume value, as it's the one supported by remote
58911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (volAdj) {
59011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        synchronized (mVolumeMapping) {
591e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                            mVolumeMapping.put(volIndex, (int) absVol);
59211798b011c962b602217b479130d413f3b30f19aLiejun Tao                            if (DEBUG) Log.v(TAG, "remember volume mapping " +volIndex+ "-"+absVol);
59311798b011c962b602217b479130d413f3b30f19aLiejun Tao                        }
59411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
59511798b011c962b602217b479130d413f3b30f19aLiejun Tao
59611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    notifyVolumeChanged(mLocalVolume);
59711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mRemoteVolume = absVol;
598e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    long pecentVolChanged = ((long) absVol * 100) / 0x7f;
5995c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                    Log.e(TAG, "percent volume changed: " + pecentVolChanged + "%");
60017675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else if (msg.arg2 == AVRC_RSP_REJ) {
60117675906064bb72fdcca75baa56cdf8bb8968d01John Du                    Log.e(TAG, "setAbsoluteVolume call rejected");
60211798b011c962b602217b479130d413f3b30f19aLiejun Tao                } else if (volAdj && mLastRemoteVolume > 0 && mLastRemoteVolume < AVRCP_MAX_VOL &&
6030e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                        mLocalVolume == volIndex &&
604e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        (msg.arg2 == AVRC_RSP_ACCEPT)) {
60511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    /* oops, the volume is still same, remote does not like the value
60611798b011c962b602217b479130d413f3b30f19aLiejun Tao                     * retry a volume one step up/down */
60711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.d(TAG, "Remote device didn't tune volume, let's try one more step.");
60811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    int retry_volume = Math.min(AVRCP_MAX_VOL,
60911798b011c962b602217b479130d413f3b30f19aLiejun Tao                            Math.max(0, mLastRemoteVolume + mLastDirection));
61011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (setVolumeNative(retry_volume)) {
61111798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLastRemoteVolume = retry_volume;
612e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
61311798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mVolCmdAdjustInProgress = true;
61411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
61517675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
61617675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
61717675906064bb72fdcca75baa56cdf8bb8968d01John Du
618e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_ADJUST_VOLUME:
61911798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (!isAbsoluteVolumeSupported()) {
620e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    if (DEBUG) Log.v(TAG, "ignore MSG_ADJUST_VOLUME");
62111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
62211798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
62311798b011c962b602217b479130d413f3b30f19aLiejun Tao
624e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.d(TAG, "MSG_ADJUST_VOLUME: direction=" + msg.arg1);
62511798b011c962b602217b479130d413f3b30f19aLiejun Tao
62611798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mVolCmdAdjustInProgress || mVolCmdSetInProgress) {
62717675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
62817675906064bb72fdcca75baa56cdf8bb8968d01John Du                    break;
62917675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
63011798b011c962b602217b479130d413f3b30f19aLiejun Tao
63111798b011c962b602217b479130d413f3b30f19aLiejun Tao                // Remote device didn't set initial volume. Let's black list it
63211798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mInitialRemoteVolume == -1) {
63311798b011c962b602217b479130d413f3b30f19aLiejun Tao                    Log.d(TAG, "remote " + mAddress + " never tell us initial volume, black list it.");
63411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    blackListCurrentDevice();
63511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
63611798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
63711798b011c962b602217b479130d413f3b30f19aLiejun Tao
63817675906064bb72fdcca75baa56cdf8bb8968d01John Du                // Wait on verification on volume from device, before changing the volume.
63911798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mRemoteVolume != -1 && (msg.arg1 == -1 || msg.arg1 == 1)) {
64011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    int setVol = -1;
64111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    int targetVolIndex = -1;
64211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mLocalVolume == 0 && msg.arg1 == -1) {
64311798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.w(TAG, "No need to Vol down from 0.");
64411798b011c962b602217b479130d413f3b30f19aLiejun Tao                        break;
64511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
64611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mLocalVolume == mAudioStreamMax && msg.arg1 == 1) {
64711798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.w(TAG, "No need to Vol up from max.");
64811798b011c962b602217b479130d413f3b30f19aLiejun Tao                        break;
64911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
65011798b011c962b602217b479130d413f3b30f19aLiejun Tao
65111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    targetVolIndex = mLocalVolume + msg.arg1;
65211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.d(TAG, "Adjusting volume to  " + targetVolIndex);
65311798b011c962b602217b479130d413f3b30f19aLiejun Tao
65411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    Integer i;
65511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    synchronized (mVolumeMapping) {
65611798b011c962b602217b479130d413f3b30f19aLiejun Tao                        i = mVolumeMapping.get(targetVolIndex);
65711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
65811798b011c962b602217b479130d413f3b30f19aLiejun Tao
65911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (i != null) {
66011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        /* if we already know this volume mapping, use it */
66111798b011c962b602217b479130d413f3b30f19aLiejun Tao                        setVol = i.byteValue();
66211798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (setVol == mRemoteVolume) {
66311798b011c962b602217b479130d413f3b30f19aLiejun Tao                            if (DEBUG) Log.d(TAG, "got same volume from mapping for " + targetVolIndex + ", ignore.");
66411798b011c962b602217b479130d413f3b30f19aLiejun Tao                            setVol = -1;
66511798b011c962b602217b479130d413f3b30f19aLiejun Tao                        }
66611798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.d(TAG, "set volume from mapping " + targetVolIndex + "-" + setVol);
66711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
66811798b011c962b602217b479130d413f3b30f19aLiejun Tao
66911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (setVol == -1) {
67011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        /* otherwise use phone steps */
67111798b011c962b602217b479130d413f3b30f19aLiejun Tao                        setVol = Math.min(AVRCP_MAX_VOL,
672e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                                convertToAvrcpVolume(Math.max(0, targetVolIndex)));
67311798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.d(TAG, "set volume from local volume "+ targetVolIndex+"-"+ setVol);
67411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
67511798b011c962b602217b479130d413f3b30f19aLiejun Tao
67617675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (setVolumeNative(setVol)) {
677e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
67811798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mVolCmdAdjustInProgress = true;
67917675906064bb72fdcca75baa56cdf8bb8968d01John Du                        mLastDirection = msg.arg1;
68011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLastRemoteVolume = setVol;
68111798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLastLocalVolume = targetVolIndex;
68211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    } else {
68311798b011c962b602217b479130d413f3b30f19aLiejun Tao                         if (DEBUG) Log.d(TAG, "setVolumeNative failed");
68417675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
68517675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else {
686e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "Unknown direction in MSG_ADJUST_VOLUME");
68717675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
68817675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
68917675906064bb72fdcca75baa56cdf8bb8968d01John Du
690e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_SET_ABSOLUTE_VOLUME:
69111798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (!isAbsoluteVolumeSupported()) {
692e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    if (DEBUG) Log.v(TAG, "ignore MSG_SET_ABSOLUTE_VOLUME");
69311798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
69411798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
69511798b011c962b602217b479130d413f3b30f19aLiejun Tao
696e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_SET_ABSOLUTE_VOLUME");
69711798b011c962b602217b479130d413f3b30f19aLiejun Tao
69811798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mVolCmdSetInProgress || mVolCmdAdjustInProgress) {
69917675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
70017675906064bb72fdcca75baa56cdf8bb8968d01John Du                    break;
70117675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
70211798b011c962b602217b479130d413f3b30f19aLiejun Tao
70311798b011c962b602217b479130d413f3b30f19aLiejun Tao                // Remote device didn't set initial volume. Let's black list it
70411798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mInitialRemoteVolume == -1) {
70511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.d(TAG, "remote " + mAddress + " never tell us initial volume, black list it.");
70611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    blackListCurrentDevice();
70711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
70811798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
70911798b011c962b602217b479130d413f3b30f19aLiejun Tao
71011798b011c962b602217b479130d413f3b30f19aLiejun Tao                int avrcpVolume = convertToAvrcpVolume(msg.arg1);
71111798b011c962b602217b479130d413f3b30f19aLiejun Tao                avrcpVolume = Math.min(AVRCP_MAX_VOL, Math.max(0, avrcpVolume));
7123b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                if (DEBUG) Log.d(TAG, "Setting volume to " + msg.arg1 + "-" + avrcpVolume);
71311798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (setVolumeNative(avrcpVolume)) {
714e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
71511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolCmdSetInProgress = true;
71611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mLastRemoteVolume = avrcpVolume;
71711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mLastLocalVolume = msg.arg1;
71811798b011c962b602217b479130d413f3b30f19aLiejun Tao                } else {
71911798b011c962b602217b479130d413f3b30f19aLiejun Tao                     if (DEBUG) Log.d(TAG, "setVolumeNative failed");
72017675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
72117675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
72217675906064bb72fdcca75baa56cdf8bb8968d01John Du
723e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_ABS_VOL_TIMEOUT:
724e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_ABS_VOL_TIMEOUT: Volume change cmd timed out.");
72511798b011c962b602217b479130d413f3b30f19aLiejun Tao                mVolCmdAdjustInProgress = false;
72611798b011c962b602217b479130d413f3b30f19aLiejun Tao                mVolCmdSetInProgress = false;
72717675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (mAbsVolRetryTimes >= MAX_ERROR_RETRY_TIMES) {
72817675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes = 0;
729f8201e1c6bf7fadc0a332151a652325a7f31255aLiejun Tao                    /* too many volume change failures, black list the device */
730f8201e1c6bf7fadc0a332151a652325a7f31255aLiejun Tao                    blackListCurrentDevice();
73117675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else {
73217675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes += 1;
73311798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (setVolumeNative(mLastRemoteVolume)) {
734e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
73511798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mVolCmdSetInProgress = true;
73617675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
73717675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
73817675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
73917675906064bb72fdcca75baa56cdf8bb8968d01John Du
740e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_SET_A2DP_AUDIO_STATE:
741e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_SET_A2DP_AUDIO_STATE:" + msg.arg1);
74293f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen                mA2dpState = msg.arg1;
74367c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                updateCurrentMediaState();
744188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                break;
745e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
746e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_FOLDER_ITEMS: {
747e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                AvrcpCmd.FolderItemsCmd folderObj = (AvrcpCmd.FolderItemsCmd) msg.obj;
7480f9c79e8afa3e575dfd8c80c2c58b9321e18898dMarie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_FOLDER_ITEMS " + folderObj);
749e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                switch (folderObj.mScope) {
750e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    case AvrcpConstants.BTRC_SCOPE_PLAYER_LIST:
751e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        handleMediaPlayerListRsp(folderObj);
752e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        break;
753e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    case AvrcpConstants.BTRC_SCOPE_FILE_SYSTEM:
754e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    case AvrcpConstants.BTRC_SCOPE_NOW_PLAYING:
755e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        handleGetFolderItemBrowseResponse(folderObj, folderObj.mAddress);
756e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        break;
757e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    default:
758e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        Log.e(TAG, "unknown scope for getfolderitems. scope = "
759e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                                + folderObj.mScope);
760e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        getFolderItemsRspNative(folderObj.mAddress,
761e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                                AvrcpConstants.RSP_INV_SCOPE, (short) 0, (byte) 0, 0,
762e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                                null, null, null, null, null, null, null, null);
763e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
764e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
765e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
766e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
767e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_SET_ADDR_PLAYER:
768e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                // object is bdaddr, argument 1 is the selected player id
769b3436e976055f684050be9afdadc73645316806aMarie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_SET_ADDR_PLAYER id=" + msg.arg1);
770e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                setAddressedPlayer((byte[]) msg.obj, msg.arg1);
771e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
772e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
773e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_ITEM_ATTR:
774e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                // msg object contains the item attribute object
7750f9c79e8afa3e575dfd8c80c2c58b9321e18898dMarie Janssen                AvrcpCmd.ItemAttrCmd cmd = (AvrcpCmd.ItemAttrCmd) msg.obj;
7760f9c79e8afa3e575dfd8c80c2c58b9321e18898dMarie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_ITEM_ATTR " + cmd);
7770f9c79e8afa3e575dfd8c80c2c58b9321e18898dMarie Janssen                handleGetItemAttr(cmd);
778e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
779e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
780e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_SET_BR_PLAYER:
781e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                // argument 1 is the selected player id
782b3436e976055f684050be9afdadc73645316806aMarie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_SET_BR_PLAYER id=" + msg.arg1);
783e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                setBrowsedPlayer((byte[]) msg.obj, msg.arg1);
784e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
785e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
786e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_CHANGE_PATH:
787e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            {
788b3436e976055f684050be9afdadc73645316806aMarie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_CHANGE_PATH");
789e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Bundle data = msg.getData();
790e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] bdaddr = data.getByteArray("BdAddress");
791e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] folderUid = data.getByteArray("folderUid");
792e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte direction = data.getByte("direction");
793e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) {
794e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).changePath(folderUid,
795e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        direction);
796e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                } else {
797e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "Remote requesting change path before setbrowsedplayer");
798e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    changePathRspNative(bdaddr, AvrcpConstants.RSP_BAD_CMD, 0);
799e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
800e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
801e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
802e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
803e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_PLAY_ITEM:
804e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            {
805e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Bundle data = msg.getData();
806e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] bdaddr = data.getByteArray("BdAddress");
807e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] uid = data.getByteArray("uid");
808e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte scope = data.getByte("scope");
8090f9c79e8afa3e575dfd8c80c2c58b9321e18898dMarie Janssen                if (DEBUG)
8100f9c79e8afa3e575dfd8c80c2c58b9321e18898dMarie Janssen                    Log.v(TAG, "MSG_NATIVE_REQ_PLAY_ITEM scope=" + scope + " id="
8110f9c79e8afa3e575dfd8c80c2c58b9321e18898dMarie Janssen                                    + Utils.byteArrayToString(uid));
812e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                handlePlayItemResponse(bdaddr, uid, scope);
813e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
814e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
815e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
816e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS:
817b3436e976055f684050be9afdadc73645316806aMarie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS scope=" + msg.arg1);
818e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                // argument 1 is scope, object is bdaddr
819e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                handleGetTotalNumOfItemsResponse((byte[]) msg.obj, (byte) msg.arg1);
820e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
821e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
822e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_PASS_THROUGH:
823b3436e976055f684050be9afdadc73645316806aMarie Janssen                if (DEBUG)
824bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    Log.v(TAG, "MSG_NATIVE_REQ_PASS_THROUGH: id=" + msg.arg1 + " st=" + msg.arg2);
825bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                // argument 1 is id, argument 2 is keyState
826bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                handlePassthroughCmd(msg.arg1, msg.arg2);
827e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
828e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
829e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            default:
830e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "unknown message! msg.what=" + msg.what);
831e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
832c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
833c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
834c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
835c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
836b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    private PlaybackState updatePlaybackState() {
837b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        PlaybackState newState = new PlaybackState.Builder()
838b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                                         .setState(PlaybackState.STATE_NONE,
839b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                                                 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f)
840b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                                         .build();
841b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        synchronized (this) {
842b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen            PlaybackState controllerState = null;
843b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen            if (mMediaController != null) {
844b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                controllerState = mMediaController.getPlaybackState();
845b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen            }
846b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen
847b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen            if (controllerState != null) {
848b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                newState = controllerState;
84976aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            }
85076aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            // Use the AudioManager to update the playback state.
85176aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            // NOTE: We cannot use the
85276aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            //    (mA2dpState == BluetoothA2dp.STATE_PLAYING)
85376aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            // check, because after Pause, the A2DP state remains in
85476aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            // STATE_PLAYING for 3 more seconds.
85576aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            // As a result of that, if we pause the music, on carkits the
85676aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            // Play status indicator will continue to display "Playing"
85776aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov            // for 3 more seconds which can be confusing.
8585e600b2e36234f267aa2b2c171f0f4edf8fa65f1Pavlin Radoslavov            if ((mAudioManagerIsPlaying && newState.getState() != PlaybackState.STATE_PLAYING)
85976aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                    || (controllerState == null && mAudioManager != null
86076aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                               && mAudioManager.isMusicActive())) {
86176aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                // Use AudioManager playback state if we don't have the state
86276aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                // from MediaControlller
863b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                PlaybackState.Builder builder = new PlaybackState.Builder();
86476aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                if (mAudioManagerIsPlaying) {
865b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                    builder.setState(PlaybackState.STATE_PLAYING,
866b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                            PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f);
867b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                } else {
868b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                    builder.setState(PlaybackState.STATE_PAUSED,
869b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                            PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f);
870b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                }
871b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                newState = builder.build();
872b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen            }
8730e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        }
874f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
875b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        byte newPlayStatus = getBluetoothPlayState(newState);
87693f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen
877b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        /* update play status in global media player list */
87893f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen        MediaPlayerInfo player = getAddressedPlayerInfo();
87993f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen        if (player != null) {
880b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen            player.setPlayStatus(newPlayStatus);
88193f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen        }
88293f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen
883fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        if (DEBUG) {
884b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen            Log.v(TAG, "updatePlaybackState (" + mPlayStatusChangedNT + "): " + mReportedPlayStatus
885b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                            + "➡" + newPlayStatus + "(" + newState + ")");
886fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        }
887fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen
888b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        if (newState != null) mCurrentPlayState = newState;
889aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
890b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        return mCurrentPlayState;
891b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    }
892b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen
893b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    private void sendPlaybackStatus(int playStatusChangedNT, byte playbackState) {
894b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        registerNotificationRspPlayStatusNative(playStatusChangedNT, playbackState);
895b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        mPlayStatusChangedNT = playStatusChangedNT;
896b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        mReportedPlayStatus = playbackState;
897c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
898c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
899c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void updateTransportControls(int transportControlFlags) {
900c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mTransportControlFlags = transportControlFlags;
901c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
902c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
9033b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen    class MediaAttributes {
9043b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private boolean exists;
9053b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String title;
9063b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String artistName;
9073b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String albumName;
9083b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String mediaNumber;
9093b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String mediaTotalNumber;
9103b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String genre;
91193f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen        private long playingTimeMs;
9123b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9133b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_TITLE = 1;
9143b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_ARTIST_NAME = 2;
9153b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_ALBUM_NAME = 3;
9163b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_MEDIA_NUMBER = 4;
9173b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_MEDIA_TOTAL_NUMBER = 5;
9183b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_GENRE = 6;
9193b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_PLAYING_TIME_MS = 7;
9203b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9213b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9223b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        public MediaAttributes(MediaMetadata data) {
9233b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            exists = data != null;
9243b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (!exists)
9253b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return;
9263b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9273b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            artistName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ARTIST));
9283b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            albumName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ALBUM));
9293b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            mediaNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER));
9303b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            mediaTotalNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS));
9313b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            genre = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_GENRE));
93293f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen            playingTimeMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION);
9333b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9343b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            // Try harder for the title.
9353b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            title = data.getString(MediaMetadata.METADATA_KEY_TITLE);
9363b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9373b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (title == null) {
9383b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                MediaDescription desc = data.getDescription();
9393b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                if (desc != null) {
9403b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    CharSequence val = desc.getDescription();
9413b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    if (val != null)
9423b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                        title = val.toString();
9433b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                }
9443b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            }
9453b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9463b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (title == null)
9473b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                title = new String();
9483b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
9493b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
95093f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen        public long getLength() {
95193f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen            if (!exists) return 0L;
95293f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen            return playingTimeMs;
95393f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen        }
95493f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen
9553b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        public boolean equals(MediaAttributes other) {
9563b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (other == null)
9573b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return false;
9583b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9593b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (exists != other.exists)
9603b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return false;
9613b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9623b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (exists == false)
9633b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return true;
9643b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
96593f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen            return (title.equals(other.title)) && (artistName.equals(other.artistName))
96693f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen                    && (albumName.equals(other.albumName))
96793f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen                    && (mediaNumber.equals(other.mediaNumber))
96893f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen                    && (mediaTotalNumber.equals(other.mediaTotalNumber))
96993f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen                    && (genre.equals(other.genre)) && (playingTimeMs == other.playingTimeMs);
9703b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
9713b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9723b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        public String getString(int attrId) {
9733b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (!exists)
9743b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return new String();
9753b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9763b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            switch (attrId) {
9773b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_TITLE:
9783b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return title;
9793b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_ARTIST_NAME:
9803b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return artistName;
9813b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_ALBUM_NAME:
9823b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return albumName;
9833b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_MEDIA_NUMBER:
9843b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return mediaNumber;
9853b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_MEDIA_TOTAL_NUMBER:
9863b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return mediaTotalNumber;
9873b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_GENRE:
9883b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return genre;
9893b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_PLAYING_TIME_MS:
99093f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen                    return Long.toString(playingTimeMs);
9913b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                default:
9923b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return new String();
9933b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            }
9943b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
9953b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9963b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String stringOrBlank(String s) {
9973b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            return s == null ? new String() : s;
9983b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
999c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
10003b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String longStringOrBlank(Long s) {
10013b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            return s == null ? new String() : s.toString();
1002c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1003c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1004c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public String toString() {
1005e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!exists) {
10063b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return "[MediaAttributes: none]";
1007e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
10083b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
100993f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen            return "[MediaAttributes: " + title + " - " + albumName + " by " + artistName + " ("
101093f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen                    + playingTimeMs + " " + mediaNumber + "/" + mediaTotalNumber + ") " + genre
101193f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen                    + "]";
1012c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1013029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen
1014029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen        public String toRedactedString() {
1015029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen            if (!exists) {
1016029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                return "[MediaAttributes: none]";
1017029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen            }
1018029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen
1019029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen            return "[MediaAttributes: " + Utils.ellipsize(title) + " - "
1020029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                    + Utils.ellipsize(albumName) + " by " + Utils.ellipsize(artistName) + " ("
1021029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                    + playingTimeMs + " " + mediaNumber + "/" + mediaTotalNumber + ") " + genre
1022029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen                    + "]";
1023029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen        }
1024c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1025c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
102667c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker    private void updateCurrentMediaState() {
102785ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen        // Only do player updates when we aren't registering for track changes.
1028d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen        MediaAttributes currentAttributes;
1029b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        PlaybackState newState = updatePlaybackState();
1030b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen
103186582543b9cd70a617e84c049c03b466653e9641Marie Janssen        synchronized (this) {
103286582543b9cd70a617e84c049c03b466653e9641Marie Janssen            if (mMediaController == null) {
1033d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen                currentAttributes = new MediaAttributes(null);
103490dcb467d4964f65bde4f847a2e8fe0fe048c3a7Marie Janssen            } else {
1035d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen                currentAttributes = new MediaAttributes(mMediaController.getMetadata());
103693f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen            }
10370e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        }
1038e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
10393211ee063dc32e07ab00d94312637dd7c27d2bbaAjay Panicker        byte newPlayStatus = getBluetoothPlayState(newState);
10403211ee063dc32e07ab00d94312637dd7c27d2bbaAjay Panicker
1041093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker        if (newState.getState() != PlaybackState.STATE_BUFFERING
1042093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker                && newState.getState() != PlaybackState.STATE_NONE) {
1043093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            long newQueueId = MediaSession.QueueItem.UNKNOWN_ID;
1044093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            if (newState != null) newQueueId = newState.getActiveQueueItemId();
1045093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            Log.v(TAG, "Media update: id " + mLastQueueId + "➡" + newQueueId + "? "
1046093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker                            + currentAttributes.toRedactedString() + " : "
1047093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker                            + mMediaAttributes.toRedactedString());
1048093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker
104967c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            if (mAvailablePlayerViewChanged) {
105067c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                registerNotificationRspAvalPlayerChangedNative(
105167c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                        AvrcpConstants.NOTIFICATION_TYPE_CHANGED);
105267c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                mAvailablePlayerViewChanged = false;
105367c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                return;
105467c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            }
105567c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker
105667c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            if (mAddrPlayerChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM
105767c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                    && mReportedPlayerID != mCurrAddrPlayerID) {
105867c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                registerNotificationRspAvalPlayerChangedNative(
105967c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                        AvrcpConstants.NOTIFICATION_TYPE_CHANGED);
106067c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                registerNotificationRspAddrPlayerChangedNative(
106167c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                        AvrcpConstants.NOTIFICATION_TYPE_CHANGED, mCurrAddrPlayerID, sUIDCounter);
106267c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker
106367c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                mAvailablePlayerViewChanged = false;
106467c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                mAddrPlayerChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
106567c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                mReportedPlayerID = mCurrAddrPlayerID;
106667c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker
106767c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                // Update the now playing list without sending the notification
106867c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                mNowPlayingListChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
106967c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                mAddressedMediaPlayer.updateNowPlayingList(mMediaController);
107067c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                mNowPlayingListChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
107167c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            }
107267c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker
1073093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            // Dont send now playing list changed if the player doesn't support browsing
1074093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            MediaPlayerInfo info = getAddressedPlayerInfo();
1075093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            if (info != null && info.isBrowseSupported()) {
1076093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker                Log.v(TAG, "Check if NowPlayingList is updated");
1077093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker                mAddressedMediaPlayer.updateNowPlayingList(mMediaController);
1078093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            }
1079093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker
1080093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            // Notify track changed if:
108167c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            //  - The CT is registered for the notification
1082093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            //  - Queue ID is UNKNOWN and MediaMetadata is different
108367c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            //  - Queue ID is valid and different from last Queue ID sent
108467c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            if ((newQueueId == -1 || newQueueId != mLastQueueId)
108567c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                    && mTrackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM
108667c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                    && !currentAttributes.equals(mMediaAttributes)
108767c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                    && newPlayStatus == PLAYSTATUS_PLAYING) {
1088093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker                Log.v(TAG, "Send track changed");
1089093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker                mMediaAttributes = currentAttributes;
1090093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker                mLastQueueId = newQueueId;
109167c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                sendTrackChangedRsp(false);
1092093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            }
1093093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker        } else {
1094093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            Log.i(TAG, "Skipping update due to invalid playback state");
1095c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1096093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker
10973211ee063dc32e07ab00d94312637dd7c27d2bbaAjay Panicker        // still send the updated play state if the playback state is none or buffering
109876aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov        Log.e(TAG,
109976aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                "play status change " + mReportedPlayStatus + "➡" + newPlayStatus
110076aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                        + " mPlayStatusChangedNT: " + mPlayStatusChangedNT);
11013211ee063dc32e07ab00d94312637dd7c27d2bbaAjay Panicker        if (mPlayStatusChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM
110276aab6dba7956b15c6daafe99b6dddab3eb028a0Pavlin Radoslavov                || (mReportedPlayStatus != newPlayStatus)) {
11033211ee063dc32e07ab00d94312637dd7c27d2bbaAjay Panicker            sendPlaybackStatus(AvrcpConstants.NOTIFICATION_TYPE_CHANGED, newPlayStatus);
11043211ee063dc32e07ab00d94312637dd7c27d2bbaAjay Panicker        }
11053211ee063dc32e07ab00d94312637dd7c27d2bbaAjay Panicker
1106b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        sendPlayPosNotificationRsp(false);
1107c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1108c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1109e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void getRcFeaturesRequestFromNative(byte[] address, int features) {
1110e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_RC_FEATURES, features, 0,
1111e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Utils.getAddressStringFromByte(address));
111217675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
111317675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
111417675906064bb72fdcca75baa56cdf8bb8968d01John Du
1115e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void getPlayStatusRequestFromNative(byte[] address) {
1116e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_PLAY_STATUS);
1117e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1118c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
1119c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1120c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
11210f9c79e8afa3e575dfd8c80c2c58b9321e18898dMarie Janssen    private void getElementAttrRequestFromNative(byte[] address, byte numAttr, int[] attrs) {
1122e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd avrcpCmdobj = new AvrcpCmd();
1123e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd.ElementAttrCmd elemAttr = avrcpCmdobj.new ElementAttrCmd(address, numAttr, attrs);
1124e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_ELEM_ATTRS);
1125e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = elemAttr;
1126c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
1127c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1128c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1129e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void registerNotificationRequestFromNative(byte[] address,int eventId, int param) {
1130e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_REGISTER_NOTIFICATION, eventId, param);
1131e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1132c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
1133c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1134c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1135e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void processRegisterNotification(byte[] address, int eventId, int param) {
1136c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        switch (eventId) {
1137c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case EVT_PLAY_STATUS_CHANGED:
1138b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
1139b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                updatePlaybackState();
11403211ee063dc32e07ab00d94312637dd7c27d2bbaAjay Panicker                sendPlaybackStatus(AvrcpConstants.NOTIFICATION_TYPE_INTERIM, mReportedPlayStatus);
1141c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1142c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1143c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case EVT_TRACK_CHANGED:
11440e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                Log.v(TAG, "Track changed notification enabled");
1145e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
1146093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker                sendTrackChangedRsp(true);
1147c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1148c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1149aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            case EVT_PLAY_POS_CHANGED:
1150e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
1151e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mPlaybackIntervalMs = (long) param * 1000L;
1152fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen                sendPlayPosNotificationRsp(true);
1153aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                break;
1154aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
1155e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVT_AVBL_PLAYERS_CHANGED:
1156e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                /* Notify remote available players changed */
1157d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen                if (DEBUG) Log.d(TAG, "Available Players notification enabled");
1158e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                registerNotificationRspAvalPlayerChangedNative(
1159e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        AvrcpConstants.NOTIFICATION_TYPE_INTERIM);
1160e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1161e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1162e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVT_ADDR_PLAYER_CHANGED:
1163e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                /* Notify remote addressed players changed */
1164d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen                if (DEBUG) Log.d(TAG, "Addressed Player notification enabled");
1165e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                registerNotificationRspAddrPlayerChangedNative(
1166e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        AvrcpConstants.NOTIFICATION_TYPE_INTERIM,
1167e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        mCurrAddrPlayerID, sUIDCounter);
1168b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                mAddrPlayerChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
1169b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                mReportedPlayerID = mCurrAddrPlayerID;
1170e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1171e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1172e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVENT_UIDS_CHANGED:
1173d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen                if (DEBUG) Log.d(TAG, "UIDs changed notification enabled");
1174e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                registerNotificationRspUIDsChangedNative(
1175e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        AvrcpConstants.NOTIFICATION_TYPE_INTERIM, sUIDCounter);
1176e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1177e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1178e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVENT_NOW_PLAYING_CONTENT_CHANGED:
1179d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen                if (DEBUG) Log.d(TAG, "Now Playing List changed notification enabled");
1180e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                /* send interim response to remote device */
11813616b7ce7be6abaca5eef876e055155f9e8a3b1fAjay Panicker                mNowPlayingListChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
1182e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!registerNotificationRspNowPlayingChangedNative(
1183e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        AvrcpConstants.NOTIFICATION_TYPE_INTERIM)) {
1184e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "EVENT_NOW_PLAYING_CONTENT_CHANGED: " +
1185e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                            "registerNotificationRspNowPlayingChangedNative for Interim rsp failed!");
1186e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
1187e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1188c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1189c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1190c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1191e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handlePassthroughCmdRequestFromNative(byte[] address, int id, int keyState) {
1192bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_PASS_THROUGH, id, keyState);
1193e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1194ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
1195ace834feb02adabd61f628c4471147aea02d939cJohn Du
1196d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen    private void sendTrackChangedRsp(boolean registering) {
1197d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen        if (!registering && mTrackChangedNT != AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
1198d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen            if (DEBUG) Log.d(TAG, "sendTrackChangedRsp: Not registered or registering.");
1199827c417f70082918b965a5213c38395398389811Marie Janssen            return;
1200827c417f70082918b965a5213c38395398389811Marie Janssen        }
1201d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen
1202d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen        mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
1203d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen        if (registering) mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
1204d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen
1205d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen        MediaPlayerInfo info = getAddressedPlayerInfo();
1206d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen        // for non-browsable players or no player
1207351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        if (info != null && !info.isBrowseSupported()) {
1208d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen            byte[] track = AvrcpConstants.TRACK_IS_SELECTED;
1209d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen            if (!mMediaAttributes.exists) track = AvrcpConstants.NO_TRACK_SELECTED;
1210d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen            registerNotificationRspTrackChangeNative(mTrackChangedNT, track);
1211d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen            return;
1212e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou        }
1213e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou
1214d5b2445ec7ff3809c1c90a9b20784a6a861a037cMarie Janssen        mAddressedMediaPlayer.sendTrackChangeWithId(mTrackChangedNT, mMediaController);
1215c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1216c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1217aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long getPlayPosition() {
1218e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (mCurrentPlayState == null) {
1219f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            return -1L;
1220e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1221f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1222e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (mCurrentPlayState.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
1223f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            return -1L;
1224e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1225f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1226f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        if (isPlayingState(mCurrentPlayState)) {
122793f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen            long sinceUpdate =
122893f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen                    (SystemClock.elapsedRealtime() - mCurrentPlayState.getLastPositionUpdateTime());
122993f177151f5b96ce3e06888884da3cd7f7858ecfMarie Janssen            return sinceUpdate + mCurrentPlayState.getPosition();
1230aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        }
1231f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
12323635a926bd7316a55b288a54d409a1070a9c19e8Marie Janssen        return mCurrentPlayState.getPosition();
1233aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    }
1234aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
1235b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    private boolean isPlayingState(@Nullable PlaybackState state) {
1236b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        if (state == null) return false;
1237093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker        return (state != null) && (state.getState() == PlaybackState.STATE_PLAYING);
1238188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
1239188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
124017675906064bb72fdcca75baa56cdf8bb8968d01John Du    /**
1241f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * Sends a play position notification, or schedules one to be
1242f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * sent later at an appropriate time. If |requested| is true,
1243f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * does both because this was called in reponse to a request from the
1244f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * TG.
1245f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     */
1246f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    private void sendPlayPosNotificationRsp(boolean requested) {
1247e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!requested && mPlayPosChangedNT != AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
1248fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen            if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: Not registered or requesting.");
1249fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen            return;
1250fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        }
1251fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen
1252f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        long playPositionMs = getPlayPosition();
1253a06a7e90bac455c4bc440a1e03117dd6ae41a653Marie Janssen        String debugLine = "sendPlayPosNotificationRsp: ";
1254f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1255f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // mNextPosMs is set to -1 when the previous position was invalid
1256f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // so this will be true if the new position is valid & old was invalid.
1257f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // mPlayPositionMs is set to -1 when the new position is invalid,
1258f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // and the old mPrevPosMs is >= 0 so this is true when the new is invalid
1259f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // and the old was valid.
1260a06a7e90bac455c4bc440a1e03117dd6ae41a653Marie Janssen        if (DEBUG) {
1261a06a7e90bac455c4bc440a1e03117dd6ae41a653Marie Janssen            debugLine += "(" + requested + ") " + mPrevPosMs + " <=? " + playPositionMs + " <=? "
1262a06a7e90bac455c4bc440a1e03117dd6ae41a653Marie Janssen                    + mNextPosMs;
1263a06a7e90bac455c4bc440a1e03117dd6ae41a653Marie Janssen            if (isPlayingState(mCurrentPlayState)) debugLine += " Playing";
1264a06a7e90bac455c4bc440a1e03117dd6ae41a653Marie Janssen            debugLine += " State: " + mCurrentPlayState.getState();
1265a06a7e90bac455c4bc440a1e03117dd6ae41a653Marie Janssen        }
1266fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        if (requested || ((mLastReportedPosition != playPositionMs) &&
1267e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                (playPositionMs >= mNextPosMs) || (playPositionMs <= mPrevPosMs))) {
1268e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!requested) mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
1269e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int) playPositionMs);
1270fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen            mLastReportedPosition = playPositionMs;
1271f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            if (playPositionMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
1272f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mNextPosMs = playPositionMs + mPlaybackIntervalMs;
1273f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mPrevPosMs = playPositionMs - mPlaybackIntervalMs;
1274f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            } else {
1275f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mNextPosMs = -1;
1276f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mPrevPosMs = -1;
1277f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            }
1278f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        }
1279f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1280e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.removeMessages(MSG_PLAY_INTERVAL_TIMEOUT);
1281e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (mPlayPosChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM && isPlayingState(mCurrentPlayState)) {
1282e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Message msg = mHandler.obtainMessage(MSG_PLAY_INTERVAL_TIMEOUT);
1283f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            long delay = mPlaybackIntervalMs;
1284f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            if (mNextPosMs != -1) {
1285f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                delay = mNextPosMs - (playPositionMs > 0 ? playPositionMs : 0);
1286f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            }
1287a06a7e90bac455c4bc440a1e03117dd6ae41a653Marie Janssen            if (DEBUG) debugLine += " Timeout " + delay + "ms";
1288f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            mHandler.sendMessageDelayed(msg, delay);
1289f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        }
1290a06a7e90bac455c4bc440a1e03117dd6ae41a653Marie Janssen        if (DEBUG) Log.d(TAG, debugLine);
1291f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    }
1292f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1293f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    /**
129417675906064bb72fdcca75baa56cdf8bb8968d01John Du     * This is called from AudioService. It will return whether this device supports abs volume.
129517675906064bb72fdcca75baa56cdf8bb8968d01John Du     * NOT USED AT THE MOMENT.
129617675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
129717675906064bb72fdcca75baa56cdf8bb8968d01John Du    public boolean isAbsoluteVolumeSupported() {
129817675906064bb72fdcca75baa56cdf8bb8968d01John Du        return ((mFeatures & BTRC_FEAT_ABSOLUTE_VOLUME) != 0);
129917675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
130017675906064bb72fdcca75baa56cdf8bb8968d01John Du
130117675906064bb72fdcca75baa56cdf8bb8968d01John Du    /**
130217675906064bb72fdcca75baa56cdf8bb8968d01John Du     * We get this call from AudioService. This will send a message to our handler object,
130317675906064bb72fdcca75baa56cdf8bb8968d01John Du     * requesting our handler to call setVolumeNative()
130417675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
130517675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void adjustVolume(int direction) {
1306e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_ADJUST_VOLUME, direction, 0);
130717675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
130817675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
130917675906064bb72fdcca75baa56cdf8bb8968d01John Du
131017675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void setAbsoluteVolume(int volume) {
131111798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (volume == mLocalVolume) {
131211798b011c962b602217b479130d413f3b30f19aLiejun Tao            if (DEBUG) Log.v(TAG, "setAbsoluteVolume is setting same index, ignore "+volume);
131311798b011c962b602217b479130d413f3b30f19aLiejun Tao            return;
131411798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
131511798b011c962b602217b479130d413f3b30f19aLiejun Tao
1316e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.removeMessages(MSG_ADJUST_VOLUME);
1317e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_SET_ABSOLUTE_VOLUME, volume, 0);
131817675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
13195c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta    }
13205c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta
132117675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* Called in the native layer as a btrc_callback to return the volume set on the carkit in the
132217675906064bb72fdcca75baa56cdf8bb8968d01John Du     * case when the volume is change locally on the carkit. This notification is not called when
132317675906064bb72fdcca75baa56cdf8bb8968d01John Du     * the volume is changed from the phone.
132417675906064bb72fdcca75baa56cdf8bb8968d01John Du     *
132517675906064bb72fdcca75baa56cdf8bb8968d01John Du     * This method will send a message to our handler to change the local stored volume and notify
132617675906064bb72fdcca75baa56cdf8bb8968d01John Du     * AudioService to update the UI
132717675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
1328e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void volumeChangeRequestFromNative(byte[] address, int volume, int ctype) {
1329e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_VOLUME_CHANGE, volume, ctype);
1330e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1331e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByteArray("BdAddress" , address);
1332e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.setData(data);
1333e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1334e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1335e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1336ce0f15c8598a1e570faf80bbc60e0568d2d20d45Marie Janssen    private void getFolderItemsRequestFromNative(
1337ce0f15c8598a1e570faf80bbc60e0568d2d20d45Marie Janssen            byte[] address, byte scope, long startItem, long endItem, byte numAttr, int[] attrIds) {
1338e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd avrcpCmdobj = new AvrcpCmd();
1339e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd.FolderItemsCmd folderObj = avrcpCmdobj.new FolderItemsCmd(address, scope,
1340e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                startItem, endItem, numAttr, attrIds);
1341e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_FOLDER_ITEMS, 0, 0);
1342e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = folderObj;
1343e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1344e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1345e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1346e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setAddressedPlayerRequestFromNative(byte[] address, int playerId) {
1347e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_SET_ADDR_PLAYER, playerId, 0);
1348e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1349e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1350e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1351e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1352e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setBrowsedPlayerRequestFromNative(byte[] address, int playerId) {
1353e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_SET_BR_PLAYER, playerId, 0);
1354e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1355e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1356e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1357e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1358e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void changePathRequestFromNative(byte[] address, byte direction, byte[] folderUid) {
1359e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1360e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_CHANGE_PATH);
1361e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByteArray("BdAddress" , address);
1362e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByteArray("folderUid" , folderUid);
1363e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByte("direction" , direction);
1364e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.setData(data);
1365e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1366e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1367e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1368e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void getItemAttrRequestFromNative(byte[] address, byte scope, byte[] itemUid, int uidCounter,
1369e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            byte numAttr, int[] attrs) {
1370e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd avrcpCmdobj = new AvrcpCmd();
1371e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd.ItemAttrCmd itemAttr = avrcpCmdobj.new ItemAttrCmd(address, scope,
1372e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                itemUid, uidCounter, numAttr, attrs);
1373e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_ITEM_ATTR);
1374e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = itemAttr;
1375e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1376e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1377e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1378e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void searchRequestFromNative(byte[] address, int charsetId, byte[] searchStr) {
1379e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Search is not supported */
1380303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen        Log.w(TAG, "searchRequestFromNative: search is not supported");
1381e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        searchRspNative(address, AvrcpConstants.RSP_SRCH_NOT_SPRTD, 0, 0);
1382e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1383e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1384e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void playItemRequestFromNative(byte[] address, byte scope, int uidCounter, byte[] uid) {
1385e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1386e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_PLAY_ITEM);
1387e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByteArray("BdAddress" , address);
1388e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByteArray("uid" , uid);
1389e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putInt("uidCounter" , uidCounter);
1390e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByte("scope" , scope);
1391e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.setData(data);
1392e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1393e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1394e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1395e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void addToPlayListRequestFromNative(byte[] address, byte scope, byte[] uid, int uidCounter) {
1396e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* add to NowPlaying not supported */
1397303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen        Log.w(TAG, "addToPlayListRequestFromNative: not supported! scope=" + scope);
1398e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        addToNowPlayingRspNative(address, AvrcpConstants.RSP_INTERNAL_ERR);
1399e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1400e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1401e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void getTotalNumOfItemsRequestFromNative(byte[] address, byte scope) {
1402e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1403e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS);
1404e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.arg1 = scope;
1405e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
140617675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
140717675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
140817675906064bb72fdcca75baa56cdf8bb8968d01John Du
14092e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private void notifyVolumeChanged(int volume) {
14102e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume,
14112e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie                      AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
141217675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
141317675906064bb72fdcca75baa56cdf8bb8968d01John Du
141417675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int convertToAudioStreamVolume(int volume) {
141517675906064bb72fdcca75baa56cdf8bb8968d01John Du        // Rescale volume to match AudioSystem's volume
141611798b011c962b602217b479130d413f3b30f19aLiejun Tao        return (int) Math.floor((double) volume*mAudioStreamMax/AVRCP_MAX_VOL);
141717675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
141817675906064bb72fdcca75baa56cdf8bb8968d01John Du
141917675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int convertToAvrcpVolume(int volume) {
14202e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        return (int) Math.ceil((double) volume*AVRCP_MAX_VOL/mAudioStreamMax);
142117675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
142217675906064bb72fdcca75baa56cdf8bb8968d01John Du
142311798b011c962b602217b479130d413f3b30f19aLiejun Tao    private void blackListCurrentDevice() {
142411798b011c962b602217b479130d413f3b30f19aLiejun Tao        mFeatures &= ~BTRC_FEAT_ABSOLUTE_VOLUME;
142511798b011c962b602217b479130d413f3b30f19aLiejun Tao        mAudioManager.avrcpSupportsAbsoluteVolume(mAddress, isAbsoluteVolumeSupported());
142611798b011c962b602217b479130d413f3b30f19aLiejun Tao
142711798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST,
142811798b011c962b602217b479130d413f3b30f19aLiejun Tao                Context.MODE_PRIVATE);
142911798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences.Editor editor = pref.edit();
143011798b011c962b602217b479130d413f3b30f19aLiejun Tao        editor.putBoolean(mAddress, true);
14317eeb95b6f29a6f55e117e329468168d4bcbec0c8Jack He        editor.apply();
143211798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
143311798b011c962b602217b479130d413f3b30f19aLiejun Tao
143411798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int modifyRcFeatureFromBlacklist(int feature, String address) {
143511798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST,
143611798b011c962b602217b479130d413f3b30f19aLiejun Tao                Context.MODE_PRIVATE);
143711798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (!pref.contains(address)) {
143811798b011c962b602217b479130d413f3b30f19aLiejun Tao            return feature;
143911798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
144011798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (pref.getBoolean(address, false)) {
144111798b011c962b602217b479130d413f3b30f19aLiejun Tao            feature &= ~BTRC_FEAT_ABSOLUTE_VOLUME;
144211798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
144311798b011c962b602217b479130d413f3b30f19aLiejun Tao        return feature;
144411798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
144511798b011c962b602217b479130d413f3b30f19aLiejun Tao
144611798b011c962b602217b479130d413f3b30f19aLiejun Tao    public void resetBlackList(String address) {
144711798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST,
144811798b011c962b602217b479130d413f3b30f19aLiejun Tao                Context.MODE_PRIVATE);
144911798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences.Editor editor = pref.edit();
145011798b011c962b602217b479130d413f3b30f19aLiejun Tao        editor.remove(address);
14517eeb95b6f29a6f55e117e329468168d4bcbec0c8Jack He        editor.apply();
145211798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
145311798b011c962b602217b479130d413f3b30f19aLiejun Tao
1454188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    /**
1455188f205b5f093850d4cc627917a21204be36c56aZhihai Xu     * This is called from A2dpStateMachine to set A2dp audio state.
1456188f205b5f093850d4cc627917a21204be36c56aZhihai Xu     */
1457188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    public void setA2dpAudioState(int state) {
1458e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_SET_A2DP_AUDIO_STATE, state, 0);
1459188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        mHandler.sendMessage(msg);
1460188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
1461188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
14620427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker    private class AvrcpServiceBootReceiver extends BroadcastReceiver {
14630427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        @Override
14640427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        public void onReceive(Context context, Intent intent) {
14650427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker            String action = intent.getAction();
1466eb829bbfa257c84c4f8fa589b54791e3f413b486Ajay Panicker            if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
1467eb829bbfa257c84c4f8fa589b54791e3f413b486Ajay Panicker                if (DEBUG) Log.d(TAG, "User unlocked, initializing player lists");
14680427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker                /* initializing media player's list */
14691111f243441532aefeadf322a9ab9800e330007bAjay Panicker                buildBrowsablePlayerList();
14700427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker            }
14710427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        }
14720427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker    }
14730427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker
1474e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private class AvrcpServiceBroadcastReceiver extends BroadcastReceiver {
1475e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        @Override
1476e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void onReceive(Context context, Intent intent) {
1477e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String action = intent.getAction();
1478e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (DEBUG) Log.d(TAG, "AvrcpServiceBroadcastReceiver-> Action: " + action);
1479e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1480e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
1481e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) {
1482e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1483e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    // a package is being removed, not replaced
1484e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    String packageName = intent.getData().getSchemeSpecificPart();
1485e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    if (packageName != null) {
1486e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        handlePackageModified(packageName, true);
1487e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    }
1488e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
1489e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1490e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else if (action.equals(Intent.ACTION_PACKAGE_ADDED)
1491e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    || action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
1492e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                String packageName = intent.getData().getSchemeSpecificPart();
1493e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.d(TAG,"AvrcpServiceBroadcastReceiver-> packageName: "
1494e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        + packageName);
1495e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (packageName != null) {
1496e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    handlePackageModified(packageName, false);
1497e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
1498e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1499e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1500838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    }
1501838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood
1502e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handlePackageModified(String packageName, boolean removed) {
1503e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "packageName: " + packageName + " removed: " + removed);
1504c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1505e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (removed) {
1506d89304c6be6e1c332008dcbeab08889881064454Marie Janssen            removeMediaPlayerInfo(packageName);
1507e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // old package is removed, updating local browsable player's list
1508e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (isBrowseSupported(packageName)) {
1509e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                removePackageFromBrowseList(packageName);
1510e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1511e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
1512e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // new package has been added.
1513e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (isBrowsableListUpdated(packageName)) {
1514e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                // Rebuilding browsable players list
15151111f243441532aefeadf322a9ab9800e330007bAjay Panicker                buildBrowsablePlayerList();
1516e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1517e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1518e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1519c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1520e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isBrowsableListUpdated(String newPackageName) {
1521e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // getting the browsable media players list from package manager
1522e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Intent intent = new Intent("android.media.browse.MediaBrowserService");
15230427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        List<ResolveInfo> resInfos = mPackageManager.queryIntentServices(intent,
15240427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker                                         PackageManager.MATCH_ALL);
1525e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        for (ResolveInfo resolveInfo : resInfos) {
15263843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            if (resolveInfo.serviceInfo.packageName.equals(newPackageName)) {
15273843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                if (DEBUG)
15283843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                    Log.d(TAG,
15293843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                            "isBrowsableListUpdated: package includes MediaBrowserService, true");
15303843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                return true;
15313843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            }
1532e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1533c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
15343843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        // if list has different size
15353843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        if (resInfos.size() != mBrowsePlayerInfoList.size()) {
15363843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            if (DEBUG) Log.d(TAG, "isBrowsableListUpdated: browsable list size mismatch, true");
15373843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            return true;
1538e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
15393843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen
15403843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        Log.d(TAG, "isBrowsableListUpdated: false");
15413843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        return false;
1542e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1543e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
15448cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private void removePackageFromBrowseList(String packageName) {
1545e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "removePackageFromBrowseList: " + packageName);
15468cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mBrowsePlayerInfoList) {
15478cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            int browseInfoID = getBrowseId(packageName);
15488cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (browseInfoID != -1) {
15498cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                mBrowsePlayerInfoList.remove(browseInfoID);
15508cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
1551e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1552e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1553e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1554e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
1555e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * utility function to get the browse player index from global browsable
1556e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * list. It may return -1 if specified package name is not in the list.
1557e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
15588cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private int getBrowseId(String packageName) {
1559e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean response = false;
1560e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        int browseInfoID = 0;
15618cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mBrowsePlayerInfoList) {
15628cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            for (BrowsePlayerInfo info : mBrowsePlayerInfoList) {
15638cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                if (info.packageName.equals(packageName)) {
15648cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    response = true;
15658cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    break;
15668cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                }
15678cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                browseInfoID++;
1568e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1569e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1570e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1571e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!response) {
1572e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            browseInfoID = -1;
1573e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1574e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1575e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "getBrowseId for packageName: " + packageName +
1576e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                " , browseInfoID: " + browseInfoID);
1577e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return browseInfoID;
1578e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1579e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1580e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setAddressedPlayer(byte[] bdaddr, int selectedId) {
158107331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen        String functionTag = "setAddressedPlayer(" + selectedId + "): ";
1582e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
15838cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
15848cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (mMediaPlayerInfoList.isEmpty()) {
158507331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                Log.w(TAG, functionTag + "no players, send no available players");
158607331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_AVBL_PLAY);
158707331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                return;
158807331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen            }
158907331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen            if (!mMediaPlayerInfoList.containsKey(selectedId)) {
159007331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                Log.w(TAG, functionTag + "invalid id, sending response back ");
159107331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_INV_PLAYER);
159207331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                return;
159307331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen            }
159407331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen
159507331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen            if (isPlayerAlreadyAddressed(selectedId)) {
15968cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                MediaPlayerInfo info = getAddressedPlayerInfo();
159707331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                Log.i(TAG, functionTag + "player already addressed: " + info);
159807331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR);
159907331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                return;
160007331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen            }
160107331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen            // register new Media Controller Callback and update the current IDs
160207331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen            if (!updateCurrentController(selectedId, mCurrBrowsePlayerID)) {
160307331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                Log.e(TAG, functionTag + "updateCurrentController failed!");
160407331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR);
160507331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                return;
160607331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen            }
160707331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen            // If we don't have a controller, try to launch the player
160807331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen            MediaPlayerInfo info = getAddressedPlayerInfo();
160907331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen            if (info.getMediaController() == null) {
161007331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                Intent launch = mPackageManager.getLaunchIntentForPackage(info.getPackageName());
161107331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                Log.i(TAG, functionTag + "launching player " + launch);
161207331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen                mContext.startActivity(launch);
1613e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1614e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
161507331cbd302f65c1cc72be3f7f20004127cdd1fbMarie Janssen        setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR);
1616e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1617e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1618e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setBrowsedPlayer(byte[] bdaddr, int selectedId) {
1619e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        int status = AvrcpConstants.RSP_NO_ERROR;
1620e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1621e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // checking for error cases
16228cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        if (mMediaPlayerInfoList.isEmpty()) {
1623e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            status = AvrcpConstants.RSP_NO_AVBL_PLAY;
1624cb63ca088b6657757fdf6bb8f3cdb58aaee9e4c3Marie Janssen            Log.w(TAG, "setBrowsedPlayer: No available players! ");
1625e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
1626cb63ca088b6657757fdf6bb8f3cdb58aaee9e4c3Marie Janssen            // Workaround for broken controllers selecting ID 0
1627cb63ca088b6657757fdf6bb8f3cdb58aaee9e4c3Marie Janssen            // Seen at least on Ford, Chevrolet MyLink
1628cb63ca088b6657757fdf6bb8f3cdb58aaee9e4c3Marie Janssen            if (selectedId == 0) {
1629cb63ca088b6657757fdf6bb8f3cdb58aaee9e4c3Marie Janssen                Log.w(TAG, "setBrowsedPlayer: workaround invalid id 0");
1630cb63ca088b6657757fdf6bb8f3cdb58aaee9e4c3Marie Janssen                selectedId = mCurrAddrPlayerID;
1631cb63ca088b6657757fdf6bb8f3cdb58aaee9e4c3Marie Janssen            }
1632cb63ca088b6657757fdf6bb8f3cdb58aaee9e4c3Marie Janssen
1633e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // update current browse player id and start browsing service
1634e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            updateNewIds(mCurrAddrPlayerID, selectedId);
1635e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String browsedPackage = getPackageName(selectedId);
1636e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1637e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!isPackageNameValid(browsedPackage)) {
1638e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.w(TAG, " Invalid package for id:" + mCurrBrowsePlayerID);
1639e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                status = AvrcpConstants.RSP_INV_PLAYER;
1640e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else if (!isBrowseSupported(browsedPackage)) {
1641e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.w(TAG, "Browse unsupported for id:" + mCurrBrowsePlayerID
1642e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        + ", packagename : " + browsedPackage);
1643e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                status = AvrcpConstants.RSP_PLAY_NOT_BROW;
1644e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else if (!startBrowseService(bdaddr, browsedPackage)) {
1645e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "service cannot be started for browse player id:" + mCurrBrowsePlayerID
1646e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        + ", packagename : " + browsedPackage);
1647e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                status = AvrcpConstants.RSP_INTERNAL_ERR;
1648e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1649e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1650e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1651e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (status != AvrcpConstants.RSP_NO_ERROR) {
1652e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            setBrowsedPlayerRspNative(bdaddr, status, (byte) 0x00, 0, null);
1653e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1654e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1655e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "setBrowsedPlayer for selectedId: " + selectedId +
1656e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                " , status: " + status);
1657e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1658e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1659bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    private MediaSessionManager.OnActiveSessionsChangedListener mActiveSessionListener =
1660bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            new MediaSessionManager.OnActiveSessionsChangedListener() {
1661e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1662bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                @Override
1663bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                public void onActiveSessionsChanged(
1664bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                        List<android.media.session.MediaController> newControllers) {
16657c12b34b98d717fdfe68f5e8c94b7a01ef372f8bMarie Janssen                    Set<String> updatedPackages = new HashSet<String>();
1666bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    // Update the current players
1667bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    for (android.media.session.MediaController controller : newControllers) {
16687c12b34b98d717fdfe68f5e8c94b7a01ef372f8bMarie Janssen                        String packageName = controller.getPackageName();
16697c12b34b98d717fdfe68f5e8c94b7a01ef372f8bMarie Janssen                        if (DEBUG) Log.v(TAG, "ActiveSession: " + MediaController.wrap(controller));
16707c12b34b98d717fdfe68f5e8c94b7a01ef372f8bMarie Janssen                        // Only use the first (highest priority) controller from each package
16717c12b34b98d717fdfe68f5e8c94b7a01ef372f8bMarie Janssen                        if (updatedPackages.contains(packageName)) continue;
1672bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                        addMediaPlayerController(controller);
16737c12b34b98d717fdfe68f5e8c94b7a01ef372f8bMarie Janssen                        updatedPackages.add(packageName);
1674351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                    }
1675d996f17ea97b2c592338bcfbc93056d0224da1cdAjay Panicker
167685ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                    if (newControllers.size() > 0 && getAddressedPlayerInfo() == null) {
167785ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                        if (DEBUG)
167885ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                            Log.v(TAG, "No addressed player but active sessions, taking first.");
167985ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                        setAddressedMediaSessionPackage(newControllers.get(0).getPackageName());
1680351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                    }
168167c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                    updateCurrentMediaState();
1682e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
1683bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            };
1684bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
16850c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen    private void setAddressedMediaSessionPackage(@Nullable String packageName) {
16861107f9516bf8866640247044deb9f780bb89e55cMarie Janssen        if (packageName == null) {
16871107f9516bf8866640247044deb9f780bb89e55cMarie Janssen            // Should only happen when there's no media players, reset to no available player.
16881107f9516bf8866640247044deb9f780bb89e55cMarie Janssen            updateCurrentController(0, mCurrBrowsePlayerID);
16891107f9516bf8866640247044deb9f780bb89e55cMarie Janssen            return;
16901107f9516bf8866640247044deb9f780bb89e55cMarie Janssen        }
1691c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker        if (packageName.equals("com.android.server.telecom")) {
1692c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker            Log.d(TAG, "Ignore addressed media session change to telecom");
1693c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker            return;
1694c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker        }
1695bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        // No change.
1696bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        if (getPackageName(mCurrAddrPlayerID).equals(packageName)) return;
16970c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        if (DEBUG) Log.v(TAG, "Changing addressed media session to " + packageName);
1698bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        // If the player doesn't exist, we need to add it.
1699bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        if (getMediaPlayerInfo(packageName) == null) {
1700bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            addMediaPlayerPackage(packageName);
170167c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            updateCurrentMediaState();
1702bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        }
17038cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
17048cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
17058cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                if (entry.getValue().getPackageName().equals(packageName)) {
17068cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    int newAddrID = entry.getKey();
17078cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    if (DEBUG) Log.v(TAG, "Set addressed #" + newAddrID + " " + entry.getValue());
17088cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    updateCurrentController(newAddrID, mCurrBrowsePlayerID);
170967c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker                    updateCurrentMediaState();
17108cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    return;
17118cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                }
1712e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1713e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1714bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        // We shouldn't ever get here.
1715bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        Log.e(TAG, "Player info for " + packageName + " doesn't exist!");
1716bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    }
1717e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1718bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    private void setActiveMediaSession(MediaSession.Token token) {
1719bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        android.media.session.MediaController activeController =
1720bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                new android.media.session.MediaController(mContext, token);
1721c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker        if (activeController.getPackageName().equals("com.android.server.telecom")) {
1722c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker            Log.d(TAG, "Ignore active media session change to telecom");
1723c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker            return;
1724c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker        }
1725bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        if (DEBUG) Log.v(TAG, "Set active media session " + activeController.getPackageName());
1726bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        addMediaPlayerController(activeController);
1727bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        setAddressedMediaSessionPackage(activeController.getPackageName());
1728bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    }
1729e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1730e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean startBrowseService(byte[] bdaddr, String packageName) {
1731e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean status = true;
1732e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1733e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* creating new instance for Browse Media Player */
1734e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browseService = getBrowseServiceName(packageName);
1735e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!browseService.isEmpty()) {
1736e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).setBrowsed(
1737e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    packageName, browseService);
1738e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
1739e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Log.w(TAG, "No Browser service available for " + packageName);
1740e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            status = false;
1741e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1742e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1743e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "startBrowseService for packageName: " + packageName +
1744e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                ", status = " + status);
1745e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return status;
1746e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1747e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
17488cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private String getBrowseServiceName(String packageName) {
1749e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browseServiceName = "";
1750e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1751e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // getting the browse service name from browse player info
17528cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mBrowsePlayerInfoList) {
17538cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            int browseInfoID = getBrowseId(packageName);
17548cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (browseInfoID != -1) {
17558cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                browseServiceName = mBrowsePlayerInfoList.get(browseInfoID).serviceClass;
17568cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
1757e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1758e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1759e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "getBrowseServiceName for packageName: " + packageName +
1760e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                ", browseServiceName = " + browseServiceName);
1761e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return browseServiceName;
1762e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1763e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
17641111f243441532aefeadf322a9ab9800e330007bAjay Panicker    void buildBrowsablePlayerList() {
17651111f243441532aefeadf322a9ab9800e330007bAjay Panicker        synchronized (mBrowsePlayerInfoList) {
17663843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            mBrowsePlayerInfoList.clear();
17673843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            Intent intent = new Intent(android.service.media.MediaBrowserService.SERVICE_INTERFACE);
17681111f243441532aefeadf322a9ab9800e330007bAjay Panicker            List<ResolveInfo> playerList =
17691111f243441532aefeadf322a9ab9800e330007bAjay Panicker                    mPackageManager.queryIntentServices(intent, PackageManager.MATCH_ALL);
17701111f243441532aefeadf322a9ab9800e330007bAjay Panicker
17711111f243441532aefeadf322a9ab9800e330007bAjay Panicker            for (ResolveInfo info : playerList) {
17721111f243441532aefeadf322a9ab9800e330007bAjay Panicker                String displayableName = info.loadLabel(mPackageManager).toString();
17731111f243441532aefeadf322a9ab9800e330007bAjay Panicker                String serviceName = info.serviceInfo.name;
17741111f243441532aefeadf322a9ab9800e330007bAjay Panicker                String packageName = info.serviceInfo.packageName;
17751111f243441532aefeadf322a9ab9800e330007bAjay Panicker
17761111f243441532aefeadf322a9ab9800e330007bAjay Panicker                if (DEBUG) Log.d(TAG, "Adding " + serviceName + " to list of browsable players");
17771111f243441532aefeadf322a9ab9800e330007bAjay Panicker                BrowsePlayerInfo currentPlayer =
17781111f243441532aefeadf322a9ab9800e330007bAjay Panicker                        new BrowsePlayerInfo(packageName, displayableName, serviceName);
17791111f243441532aefeadf322a9ab9800e330007bAjay Panicker                mBrowsePlayerInfoList.add(currentPlayer);
17801111f243441532aefeadf322a9ab9800e330007bAjay Panicker                MediaPlayerInfo playerInfo = getMediaPlayerInfo(packageName);
17811111f243441532aefeadf322a9ab9800e330007bAjay Panicker                MediaController controller =
17821111f243441532aefeadf322a9ab9800e330007bAjay Panicker                        (playerInfo == null) ? null : playerInfo.getMediaController();
17831111f243441532aefeadf322a9ab9800e330007bAjay Panicker                // Refresh the media player entry so it notices we can browse
17841111f243441532aefeadf322a9ab9800e330007bAjay Panicker                if (controller != null) {
17851111f243441532aefeadf322a9ab9800e330007bAjay Panicker                    addMediaPlayerController(controller.getWrappedInstance());
17861111f243441532aefeadf322a9ab9800e330007bAjay Panicker                } else {
17871111f243441532aefeadf322a9ab9800e330007bAjay Panicker                    addMediaPlayerPackage(packageName);
1788351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                }
17893843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            }
179067c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            updateCurrentMediaState();
1791e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1792e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1793e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1794bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    /* Initializes list of media players identified from session manager active sessions */
17958cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private void initMediaPlayersList() {
17968cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
17978cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            // Clearing old browsable player's list
17988cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            mMediaPlayerInfoList.clear();
1799bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
18008cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (mMediaSessionManager == null) {
18018cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                if (DEBUG) Log.w(TAG, "initMediaPlayersList: no media session manager!");
18028cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                return;
18038cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
1804bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
18058cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            List<android.media.session.MediaController> controllers =
18068cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    mMediaSessionManager.getActiveSessions(null);
18078cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (DEBUG)
18088cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                Log.v(TAG, "initMediaPlayerInfoList: " + controllers.size() + " controllers");
18098cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            /* Initializing all media players */
18108cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            for (android.media.session.MediaController controller : controllers) {
18118cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                addMediaPlayerController(controller);
18128cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
181385ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen
181467c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker            updateCurrentMediaState();
1815e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
18168cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (mMediaPlayerInfoList.size() > 0) {
18178cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                // Set the first one as the Addressed Player
18188cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                updateCurrentController(mMediaPlayerInfoList.firstKey(), -1);
18198cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
1820e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1821e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1822e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1823351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    private List<android.media.session.MediaController> getMediaControllers() {
1824351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        List<android.media.session.MediaController> controllers =
1825351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                new ArrayList<android.media.session.MediaController>();
18268cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
18278cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            for (MediaPlayerInfo info : mMediaPlayerInfoList.values()) {
1828c721162e8198dbc1b4b3ec9d87beb083ba704307Marie Janssen                MediaController controller = info.getMediaController();
1829c721162e8198dbc1b4b3ec9d87beb083ba704307Marie Janssen                if (controller != null) {
1830c721162e8198dbc1b4b3ec9d87beb083ba704307Marie Janssen                    controllers.add(controller.getWrappedInstance());
18318cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                }
1832351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen            }
1833351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        }
1834351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        return controllers;
1835351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    }
1836351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen
1837351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    /** Add (or update) a player to the media player list without a controller */
18388cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private boolean addMediaPlayerPackage(String packageName) {
1839351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        MediaPlayerInfo info = new MediaPlayerInfo(null, AvrcpConstants.PLAYER_TYPE_AUDIO,
1840b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                AvrcpConstants.PLAYER_SUBTYPE_NONE, PLAYSTATUS_STOPPED,
18410b6cad4a9f1ab18f6b3627ce7cf6316466cdb95aMarie Janssen                getFeatureBitMask(packageName), packageName, getAppLabel(packageName));
1842bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        return addMediaPlayerInfo(info);
1843351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    }
1844351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen
1845351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    /** Add (or update) a player to the media player list given an active controller */
18468cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private boolean addMediaPlayerController(android.media.session.MediaController controller) {
1847351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        String packageName = controller.getPackageName();
1848351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        MediaPlayerInfo info = new MediaPlayerInfo(MediaController.wrap(controller),
1849351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                AvrcpConstants.PLAYER_TYPE_AUDIO, AvrcpConstants.PLAYER_SUBTYPE_NONE,
1850b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                getBluetoothPlayState(controller.getPlaybackState()),
1851b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                getFeatureBitMask(packageName), controller.getPackageName(),
1852b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen                getAppLabel(packageName));
1853bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        return addMediaPlayerInfo(info);
1854351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    }
1855351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen
1856bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    /** Add or update a player to the media player list given the MediaPlayerInfo object.
1857bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen     *  @return true if an item was updated, false if it was added instead
1858bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen     */
18598cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private boolean addMediaPlayerInfo(MediaPlayerInfo info) {
18600b6cad4a9f1ab18f6b3627ce7cf6316466cdb95aMarie Janssen        int updateId = -1;
1861bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        boolean updated = false;
186285ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen        boolean currentRemoved = false;
1863c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker        if (info.getPackageName().equals("com.android.server.telecom")) {
1864c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker            Log.d(TAG, "Skip adding telecom to the media player info list");
1865c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker            return updated;
1866c833de68eb3f5a82db6e83166e18504e83e5d035Ajay Panicker        }
18678cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
18688cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
186985ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                MediaPlayerInfo current = entry.getValue();
187085ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                int id = entry.getKey();
187185ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                if (info.getPackageName().equals(current.getPackageName())) {
187285ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                    if (!current.equalView(info)) {
187385ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                        // If we would present a different player, make it a new player
187485ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                        // so that controllers know whether a player is browsable or not.
187585ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                        mMediaPlayerInfoList.remove(id);
187685ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                        currentRemoved = (mCurrAddrPlayerID == id);
187785ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                        break;
187885ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                    }
187985ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                    updateId = id;
18808cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    updated = true;
18818cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    break;
18828cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                }
18830b6cad4a9f1ab18f6b3627ce7cf6316466cdb95aMarie Janssen            }
18848cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (updateId == -1) {
18858cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                // New player
18868cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                mLastUsedPlayerID++;
18878cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                updateId = mLastUsedPlayerID;
188885ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                mAvailablePlayerViewChanged = true;
18898cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
18908cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            mMediaPlayerInfoList.put(updateId, info);
18910704743e3d020c050b7eba86f79656bb3dbd9c18Jack He        }
18920704743e3d020c050b7eba86f79656bb3dbd9c18Jack He        if (DEBUG) Log.d(TAG, (updated ? "update #" : "add #") + updateId + ":" + info.toString());
18930704743e3d020c050b7eba86f79656bb3dbd9c18Jack He        if (currentRemoved || updateId == mCurrAddrPlayerID) {
18940704743e3d020c050b7eba86f79656bb3dbd9c18Jack He            updateCurrentController(updateId, mCurrBrowsePlayerID);
18950b6cad4a9f1ab18f6b3627ce7cf6316466cdb95aMarie Janssen        }
1896bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        return updated;
1897351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    }
1898351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen
1899351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    /** Remove all players related to |packageName| from the media player info list */
19008cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private MediaPlayerInfo removeMediaPlayerInfo(String packageName) {
19018cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
19028cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            int removeKey = -1;
19038cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
19048cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                if (entry.getValue().getPackageName().equals(packageName)) {
19058cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    removeKey = entry.getKey();
19068cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    break;
19078cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                }
19088cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
19098cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (removeKey != -1) {
1910d89304c6be6e1c332008dcbeab08889881064454Marie Janssen                if (DEBUG)
1911d89304c6be6e1c332008dcbeab08889881064454Marie Janssen                    Log.d(TAG, "remove #" + removeKey + ":" + mMediaPlayerInfoList.get(removeKey));
191285ff6903243d244d4342f390bb40aa99097a9a7cMarie Janssen                mAvailablePlayerViewChanged = true;
19138cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                return mMediaPlayerInfoList.remove(removeKey);
1914351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen            }
19150b6cad4a9f1ab18f6b3627ce7cf6316466cdb95aMarie Janssen
19168cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            return null;
19178cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        }
1918351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    }
1919351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen
1920d89304c6be6e1c332008dcbeab08889881064454Marie Janssen    /** Remove the controller referenced by |controller| from any player in the list */
1921214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen    private void removeMediaController(@Nullable android.media.session.MediaController controller) {
1922214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen        if (controller == null) return;
1923d89304c6be6e1c332008dcbeab08889881064454Marie Janssen        synchronized (mMediaPlayerInfoList) {
1924214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
1925214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                MediaPlayerInfo info = entry.getValue();
1926c721162e8198dbc1b4b3ec9d87beb083ba704307Marie Janssen                MediaController c = info.getMediaController();
1927214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                if (c != null && c.equals(controller)) {
1928214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                    info.setMediaController(null);
1929214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                    if (entry.getKey() == mCurrAddrPlayerID) {
1930214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                        updateCurrentController(mCurrAddrPlayerID, mCurrBrowsePlayerID);
1931214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                    }
1932214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                }
1933d89304c6be6e1c332008dcbeab08889881064454Marie Janssen            }
1934d89304c6be6e1c332008dcbeab08889881064454Marie Janssen        }
1935d89304c6be6e1c332008dcbeab08889881064454Marie Janssen    }
1936d89304c6be6e1c332008dcbeab08889881064454Marie Janssen
1937e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
1938e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * utility function to get the playback state of any media player through
1939e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * media controller APIs.
1940e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
1941b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    private byte getBluetoothPlayState(PlaybackState pbState) {
1942b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        if (pbState == null) {
1943b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen            Log.w(TAG, "playState object null, sending STOPPED");
1944b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen            return PLAYSTATUS_STOPPED;
1945e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1946e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1947b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen        switch (pbState.getState()) {
1948e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_PLAYING:
1949e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_PLAYING;
1950e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1951093a2e4d9aeaecb0d51d8b7c74b4466d368c31cfAjay Panicker            case PlaybackState.STATE_BUFFERING:
1952e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_STOPPED:
1953e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_NONE:
1954e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_CONNECTING:
1955e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_STOPPED;
1956e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1957e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_PAUSED:
1958e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_PAUSED;
1959e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1960e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_FAST_FORWARDING:
1961e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_SKIPPING_TO_NEXT:
1962e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM:
1963e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_FWD_SEEK;
1964e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1965e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_REWINDING:
1966e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
1967e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_REV_SEEK;
1968e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1969e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_ERROR:
1970e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            default:
1971e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_ERROR;
1972e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1973e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1974e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1975e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
1976e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * utility function to get the feature bit mask of any media player through
1977e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * package name
1978e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
1979e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private short[] getFeatureBitMask(String packageName) {
1980e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1981e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ArrayList<Short> featureBitsList = new ArrayList<Short>();
1982e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1983e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* adding default feature bits */
1984e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_PLAY_BIT_NO);
1985e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_STOP_BIT_NO);
1986e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_PAUSE_BIT_NO);
1987e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_REWIND_BIT_NO);
1988e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_FAST_FWD_BIT_NO);
1989e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_FORWARD_BIT_NO);
1990e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_BACKWARD_BIT_NO);
1991e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_ADV_CTRL_BIT_NO);
1992e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1993e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Add/Modify browse player supported features. */
1994e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (isBrowseSupported(packageName)) {
1995e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_BROWSE_BIT_NO);
1996e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_UID_UNIQUE_BIT_NO);
1997e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_NOW_PLAY_BIT_NO);
1998e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_GET_NUM_OF_ITEMS_BIT_NO);
1999e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2000e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2001e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // converting arraylist to array for response
2002e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        short[] featureBitsArray = new short[featureBitsList.size()];
2003e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2004e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        for (int i = 0; i < featureBitsList.size(); i++) {
2005e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsArray[i] = featureBitsList.get(i).shortValue();
2006e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2007e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2008e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return featureBitsArray;
2009e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2010e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2011e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /**
2012e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * Checks the Package name if it supports Browsing or not.
2013e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     *
2014e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * @param packageName - name of the package to get the Id.
2015e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * @return true if it supports browsing, else false.
2016e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
20178cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private boolean isBrowseSupported(String packageName) {
20188cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mBrowsePlayerInfoList) {
20198cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            /* check if Browsable Player's list contains this package name */
20208cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            for (BrowsePlayerInfo info : mBrowsePlayerInfoList) {
20218cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                if (info.packageName.equals(packageName)) {
20228cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    if (DEBUG) Log.v(TAG, "isBrowseSupported for " + packageName + ": true");
20238cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    return true;
20248cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                }
2025e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2026e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2027e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
20280b6cad4a9f1ab18f6b3627ce7cf6316466cdb95aMarie Janssen        if (DEBUG) Log.v(TAG, "isBrowseSupported for " + packageName + ": false");
20291b70ec148be773651d5ad00e3ce0d28b3a63306dAjay Panicker        return false;
2030e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2031e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2032e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private String getPackageName(int id) {
20338cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        MediaPlayerInfo player = null;
20348cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
20358cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            player = mMediaPlayerInfoList.getOrDefault(id, null);
20368cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        }
2037e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2038351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        if (player == null) {
2039351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen            Log.w(TAG, "No package name for player (" + id + " not valid)");
2040351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen            return "";
2041e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2042351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen
2043351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        String packageName = player.getPackageName();
2044351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        if (DEBUG) Log.v(TAG, "Player " + id + " package: " + packageName);
2045e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return packageName;
2046e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2047e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2048e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* from the global object, getting the current browsed player's package name */
2049e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private String getCurrentBrowsedPlayer(byte[] bdaddr) {
2050e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browsedPlayerPackage = "";
2051e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2052e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Map<String, BrowsedMediaPlayer> connList = mAvrcpBrowseManager.getConnList();
2053e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String bdaddrStr = new String(bdaddr);
2054e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if(connList.containsKey(bdaddrStr)){
2055e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            browsedPlayerPackage = connList.get(bdaddrStr).getPackageName();
2056e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2057e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.v(TAG, "getCurrentBrowsedPlayerPackage: " + browsedPlayerPackage);
2058e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return browsedPlayerPackage;
2059e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2060e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2061351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen    /* Returns the MediaPlayerInfo for the currently addressed media player */
20628cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private MediaPlayerInfo getAddressedPlayerInfo() {
20638cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
20648cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            return mMediaPlayerInfoList.getOrDefault(mCurrAddrPlayerID, null);
20658cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        }
2066e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2067e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2068e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
2069e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * Utility function to get the Media player info from package name returns
2070e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * null if package name not found in media players list
2071e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
20728cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private MediaPlayerInfo getMediaPlayerInfo(String packageName) {
20738cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
20748cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (mMediaPlayerInfoList.isEmpty()) {
20758cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                if (DEBUG) Log.v(TAG, "getMediaPlayerInfo: Media players list empty");
20768cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                return null;
20778cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
2078351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen
20798cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            for (MediaPlayerInfo info : mMediaPlayerInfoList.values()) {
20808cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                if (packageName.equals(info.getPackageName())) {
20818cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    if (DEBUG) Log.v(TAG, "getMediaPlayerInfo: Found " + packageName);
20828cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    return info;
20838cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                }
2084e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
20858cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (DEBUG) Log.w(TAG, "getMediaPlayerInfo: " + packageName + " not found");
20868cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            return null;
2087e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2088e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2089e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2090e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* prepare media list & return the media player list response object */
20918cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private MediaPlayerListRsp prepareMediaPlayerRspObj() {
20928cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
209382cfeee4ed9139eeb55e6823d9b721ba17db8b25Ajay Panicker            // TODO(apanicke): This hack will go away as soon as a developer
209482cfeee4ed9139eeb55e6823d9b721ba17db8b25Ajay Panicker            // option to enable or disable player selection is created. Right
209582cfeee4ed9139eeb55e6823d9b721ba17db8b25Ajay Panicker            // now this is needed to fix BMW i3 carkits and any other carkits
209682cfeee4ed9139eeb55e6823d9b721ba17db8b25Ajay Panicker            // that might try to connect to a player that isnt the current
209782cfeee4ed9139eeb55e6823d9b721ba17db8b25Ajay Panicker            // player based on this list
209882cfeee4ed9139eeb55e6823d9b721ba17db8b25Ajay Panicker            int numPlayers = 1;
20998cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen
21008cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            int[] playerIds = new int[numPlayers];
21018cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            byte[] playerTypes = new byte[numPlayers];
21028cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            int[] playerSubTypes = new int[numPlayers];
21038cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            String[] displayableNameArray = new String[numPlayers];
21048cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            byte[] playStatusValues = new byte[numPlayers];
21058cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            short[] featureBitMaskValues =
21068cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    new short[numPlayers * AvrcpConstants.AVRC_FEATURE_MASK_SIZE];
21078cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen
2108f73db9bf71badd648320cac0074169e009562d77Ajay Panicker            // Reserve the first spot for the currently addressed player if
2109f73db9bf71badd648320cac0074169e009562d77Ajay Panicker            // we have one
2110f73db9bf71badd648320cac0074169e009562d77Ajay Panicker            int players = mMediaPlayerInfoList.containsKey(mCurrAddrPlayerID) ? 1 : 0;
21118cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
2112cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                int idx = players;
211382cfeee4ed9139eeb55e6823d9b721ba17db8b25Ajay Panicker                if (entry.getKey() == mCurrAddrPlayerID)
211482cfeee4ed9139eeb55e6823d9b721ba17db8b25Ajay Panicker                    idx = 0;
211582cfeee4ed9139eeb55e6823d9b721ba17db8b25Ajay Panicker                else
211682cfeee4ed9139eeb55e6823d9b721ba17db8b25Ajay Panicker                    continue; // TODO(apanicke): Remove, see above note
21178cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                MediaPlayerInfo info = entry.getValue();
2118cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                playerIds[idx] = entry.getKey();
2119cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                playerTypes[idx] = info.getMajorType();
2120cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                playerSubTypes[idx] = info.getSubType();
2121cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                displayableNameArray[idx] = info.getDisplayableName();
2122cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                playStatusValues[idx] = info.getPlayStatus();
21238cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen
21248cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                short[] featureBits = info.getFeatureBitMask();
21258cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                for (int numBit = 0; numBit < featureBits.length; numBit++) {
21268cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    /* gives which octet this belongs to */
21278cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    byte octet = (byte) (featureBits[numBit] / 8);
21288cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    /* gives the bit position within the octet */
21298cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    byte bit = (byte) (featureBits[numBit] % 8);
2130cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                    featureBitMaskValues[(idx * AvrcpConstants.AVRC_FEATURE_MASK_SIZE) + octet] |=
2131cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                            (1 << bit);
21328cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                }
2133e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
21348cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                /* printLogs */
21358cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                if (DEBUG) {
2136cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                    Log.d(TAG, "Player " + playerIds[idx] + ": " + displayableNameArray[idx]
2137cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                                    + " type: " + playerTypes[idx] + ", " + playerSubTypes[idx]
2138cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                                    + " status: " + playStatusValues[idx]);
21398cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                }
2140e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2141cc75e0ce509baa8e9cd27c38327c786b46b164acAjay Panicker                if (idx != 0) players++;
21428cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
2143e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
21448cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (DEBUG) Log.d(TAG, "prepareMediaPlayerRspObj: numPlayers = " + numPlayers);
2145e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
21468cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            return new MediaPlayerListRsp(AvrcpConstants.RSP_NO_ERROR, sUIDCounter, numPlayers,
21478cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    AvrcpConstants.BTRC_ITEM_PLAYER, playerIds, playerTypes, playerSubTypes,
21488cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                    playStatusValues, featureBitMaskValues, displayableNameArray);
21498cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        }
2150e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2151e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2152e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     /* build media player list and send it to remote. */
2153e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handleMediaPlayerListRsp(AvrcpCmd.FolderItemsCmd folderObj) {
21548cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        MediaPlayerListRsp rspObj = null;
21558cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
21568cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            int numPlayers = mMediaPlayerInfoList.size();
21578cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (numPlayers == 0) {
21588cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                mediaPlayerListRspNative(folderObj.mAddress, AvrcpConstants.RSP_NO_AVBL_PLAY,
21598cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                        (short) 0, (byte) 0, 0, null, null, null, null, null, null);
21608cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                return;
21618cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
21628cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (folderObj.mStartItem >= numPlayers) {
21638cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                Log.i(TAG, "handleMediaPlayerListRsp: start = " + folderObj.mStartItem
21648cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                                + " > num of items = " + numPlayers);
21658cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                mediaPlayerListRspNative(folderObj.mAddress, AvrcpConstants.RSP_INV_RANGE,
21668cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                        (short) 0, (byte) 0, 0, null, null, null, null, null, null);
21678cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                return;
21688cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
21698cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            rspObj = prepareMediaPlayerRspObj();
2170e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
21718cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        if (DEBUG) Log.d(TAG, "handleMediaPlayerListRsp: sending " + rspObj.mNumItems + " players");
2172351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        mediaPlayerListRspNative(folderObj.mAddress, rspObj.mStatus, rspObj.mUIDCounter,
2173351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                rspObj.itemType, rspObj.mNumItems, rspObj.mPlayerIds, rspObj.mPlayerTypes,
2174351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                rspObj.mPlayerSubTypes, rspObj.mPlayStatusValues, rspObj.mFeatureBitMaskValues,
2175351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                rspObj.mPlayerNameList);
2176e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2177e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2178e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* unregister to the old controller, update new IDs and register to the new controller */
2179e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean updateCurrentController(int addrId, int browseId) {
2180e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean registerRsp = true;
2181e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2182e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        updateNewIds(addrId, browseId);
2183e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2184351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        MediaController newController = null;
2185351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        MediaPlayerInfo info = getAddressedPlayerInfo();
21860c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        if (info != null) newController = info.getMediaController();
2187351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen
2188351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        if (DEBUG)
2189351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen            Log.d(TAG, "updateCurrentController: " + mMediaController + " to " + newController);
219086582543b9cd70a617e84c049c03b466653e9641Marie Janssen        synchronized (this) {
219186582543b9cd70a617e84c049c03b466653e9641Marie Janssen            if (mMediaController == null || (!mMediaController.equals(newController))) {
2192214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                if (mMediaController != null) {
2193214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                    mMediaController.unregisterCallback(mMediaControllerCb);
2194214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                }
2195214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                mMediaController = newController;
2196214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                if (mMediaController != null) {
2197214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                    mMediaController.registerCallback(mMediaControllerCb, mHandler);
2198214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                } else {
2199214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                    registerRsp = false;
2200214b7f0b959e2fb3474d43f99136c83e4e11c843Marie Janssen                }
2201351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen            }
2202e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
220367c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker        updateCurrentMediaState();
2204351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        return registerRsp;
2205e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2206e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2207e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Handle getfolderitems for scope = VFS, Search, NowPlayingList */
2208e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handleGetFolderItemBrowseResponse(AvrcpCmd.FolderItemsCmd folderObj, byte[] bdaddr) {
2209e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        int status = AvrcpConstants.RSP_NO_ERROR;
2210e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2211e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Browsed player is already set */
2212bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        if (folderObj.mScope == AvrcpConstants.BTRC_SCOPE_FILE_SYSTEM) {
2213bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) == null) {
2214bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                Log.e(TAG, "handleGetFolderItemBrowseResponse: no browsed player set for "
2215bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                                + Utils.getAddressStringFromByte(bdaddr));
2216bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                getFolderItemsRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR, (short) 0,
2217bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                        (byte) 0x00, 0, null, null, null, null, null, null, null, null);
2218bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return;
2219bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            }
2220bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).getFolderItemsVFS(folderObj);
2221bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            return;
2222e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2223bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        if (folderObj.mScope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
2224bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            mAddressedMediaPlayer.getFolderItemsNowPlaying(bdaddr, folderObj, mMediaController);
2225bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            return;
2226e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2227e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2228bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        /* invalid scope */
2229bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        Log.e(TAG, "handleGetFolderItemBrowseResponse: unknown scope " + folderObj.mScope);
2230bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        getFolderItemsRspNative(bdaddr, AvrcpConstants.RSP_INV_SCOPE, (short) 0, (byte) 0x00, 0,
2231bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                null, null, null, null, null, null, null, null);
2232e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2233e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2234e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* utility function to update the global values of current Addressed and browsed player */
22358cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen    private void updateNewIds(int addrId, int browseId) {
22360c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        if (DEBUG)
22370c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen            Log.v(TAG, "updateNewIds: Addressed:" + mCurrAddrPlayerID + " to " + addrId
22380c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen                            + ", Browse:" + mCurrBrowsePlayerID + " to " + browseId);
2239e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mCurrAddrPlayerID = addrId;
2240e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mCurrBrowsePlayerID = browseId;
2241e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2242e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2243e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Getting the application's displayable name from package name */
2244e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private String getAppLabel(String packageName) {
2245e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ApplicationInfo appInfo = null;
2246e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        try {
2247e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            appInfo = mPackageManager.getApplicationInfo(packageName, 0);
2248e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } catch (NameNotFoundException e) {
2249e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            e.printStackTrace();
2250e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2251e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2252e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return (String) (appInfo != null ? mPackageManager
2253e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                .getApplicationLabel(appInfo) : "Unknown");
2254e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2255e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2256e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handlePlayItemResponse(byte[] bdaddr, byte[] uid, byte scope) {
2257b3436e976055f684050be9afdadc73645316806aMarie Janssen        if (scope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
2258b3436e976055f684050be9afdadc73645316806aMarie Janssen            mAddressedMediaPlayer.playItem(bdaddr, uid, mMediaController);
2259e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2260e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        else {
2261e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if(!isAddrPlayerSameAsBrowsed(bdaddr)) {
2262e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.w(TAG, "Remote requesting play item on uid which may not be recognized by" +
2263e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        "current addressed player");
2264e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                playItemRspNative(bdaddr, AvrcpConstants.RSP_INV_ITEM);
2265e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2266e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2267e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) {
2268e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).playItem(uid, scope);
2269e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2270e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "handlePlayItemResponse: Remote requested playitem " +
2271e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        "before setbrowsedplayer");
2272e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                playItemRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR);
2273e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2274e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2275e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2276e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2277e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handleGetItemAttr(AvrcpCmd.ItemAttrCmd itemAttr) {
227858e50a45b65eff899b284a3f51da781a3087bec4koh.changseok        if (itemAttr.mUidCounter != sUIDCounter) {
227958e50a45b65eff899b284a3f51da781a3087bec4koh.changseok            Log.e(TAG, "handleGetItemAttr: invaild uid counter.");
228058e50a45b65eff899b284a3f51da781a3087bec4koh.changseok            getItemAttrRspNative(
228158e50a45b65eff899b284a3f51da781a3087bec4koh.changseok                    itemAttr.mAddress, AvrcpConstants.RSP_UID_CHANGED, (byte) 0, null, null);
228258e50a45b65eff899b284a3f51da781a3087bec4koh.changseok            return;
228358e50a45b65eff899b284a3f51da781a3087bec4koh.changseok        }
2284d89304c6be6e1c332008dcbeab08889881064454Marie Janssen        if (itemAttr.mScope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
2285d89304c6be6e1c332008dcbeab08889881064454Marie Janssen            if (mCurrAddrPlayerID == NO_PLAYER_ID) {
2286d89304c6be6e1c332008dcbeab08889881064454Marie Janssen                getItemAttrRspNative(
2287d89304c6be6e1c332008dcbeab08889881064454Marie Janssen                        itemAttr.mAddress, AvrcpConstants.RSP_NO_AVBL_PLAY, (byte) 0, null, null);
22880533d66ae0a334789c197cde425d3ad87a84dd7dMarie Janssen                return;
2289d89304c6be6e1c332008dcbeab08889881064454Marie Janssen            }
22900533d66ae0a334789c197cde425d3ad87a84dd7dMarie Janssen            mAddressedMediaPlayer.getItemAttr(itemAttr.mAddress, itemAttr, mMediaController);
22910533d66ae0a334789c197cde425d3ad87a84dd7dMarie Janssen            return;
22920533d66ae0a334789c197cde425d3ad87a84dd7dMarie Janssen        }
22930533d66ae0a334789c197cde425d3ad87a84dd7dMarie Janssen        // All other scopes use browsed player
22940533d66ae0a334789c197cde425d3ad87a84dd7dMarie Janssen        if (mAvrcpBrowseManager.getBrowsedMediaPlayer(itemAttr.mAddress) != null) {
22950533d66ae0a334789c197cde425d3ad87a84dd7dMarie Janssen            mAvrcpBrowseManager.getBrowsedMediaPlayer(itemAttr.mAddress).getItemAttr(itemAttr);
2296d89304c6be6e1c332008dcbeab08889881064454Marie Janssen        } else {
22970533d66ae0a334789c197cde425d3ad87a84dd7dMarie Janssen            Log.e(TAG, "Could not get attributes. mBrowsedMediaPlayer is null");
22980533d66ae0a334789c197cde425d3ad87a84dd7dMarie Janssen            getItemAttrRspNative(
22990533d66ae0a334789c197cde425d3ad87a84dd7dMarie Janssen                    itemAttr.mAddress, AvrcpConstants.RSP_INTERNAL_ERR, (byte) 0, null, null);
2300e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2301e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2302e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2303e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handleGetTotalNumOfItemsResponse(byte[] bdaddr, byte scope) {
2304e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // for scope as media player list
2305e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (scope == AvrcpConstants.BTRC_SCOPE_PLAYER_LIST) {
23068cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            int numPlayers = 0;
23078cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            synchronized (mMediaPlayerInfoList) {
23088cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                numPlayers = mMediaPlayerInfoList.size();
23098cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
23108cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            if (DEBUG) Log.d(TAG, "handleGetTotalNumOfItemsResponse: " + numPlayers + " players.");
23118cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            getTotalNumOfItemsRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, numPlayers);
23128cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        } else if (scope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
2313b3436e976055f684050be9afdadc73645316806aMarie Janssen            mAddressedMediaPlayer.getTotalNumOfItems(bdaddr, mMediaController);
2314e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
2315e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // for FileSystem browsing scopes as VFS, Now Playing
2316e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) {
2317e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).getTotalNumOfItems(scope);
2318e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2319e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "Could not get Total NumOfItems. mBrowsedMediaPlayer is null");
2320e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                getTotalNumOfItemsRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR, 0, 0);
2321e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2322e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2323e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2324e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2325e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2326e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* check if browsed player and addressed player are same */
2327e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isAddrPlayerSameAsBrowsed(byte[] bdaddr) {
2328e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browsedPlayer = getCurrentBrowsedPlayer(bdaddr);
2329e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2330e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!isPackageNameValid(browsedPlayer)) {
2331e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Log.w(TAG, "Browsed player name empty");
2332351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen            return false;
2333e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2334e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
23350b6cad4a9f1ab18f6b3627ce7cf6316466cdb95aMarie Janssen        MediaPlayerInfo info = getAddressedPlayerInfo();
2336810d960162d74ba291a085ee2b11a37e7cbdace7Marie Janssen        String packageName = (info == null) ? "<none>" : info.getPackageName();
2337810d960162d74ba291a085ee2b11a37e7cbdace7Marie Janssen        if (info == null || !packageName.equals(browsedPlayer)) {
2338810d960162d74ba291a085ee2b11a37e7cbdace7Marie Janssen            if (DEBUG) Log.d(TAG, browsedPlayer + " is not addressed player " + packageName);
2339351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen            return false;
2340351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        }
2341351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen        return true;
2342e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2343e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2344e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* checks if package name is not null or empty */
2345e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isPackageNameValid(String browsedPackage) {
2346e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean isValid = (browsedPackage != null && browsedPackage.length() > 0);
2347e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "isPackageNameValid: browsedPackage = " + browsedPackage +
2348e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                "isValid = " + isValid);
2349e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return isValid;
2350e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2351e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2352e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* checks if selected addressed player is already addressed */
2353e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isPlayerAlreadyAddressed(int selectedId) {
2354e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // checking if selected ID is same as the current addressed player id
2355e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean isAddressed = (mCurrAddrPlayerID == selectedId);
2356e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "isPlayerAlreadyAddressed: isAddressed = " + isAddressed);
2357e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return isAddressed;
2358e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2359e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2360e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    public void dump(StringBuilder sb) {
2361e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        sb.append("AVRCP:\n");
2362029b34a866c2f4ab132412ec2814fd500813c565Marie Janssen        ProfileService.println(sb, "mMediaAttributes: " + mMediaAttributes.toRedactedString());
2363e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags);
2364e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState);
2365e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT);
2366e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT);
2367e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs);
2368e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT);
2369e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mNextPosMs: " + mNextPosMs);
2370e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPrevPosMs: " + mPrevPosMs);
2371e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mFeatures: " + mFeatures);
2372e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mRemoteVolume: " + mRemoteVolume);
2373e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mLastRemoteVolume: " + mLastRemoteVolume);
2374e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mLastDirection: " + mLastDirection);
2375e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mVolumeStep: " + mVolumeStep);
2376e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mAudioStreamMax: " + mAudioStreamMax);
2377e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mVolCmdAdjustInProgress: " + mVolCmdAdjustInProgress);
2378e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mVolCmdSetInProgress: " + mVolCmdSetInProgress);
2379e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mAbsVolRetryTimes: " + mAbsVolRetryTimes);
2380e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mVolumeMapping: " + mVolumeMapping.toString());
238186582543b9cd70a617e84c049c03b466653e9641Marie Janssen        synchronized (this) {
238286582543b9cd70a617e84c049c03b466653e9641Marie Janssen            if (mMediaController != null)
238386582543b9cd70a617e84c049c03b466653e9641Marie Janssen                ProfileService.println(sb, "mMediaController: "
238486582543b9cd70a617e84c049c03b466653e9641Marie Janssen                                + mMediaController.getWrappedInstance() + " pkg "
238586582543b9cd70a617e84c049c03b466653e9641Marie Janssen                                + mMediaController.getPackageName());
238686582543b9cd70a617e84c049c03b466653e9641Marie Janssen        }
23870c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        ProfileService.println(sb, "");
23880c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        ProfileService.println(sb, "Media Players:");
23898cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen        synchronized (mMediaPlayerInfoList) {
23908cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
23918cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                int key = entry.getKey();
23928cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                ProfileService.println(sb, ((mCurrAddrPlayerID == key) ? " *#" : "  #")
23938cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen                                + entry.getKey() + ": " + entry.getValue());
23948cd453176a070f0627d64fc2f3e34b8258d2e9a7Marie Janssen            }
2395bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        }
2396bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
2397303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen        ProfileService.println(sb, "");
2398303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen        mAddressedMediaPlayer.dump(sb, mMediaController);
2399303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen
2400303c1c67dbc142822bc37e7c5a89fba82faf2ac0Marie Janssen        ProfileService.println(sb, "");
24010c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        ProfileService.println(sb, mPassthroughDispatched + " passthrough operations: ");
24020c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        if (mPassthroughDispatched > mPassthroughLogs.size())
24030c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen            ProfileService.println(sb, "  (last " + mPassthroughLogs.size() + ")");
24040c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        synchronized (mPassthroughLogs) {
24050c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen            for (MediaKeyLog log : mPassthroughLogs) {
24060c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen                ProfileService.println(sb, "  " + log);
24070c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen            }
2408bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        }
24090c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        synchronized (mPassthroughPending) {
24100c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen            for (MediaKeyLog log : mPassthroughPending) {
24110c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen                ProfileService.println(sb, "  " + log);
24120c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen            }
241332638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov        }
241432638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov
241532638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov        // Print the blacklisted devices (for absolute volume control)
241632638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov        SharedPreferences pref =
241732638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov                mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, Context.MODE_PRIVATE);
241832638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov        Map<String, ?> allKeys = pref.getAll();
241932638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov        ProfileService.println(sb, "");
242032638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov        ProfileService.println(sb, "Runtime Blacklisted Devices (absolute volume):");
242132638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov        if (allKeys.isEmpty()) {
242232638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov            ProfileService.println(sb, "  None");
242332638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov        } else {
242432638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov            for (String key : allKeys.keySet()) {
242532638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov                ProfileService.println(sb, "  " + key);
242632638175c01351b88bbbc5628825db2d62bd1a89Pavlin Radoslavov            }
24270b6cad4a9f1ab18f6b3627ce7cf6316466cdb95aMarie Janssen        }
2428e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2429e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2430e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    public class AvrcpBrowseManager {
2431e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Map<String, BrowsedMediaPlayer> connList = new HashMap<String, BrowsedMediaPlayer>();
2432e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private AvrcpMediaRspInterface mMediaInterface;
2433e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private Context mContext;
2434e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2435e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public AvrcpBrowseManager(Context context, AvrcpMediaRspInterface mediaInterface) {
2436e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            mContext = context;
2437e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            mMediaInterface = mediaInterface;
2438e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2439e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2440e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void cleanup() {
2441e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Iterator entries = connList.entrySet().iterator();
2442e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            while (entries.hasNext()) {
2443e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Map.Entry entry = (Map.Entry) entries.next();
2444e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                BrowsedMediaPlayer browsedMediaPlayer = (BrowsedMediaPlayer) entry.getValue();
2445e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (browsedMediaPlayer != null) {
2446e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    browsedMediaPlayer.cleanup();
2447e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
2448e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2449e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // clean up the map
2450e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            connList.clear();
2451e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2452e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2453e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // get the a free media player interface based on the passed bd address
2454e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // if the no items is found for the passed media player then it assignes a
2455e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // available media player interface
2456e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public BrowsedMediaPlayer getBrowsedMediaPlayer(byte[] bdaddr) {
2457e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            BrowsedMediaPlayer mediaPlayer;
2458e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String bdaddrStr = new String(bdaddr);
2459bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            if (connList.containsKey(bdaddrStr)) {
2460e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mediaPlayer = connList.get(bdaddrStr);
2461e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2462e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mediaPlayer = new BrowsedMediaPlayer(bdaddr, mContext, mMediaInterface);
2463e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                connList.put(bdaddrStr, mediaPlayer);
2464e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2465e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return mediaPlayer;
2466e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2467e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2468e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // clears the details pertaining to passed bdaddres
2469e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public boolean clearBrowsedMediaPlayer(byte[] bdaddr) {
2470e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String bdaddrStr = new String(bdaddr);
2471bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            if (connList.containsKey(bdaddrStr)) {
2472e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                connList.remove(bdaddrStr);
2473e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return true;
2474e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2475e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return false;
2476e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2477e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2478e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public Map<String, BrowsedMediaPlayer> getConnList() {
2479e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return connList;
2480e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2481e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2482e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Helper function to convert colon separated bdaddr to byte string */
2483e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private byte[] hexStringToByteArray(String s) {
2484e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int len = s.length();
2485e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            byte[] data = new byte[len / 2];
2486e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            for (int i = 0; i < len; i += 2) {
2487e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
2488e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        + Character.digit(s.charAt(i+1), 16));
2489e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2490e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return data;
2491e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2492e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2493e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2494e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
2495e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * private class which handles responses from AvrcpMediaManager. Maps responses to native
2496e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * responses. This class implements the AvrcpMediaRspInterface interface.
2497e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
2498e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private class AvrcpMediaRsp implements AvrcpMediaRspInterface {
2499e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private static final String TAG = "AvrcpMediaRsp";
2500e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2501e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void setAddrPlayerRsp(byte[] address, int rspStatus) {
2502e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!setAddressedPlayerRspNative(address, rspStatus)) {
2503e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "setAddrPlayerRsp failed!");
2504e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2505e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2506e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2507e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void setBrowsedPlayerRsp(byte[] address, int rspStatus, byte depth, int numItems,
2508e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                String[] textArray) {
2509e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!setBrowsedPlayerRspNative(address, rspStatus, depth, numItems, textArray)) {
2510e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "setBrowsedPlayerRsp failed!");
2511e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2512e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2513e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2514e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void mediaPlayerListRsp(byte[] address, int rspStatus, MediaPlayerListRsp rspObj) {
2515e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) {
2516e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!mediaPlayerListRspNative(address, rspStatus, sUIDCounter, rspObj.itemType,
2517351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                            rspObj.mNumItems, rspObj.mPlayerIds, rspObj.mPlayerTypes,
2518351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                            rspObj.mPlayerSubTypes, rspObj.mPlayStatusValues,
2519351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                            rspObj.mFeatureBitMaskValues, rspObj.mPlayerNameList))
2520351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                    Log.e(TAG, "mediaPlayerListRsp failed!");
2521e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2522e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "mediaPlayerListRsp: rspObj is null");
2523351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                if (!mediaPlayerListRspNative(address, rspStatus, sUIDCounter, (byte) 0x00, 0, null,
2524351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                            null, null, null, null, null))
2525351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen                    Log.e(TAG, "mediaPlayerListRsp failed!");
2526e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2527e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2528e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2529e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void folderItemsRsp(byte[] address, int rspStatus, FolderItemsRsp rspObj) {
2530e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) {
2531e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!getFolderItemsRspNative(address, rspStatus, sUIDCounter, rspObj.mScope,
2532e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        rspObj.mNumItems, rspObj.mFolderTypes, rspObj.mPlayable, rspObj.mItemTypes,
2533e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        rspObj.mItemUid, rspObj.mDisplayNames, rspObj.mAttributesNum,
2534e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        rspObj.mAttrIds, rspObj.mAttrValues))
2535e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getFolderItemsRspNative failed!");
2536e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2537e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "folderItemsRsp: rspObj is null or rspStatus is error:" + rspStatus);
2538e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!getFolderItemsRspNative(address, rspStatus, sUIDCounter, (byte) 0x00, 0,
2539e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        null, null, null, null, null, null, null, null))
2540e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getFolderItemsRspNative failed!");
2541e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2542e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2543e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2544e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2545e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void changePathRsp(byte[] address, int rspStatus, int numItems) {
2546e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!changePathRspNative(address, rspStatus, numItems))
2547e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "changePathRspNative failed!");
2548e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2549e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2550e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void getItemAttrRsp(byte[] address, int rspStatus, ItemAttrRsp rspObj) {
2551e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) {
2552e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!getItemAttrRspNative(address, rspStatus, rspObj.mNumAttr,
2553e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        rspObj.mAttributesIds, rspObj.mAttributesArray))
2554e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getItemAttrRspNative failed!");
2555e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2556e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "getItemAttrRsp: rspObj is null or rspStatus is error:" + rspStatus);
2557e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!getItemAttrRspNative(address, rspStatus, (byte) 0x00, null, null))
2558e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getItemAttrRspNative failed!");
2559e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2560e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2561e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2562e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void playItemRsp(byte[] address, int rspStatus) {
2563e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!playItemRspNative(address, rspStatus)) {
2564e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "playItemRspNative failed!");
2565e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2566e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2567e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2568e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void getTotalNumOfItemsRsp(byte[] address, int rspStatus, int uidCounter,
2569e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                int numItems) {
2570e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!getTotalNumOfItemsRspNative(address, rspStatus, sUIDCounter, numItems)) {
2571e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "getTotalNumOfItemsRspNative failed!");
2572e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2573e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2574e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2575bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        public void addrPlayerChangedRsp(int type, int playerId, int uidCounter) {
2576e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspAddrPlayerChangedNative(type, playerId, sUIDCounter)) {
2577e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspAddrPlayerChangedNative failed!");
2578e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2579e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2580e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2581e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void avalPlayerChangedRsp(byte[] address, int type) {
2582e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspAvalPlayerChangedNative(type)) {
2583e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspAvalPlayerChangedNative failed!");
2584e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2585e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2586e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2587d65422f9b47bff59b12162fc51032eb633f0722fAjay Panicker        public void uidsChangedRsp(int type) {
2588e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspUIDsChangedNative(type, sUIDCounter)) {
2589e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspUIDsChangedNative failed!");
2590e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2591e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2592e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2593e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void nowPlayingChangedRsp(int type) {
25943616b7ce7be6abaca5eef876e055155f9e8a3b1fAjay Panicker            if (mNowPlayingListChangedNT != AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
25953616b7ce7be6abaca5eef876e055155f9e8a3b1fAjay Panicker                if (DEBUG) Log.d(TAG, "NowPlayingListChanged: Not registered or requesting.");
25963616b7ce7be6abaca5eef876e055155f9e8a3b1fAjay Panicker                return;
25973616b7ce7be6abaca5eef876e055155f9e8a3b1fAjay Panicker            }
25983616b7ce7be6abaca5eef876e055155f9e8a3b1fAjay Panicker
2599e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspNowPlayingChangedNative(type)) {
2600e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspNowPlayingChangedNative failed!");
2601e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
26023616b7ce7be6abaca5eef876e055155f9e8a3b1fAjay Panicker            mNowPlayingListChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
2603e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2604e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2605e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void trackChangedRsp(int type, byte[] uid) {
2606e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspTrackChangeNative(type, uid)) {
2607e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspTrackChangeNative failed!");
2608e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2609e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2610e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2611e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2612e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* getters for some private variables */
2613e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    public AvrcpBrowseManager getAvrcpBrowseManager() {
2614e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return mAvrcpBrowseManager;
2615e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2616e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2617bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    /* PASSTHROUGH COMMAND MANAGEMENT */
2618bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
2619bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    void handlePassthroughCmd(int op, int state) {
2620bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        int code = avrcpPassthroughToKeyCode(op);
2621bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        if (code == KeyEvent.KEYCODE_UNKNOWN) {
2622bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            Log.w(TAG, "Ignoring passthrough of unknown key " + op + " state " + state);
2623bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            return;
2624bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        }
2625bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        int action = KeyEvent.ACTION_DOWN;
2626bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        if (state == AvrcpConstants.KEY_STATE_RELEASE) action = KeyEvent.ACTION_UP;
2627bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        KeyEvent event = new KeyEvent(action, code);
2628bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        if (!KeyEvent.isMediaKey(code)) {
2629bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            Log.w(TAG, "Passthrough non-media key " + op + " (code " + code + ") state " + state);
2630bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        }
263167c982aed4e67772e155f934c2055c72b83f1f22Ajay Panicker
2632bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        mMediaSessionManager.dispatchMediaKeyEvent(event);
2633bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        addKeyPending(event);
2634bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    }
2635bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
2636bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    private int avrcpPassthroughToKeyCode(int operation) {
2637bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        switch (operation) {
2638bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_UP:
2639bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_DPAD_UP;
2640bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_DOWN:
2641bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_DPAD_DOWN;
2642bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_LEFT:
2643bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_DPAD_LEFT;
2644bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT:
2645bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_DPAD_RIGHT;
2646bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT_UP:
2647bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_DPAD_UP_RIGHT;
2648bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT_DOWN:
2649bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_DPAD_DOWN_RIGHT;
2650bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_LEFT_UP:
2651bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_DPAD_UP_LEFT;
2652bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_LEFT_DOWN:
2653bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_DPAD_DOWN_LEFT;
2654bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_0:
2655bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_0;
2656bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_1:
2657bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_1;
2658bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_2:
2659bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_2;
2660bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_3:
2661bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_3;
2662bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_4:
2663bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_4;
2664bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_5:
2665bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_5;
2666bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_6:
2667bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_6;
2668bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_7:
2669bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_7;
2670bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_8:
2671bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_8;
2672bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_9:
2673bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_9;
2674bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_DOT:
2675bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_DOT;
2676bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_ENTER:
2677bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_NUMPAD_ENTER;
2678bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CLEAR:
2679bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_CLEAR;
2680bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CHAN_UP:
2681bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_CHANNEL_UP;
2682bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CHAN_DOWN:
2683bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_CHANNEL_DOWN;
2684bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_PREV_CHAN:
2685bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_LAST_CHANNEL;
2686bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_INPUT_SEL:
2687bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_TV_INPUT;
2688bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_DISP_INFO:
2689bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_INFO;
2690bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_HELP:
2691bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_HELP;
2692bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_PAGE_UP:
2693bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_PAGE_UP;
2694bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_PAGE_DOWN:
2695bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_PAGE_DOWN;
2696bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_POWER:
2697bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_POWER;
2698bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_VOL_UP:
2699bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_VOLUME_UP;
2700bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_VOL_DOWN:
2701bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_VOLUME_DOWN;
2702bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_MUTE:
2703bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_MUTE;
2704e85822729c985ca537d5f9943ed12f37976bfbafAndre Eisenbach            case BluetoothAvrcp.PASSTHROUGH_ID_PLAY:
2705e85822729c985ca537d5f9943ed12f37976bfbafAndre Eisenbach                return KeyEvent.KEYCODE_MEDIA_PLAY;
2706bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_STOP:
2707bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_MEDIA_STOP;
2708e85822729c985ca537d5f9943ed12f37976bfbafAndre Eisenbach            case BluetoothAvrcp.PASSTHROUGH_ID_PAUSE:
2709e85822729c985ca537d5f9943ed12f37976bfbafAndre Eisenbach                return KeyEvent.KEYCODE_MEDIA_PAUSE;
2710bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RECORD:
2711bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_MEDIA_RECORD;
2712bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_REWIND:
2713bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_MEDIA_REWIND;
2714bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR:
2715bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
2716bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_EJECT:
2717bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_MEDIA_EJECT;
2718bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_FORWARD:
2719bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_MEDIA_NEXT;
2720bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_BACKWARD:
2721bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_MEDIA_PREVIOUS;
2722bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F1:
2723bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_F1;
2724bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F2:
2725bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_F2;
2726bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F3:
2727bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_F3;
2728bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F4:
2729bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_F4;
2730bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F5:
2731bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_F5;
2732bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            // Fallthrough for all unknown key mappings
2733bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SELECT:
2734bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_ROOT_MENU:
2735bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SETUP_MENU:
2736bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CONT_MENU:
2737bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_FAV_MENU:
2738bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_EXIT:
2739bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SOUND_SEL:
2740bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_ANGLE:
2741bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SUBPICT:
2742bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_VENDOR:
2743bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            default:
2744bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                return KeyEvent.KEYCODE_UNKNOWN;
2745bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        }
2746bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    }
2747bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
2748bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    private void addKeyPending(KeyEvent event) {
27490c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        mPassthroughPending.add(new MediaKeyLog(System.currentTimeMillis(), event));
2750bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    }
2751bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
2752bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    private void recordKeyDispatched(KeyEvent event, String packageName) {
2753bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        long time = System.currentTimeMillis();
2754bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        Log.v(TAG, "recordKeyDispatched: " + event + " dispatched to " + packageName);
27550c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen        setAddressedMediaSessionPackage(packageName);
2756bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        synchronized (mPassthroughPending) {
2757bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            Iterator<MediaKeyLog> pending = mPassthroughPending.iterator();
2758bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            while (pending.hasNext()) {
2759bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                MediaKeyLog log = pending.next();
2760bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                if (log.addDispatch(time, event, packageName)) {
2761bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    mPassthroughDispatched++;
2762bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    mPassthroughLogs.add(log);
2763bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    pending.remove();
2764bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    return;
2765bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                }
2766bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            }
27670c3b4f4f77175b72061b356a54e2febaf1f19a6aMarie Janssen            Log.w(TAG, "recordKeyDispatch: can't find matching log!");
2768bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen        }
2769bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    }
2770bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
2771bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen    private final MediaSessionManager.Callback mButtonDispatchCallback =
2772bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            new MediaSessionManager.Callback() {
2773bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                @Override
2774bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                public void onMediaKeyEventDispatched(KeyEvent event, MediaSession.Token token) {
2775bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    // Get the package name
2776bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    android.media.session.MediaController controller =
2777bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                            new android.media.session.MediaController(mContext, token);
2778bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    String targetPackage = controller.getPackageName();
2779bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    recordKeyDispatched(event, targetPackage);
2780bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                }
2781bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
2782bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                @Override
2783bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                public void onMediaKeyEventDispatched(KeyEvent event, ComponentName receiver) {
2784bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    recordKeyDispatched(event, receiver.getPackageName());
2785bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                }
2786bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
2787bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                @Override
2788bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                public void onAddressedPlayerChanged(MediaSession.Token token) {
2789bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    setActiveMediaSession(token);
2790bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                }
2791bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
2792bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                @Override
2793bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                public void onAddressedPlayerChanged(ComponentName receiver) {
27941107f9516bf8866640247044deb9f780bb89e55cMarie Janssen                    if (receiver == null) {
27951107f9516bf8866640247044deb9f780bb89e55cMarie Janssen                        // No active sessions, and no session to revive, give up.
27961107f9516bf8866640247044deb9f780bb89e55cMarie Janssen                        setAddressedMediaSessionPackage(null);
27971107f9516bf8866640247044deb9f780bb89e55cMarie Janssen                        return;
27981107f9516bf8866640247044deb9f780bb89e55cMarie Janssen                    }
27991107f9516bf8866640247044deb9f780bb89e55cMarie Janssen                    // We can still get a passthrough which will revive this player.
2800bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                    setAddressedMediaSessionPackage(receiver.getPackageName());
2801bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen                }
2802bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen            };
2803bdcf510515b5b251b0b88ba3c05937661ca5da3fMarie Janssen
2804e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // Do not modify without updating the HAL bt_rc.h files.
2805e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2806e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // match up with btrc_play_status_t enum of bt_rc.h
2807b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    final static byte PLAYSTATUS_STOPPED = 0;
2808b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    final static byte PLAYSTATUS_PLAYING = 1;
2809b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    final static byte PLAYSTATUS_PAUSED = 2;
2810b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    final static byte PLAYSTATUS_FWD_SEEK = 3;
2811b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    final static byte PLAYSTATUS_REV_SEEK = 4;
2812b631457c5ccc472a499334f65b88848bbaf3c605Marie Janssen    final static byte PLAYSTATUS_ERROR = (byte) 255;
2813e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2814e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // match up with btrc_media_attr_t enum of bt_rc.h
2815e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_TITLE = 1;
2816e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_ARTIST = 2;
2817e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_ALBUM = 3;
2818e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_TRACK_NUM = 4;
2819e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_NUM_TRACKS = 5;
2820e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_GENRE = 6;
2821e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_PLAYING_TIME = 7;
2822e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2823e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // match up with btrc_event_id_t enum of bt_rc.h
2824e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_PLAY_STATUS_CHANGED = 1;
2825e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_TRACK_CHANGED = 2;
2826e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_TRACK_REACHED_END = 3;
2827e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_TRACK_REACHED_START = 4;
2828e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_PLAY_POS_CHANGED = 5;
2829e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_BATT_STATUS_CHANGED = 6;
2830e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_SYSTEM_STATUS_CHANGED = 7;
2831e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_APP_SETTINGS_CHANGED = 8;
2832e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVENT_NOW_PLAYING_CONTENT_CHANGED = 9;
2833e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_AVBL_PLAYERS_CHANGED = 0xa;
2834e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_ADDR_PLAYER_CHANGED = 0xb;
2835e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVENT_UIDS_CHANGED = 0x0c;
2836c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
2837c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native static void classInitNative();
2838c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native void initNative();
2839c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native void cleanupNative();
2840e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getPlayStatusRspNative(byte[] address, int playStatus, int songLen,
2841e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int songPos);
2842e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getElementAttrRspNative(byte[] address, byte numAttr, int[] attrIds,
2843e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String[] textArray);
2844c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean registerNotificationRspPlayStatusNative(int type, int playStatus);
2845c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean registerNotificationRspTrackChangeNative(int type, byte[] track);
2846aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private native boolean registerNotificationRspPlayPosNative(int type, int playPos);
284717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private native boolean setVolumeNative(int volume);
28485c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta    private native boolean sendPassThroughCommandNative(int keyCode, int keyState);
2849e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean setAddressedPlayerRspNative(byte[] address, int rspStatus);
2850e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean setBrowsedPlayerRspNative(byte[] address, int rspStatus, byte depth,
2851e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int numItems, String[] textArray);
2852e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean mediaPlayerListRspNative(byte[] address, int rsStatus, int uidCounter,
2853351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen            byte item_type, int numItems, int[] playerIds, byte[] playerTypes, int[] playerSubTypes,
2854351ffc02e8c395d0eabe108e5b4909e7f41ffae6Marie Janssen            byte[] playStatusValues, short[] featureBitMaskValues, String[] textArray);
2855e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getFolderItemsRspNative(byte[] address, int rspStatus, short uidCounter,
2856e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            byte scope, int numItems, byte[] folderTypes, byte[] playable, byte[] itemTypes,
2857e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            byte[] itemUidArray, String[] textArray, int[] AttributesNum, int[] AttributesIds,
2858e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String[] attributesArray);
2859e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean changePathRspNative(byte[] address, int rspStatus, int numItems);
2860e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getItemAttrRspNative(byte[] address, int rspStatus, byte numAttr,
2861e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int[] attrIds, String[] textArray);
2862e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean playItemRspNative(byte[] address, int rspStatus);
2863e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getTotalNumOfItemsRspNative(byte[] address, int rspStatus,
2864e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int uidCounter, int numItems);
2865e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean searchRspNative(byte[] address, int rspStatus, int uidCounter,
2866e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int numItems);
2867e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean addToNowPlayingRspNative(byte[] address, int rspStatus);
2868e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean registerNotificationRspAddrPlayerChangedNative(int type,
2869e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        int playerId, int uidCounter);
2870e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean registerNotificationRspAvalPlayerChangedNative(int type);
2871e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean registerNotificationRspUIDsChangedNative(int type, int uidCounter);
2872e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean registerNotificationRspNowPlayingChangedNative(int type);
28735c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta
2874c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
2875