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
1929174eb9ad6e255d7ec216ab9a2ce8d20e2fe13cMarie Janssenimport android.annotation.NonNull;
2078d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssenimport android.annotation.Nullable;
21188f205b5f093850d4cc627917a21204be36c56aZhihai Xuimport android.bluetooth.BluetoothA2dp;
22066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.bluetooth.BluetoothAvrcp;
23e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.BroadcastReceiver;
24e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.ComponentName;
25c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.content.Context;
26e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.Intent;
27e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.IntentFilter;
28c4fbd756e2645147470c486ae96f2253f5e13a52Jack Heimport android.content.SharedPreferences;
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;
34c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.AudioManager;
35a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavovimport android.media.AudioPlaybackConfiguration;
363b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssenimport android.media.MediaDescription;
370e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssenimport android.media.MediaMetadata;
38e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.media.session.MediaSession;
390e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssenimport android.media.session.MediaSessionManager;
400e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssenimport android.media.session.PlaybackState;
41e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.os.Bundle;
42c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Handler;
43c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.HandlerThread;
44c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Looper;
45c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Message;
46aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport android.os.SystemClock;
470427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panickerimport android.os.UserManager;
48c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.util.Log;
49881675b362bde18acbbcf69c513175addca4a8baZhenye Zhuimport android.view.KeyEvent;
506e29e12add362546784126119f26f04fc760f021RoboErik
51e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport com.android.bluetooth.R;
52aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport com.android.bluetooth.Utils;
53c4fbd756e2645147470c486ae96f2253f5e13a52Jack Heimport com.android.bluetooth.btservice.ProfileService;
546e29e12add362546784126119f26f04fc760f021RoboErik
55c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.ArrayList;
5678d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssenimport java.util.Collections;
5711798b011c962b602217b479130d413f3b30f19aLiejun Taoimport java.util.HashMap;
58bc5aacf160c5cc7ff5a196c7c3c1cf62f322fc14Marie Janssenimport java.util.HashSet;
59e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport java.util.Iterator;
60c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.List;
61e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport java.util.Map;
62bc5aacf160c5cc7ff5a196c7c3c1cf62f322fc14Marie Janssenimport java.util.Set;
63eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssenimport java.util.SortedMap;
64eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssenimport java.util.TreeMap;
65e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
66e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah/******************************************************************************
67e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah * support Bluetooth AVRCP profile. support metadata, play status, event
68e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah * notifications, address player selection and browse feature implementation.
69e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah ******************************************************************************/
70eb7b90f5b93db1230a5b64caa3d8d05a642e33a6Marie Janssen
71066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodpublic final class Avrcp {
7206457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski    private static final boolean DEBUG = false;
73c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private static final String TAG = "Avrcp";
7411798b011c962b602217b479130d413f3b30f19aLiejun Tao    private static final String ABSOLUTE_VOLUME_BLACKLIST = "absolute_volume_blacklist";
75c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
76c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Context mContext;
77c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private final AudioManager mAudioManager;
78ded973620f204f11f20d40928735a4d87e00afedHansong Zhang    private volatile AvrcpMessageHandler mHandler;
79a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov    private Handler mAudioManagerPlaybackHandler;
80a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov    private AudioManagerPlaybackListener mAudioManagerPlaybackCb;
810e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen    private MediaSessionManager mMediaSessionManager;
82dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    @Nullable private MediaController mMediaController;
830e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen    private MediaControllerListener mMediaControllerCb;
843b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen    private MediaAttributes mMediaAttributes;
855aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen    private long mLastQueueId;
86e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private PackageManager mPackageManager;
87c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mTransportControlFlags;
88dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    @NonNull private PlaybackState mCurrentPlayState;
890a429916782c20980e7f0893c503c633b8341f88Marie Janssen    private int mA2dpState;
90a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov    private boolean mAudioManagerIsPlaying;
91c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mPlayStatusChangedNT;
92cb00f2feb8405508707e41e463a79bf77eac7bc7Ajay Panicker    private byte mReportedPlayStatus;
93c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mTrackChangedNT;
94f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    private int mPlayPosChangedNT;
9559b1c77f883bd97816332046a3a98be4431cceddMarie Janssen    private int mAddrPlayerChangedNT;
9659b1c77f883bd97816332046a3a98be4431cceddMarie Janssen    private int mReportedPlayerID;
9705723ee9e6619814876a6cce5004d11b38c3f648Ajay Panicker    private int mNowPlayingListChangedNT;
98aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPlaybackIntervalMs;
99fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen    private long mLastReportedPosition;
100aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mNextPosMs;
101aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPrevPosMs;
10217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mFeatures;
10311798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mRemoteVolume;
10411798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLastRemoteVolume;
10511798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mInitialRemoteVolume;
10611798b011c962b602217b479130d413f3b30f19aLiejun Tao
10711798b011c962b602217b479130d413f3b30f19aLiejun Tao    /* Local volume in audio index 0-15 */
10811798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLocalVolume;
10911798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLastLocalVolume;
11011798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mAbsVolThreshold;
11111798b011c962b602217b479130d413f3b30f19aLiejun Tao
11211798b011c962b602217b479130d413f3b30f19aLiejun Tao    private String mAddress;
11311798b011c962b602217b479130d413f3b30f19aLiejun Tao    private HashMap<Integer, Integer> mVolumeMapping;
11411798b011c962b602217b479130d413f3b30f19aLiejun Tao
11517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mLastDirection;
1162e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private final int mVolumeStep;
1172e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private final int mAudioStreamMax;
11811798b011c962b602217b479130d413f3b30f19aLiejun Tao    private boolean mVolCmdSetInProgress;
11917675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mAbsVolRetryTimes;
120eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
121384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen    private static final int NO_PLAYER_ID = 0;
122384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen
123e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private int mCurrAddrPlayerID;
124e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private int mCurrBrowsePlayerID;
125eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    private int mLastUsedPlayerID;
126e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private AvrcpMediaRsp mAvrcpMediaRsp;
127e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
128e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* UID counter to be shared across different files. */
12959b1c77f883bd97816332046a3a98be4431cceddMarie Janssen    static short sUIDCounter = AvrcpConstants.DEFAULT_UID_COUNTER;
130ace834feb02adabd61f628c4471147aea02d939cJohn Du
13117675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* BTRC features */
13217675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_METADATA = 0x01;
13317675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02;
13417675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_BROWSE = 0x04;
13517675906064bb72fdcca75baa56cdf8bb8968d01John Du
13617675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* AVRC response codes, from avrc_defs */
13717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_NOT_IMPL = 8;
13817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_ACCEPT = 9;
13917675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_REJ = 10;
14017675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_IN_TRANS = 11;
14117675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_IMPL_STBL = 12;
14217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_CHANGED = 13;
14317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_INTERIM = 15;
14417675906064bb72fdcca75baa56cdf8bb8968d01John Du
145e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* AVRC request commands from Native */
146e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_RC_FEATURES = 1;
147e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_PLAY_STATUS = 2;
148e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_ELEM_ATTRS = 3;
149e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_REGISTER_NOTIFICATION = 4;
150e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_VOLUME_CHANGE = 5;
151e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_FOLDER_ITEMS = 6;
152e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_SET_ADDR_PLAYER = 7;
153e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_SET_BR_PLAYER = 8;
154e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_CHANGE_PATH = 9;
155e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_PLAY_ITEM = 10;
156e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_ITEM_ATTR = 11;
157e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS = 12;
158e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_PASS_THROUGH = 13;
159e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
160e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* other AVRC messages */
161e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_PLAY_INTERVAL_TIMEOUT = 14;
162e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_SET_ABSOLUTE_VOLUME = 16;
163e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_ABS_VOL_TIMEOUT = 17;
16459b1c77f883bd97816332046a3a98be4431cceddMarie Janssen    private static final int MSG_SET_A2DP_AUDIO_STATE = 18;
165f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen    private static final int MSG_NOW_PLAYING_CHANGED_RSP = 19;
16605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
16717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int CMD_TIMEOUT_DELAY = 2000;
168f8201e1c6bf7fadc0a332151a652325a7f31255aLiejun Tao    private static final int MAX_ERROR_RETRY_TIMES = 6;
16917675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRCP_MAX_VOL = 127;
17017675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRCP_BASE_VOLUME_STEP = 1;
171ace834feb02adabd61f628c4471147aea02d939cJohn Du
172e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Communicates with MediaPlayer to fetch media content */
173e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private BrowsedMediaPlayer mBrowsedMediaPlayer;
174e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
17505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    /* Addressed player handling */
176e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private AddressedMediaPlayer mAddressedMediaPlayer;
177e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
178e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* List of Media player instances, useful for retrieving MediaPlayerList or MediaPlayerInfo */
179eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    private SortedMap<Integer, MediaPlayerInfo> mMediaPlayerInfoList;
180f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen    private boolean mAvailablePlayerViewChanged;
181e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
182e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* List of media players which supports browse */
1835146bd27869df5473aa53e6271266f51733971efMarie Janssen    private List<BrowsePlayerInfo> mBrowsePlayerInfoList;
184e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
185e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Manage browsed players */
186e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private AvrcpBrowseManager mAvrcpBrowseManager;
187e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
188e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Broadcast receiver for device connections intent broadcasts */
189e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private final BroadcastReceiver mAvrcpReceiver = new AvrcpServiceBroadcastReceiver();
1900427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker    private final BroadcastReceiver mBootReceiver = new AvrcpServiceBootReceiver();
191e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
19205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    /* Recording passthrough key dispatches */
193dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    private static final int PASSTHROUGH_LOG_MAX_SIZE = DEBUG ? 50 : 10;
19405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private EvictingQueue<MediaKeyLog> mPassthroughLogs; // Passthorugh keys dispatched
19578d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen    private List<MediaKeyLog> mPassthroughPending; // Passthrough keys sent not dispatched yet
19605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private int mPassthroughDispatched; // Number of keys dispatched
19705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
19805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private class MediaKeyLog {
19905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        private long mTimeSent;
20005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        private long mTimeProcessed;
20105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        private String mPackage;
20205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        private KeyEvent mEvent;
20305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
204d04c0a8609b39f891d5787f051b1dfb105ceee93Jack He        MediaKeyLog(long time, KeyEvent event) {
20505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mEvent = event;
20605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mTimeSent = time;
20705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
20805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
20905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        public boolean addDispatch(long time, KeyEvent event, String packageName) {
210c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (mPackage != null) {
211c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                return false;
212c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
213c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (event.getAction() != mEvent.getAction()) {
214c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                return false;
215c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
216c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (event.getKeyCode() != mEvent.getKeyCode()) {
217c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                return false;
218c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
21905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mPackage = packageName;
22005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mTimeProcessed = time;
22105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            return true;
22205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
22305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
2242fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
22505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        public String toString() {
22605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            StringBuilder sb = new StringBuilder();
22705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            sb.append(android.text.format.DateFormat.format("MM-dd HH:mm:ss", mTimeSent));
22805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            sb.append(" " + mEvent.toString());
22905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            if (mPackage == null) {
23005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                sb.append(" (undispatched)");
23105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            } else {
23205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                sb.append(" to " + mPackage);
23305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                sb.append(" in " + (mTimeProcessed - mTimeSent) + "ms");
23405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            }
23505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            return sb.toString();
23605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
23705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
23805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
239c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    static {
240c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        classInitNative();
241c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
242c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
243c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Avrcp(Context context) {
2443b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        mMediaAttributes = new MediaAttributes(null);
2455aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen        mLastQueueId = MediaSession.QueueItem.UNKNOWN_ID;
246c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        mCurrentPlayState =
247c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build();
24859b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        mReportedPlayStatus = PLAYSTATUS_ERROR;
2490a429916782c20980e7f0893c503c633b8341f88Marie Janssen        mA2dpState = BluetoothA2dp.STATE_NOT_PLAYING;
250a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov        mAudioManagerIsPlaying = false;
251e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
252e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
253e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
25459b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        mAddrPlayerChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
25505723ee9e6619814876a6cce5004d11b38c3f648Ajay Panicker        mNowPlayingListChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
25659b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        mPlaybackIntervalMs = 0L;
257fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        mLastReportedPosition = -1;
2583635a926bd7316a55b288a54d409a1070a9c19e8Marie Janssen        mNextPosMs = -1;
2593635a926bd7316a55b288a54d409a1070a9c19e8Marie Janssen        mPrevPosMs = -1;
26017675906064bb72fdcca75baa56cdf8bb8968d01John Du        mFeatures = 0;
26111798b011c962b602217b479130d413f3b30f19aLiejun Tao        mRemoteVolume = -1;
26211798b011c962b602217b479130d413f3b30f19aLiejun Tao        mInitialRemoteVolume = -1;
26311798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLastRemoteVolume = -1;
26417675906064bb72fdcca75baa56cdf8bb8968d01John Du        mLastDirection = 0;
26511798b011c962b602217b479130d413f3b30f19aLiejun Tao        mVolCmdSetInProgress = false;
26617675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAbsVolRetryTimes = 0;
26711798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLocalVolume = -1;
26811798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLastLocalVolume = -1;
26911798b011c962b602217b479130d413f3b30f19aLiejun Tao        mAbsVolThreshold = 0;
27011798b011c962b602217b479130d413f3b30f19aLiejun Tao        mVolumeMapping = new HashMap<Integer, Integer>();
271384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        mCurrAddrPlayerID = NO_PLAYER_ID;
27259b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        mReportedPlayerID = mCurrAddrPlayerID;
273294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen        mCurrBrowsePlayerID = 0;
274c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mContext = context;
275eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        mLastUsedPlayerID = 0;
276e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAddressedMediaPlayer = null;
277c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
278c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        initNative();
279c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
280c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        mMediaSessionManager =
281c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
282c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
2832e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mAudioStreamMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
284c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        mVolumeStep = Math.max(AVRCP_BASE_VOLUME_STEP, AVRCP_MAX_VOL / mAudioStreamMax);
285e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
28611798b011c962b602217b479130d413f3b30f19aLiejun Tao        Resources resources = context.getResources();
28711798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (resources != null) {
288c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            mAbsVolThreshold =
289c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    resources.getInteger(R.integer.a2dp_absolute_volume_initial_threshold);
290241337c1482c484e1a3a5fb24bc642937ab1a47cPavlin Radoslavov
2915ef52da260f8b4c1baed22bceb2983a694bb022cJack He            // Update the threshold if the thresholdPercent is valid
2925ef52da260f8b4c1baed22bceb2983a694bb022cJack He            int thresholdPercent =
293241337c1482c484e1a3a5fb24bc642937ab1a47cPavlin Radoslavov                    resources.getInteger(R.integer.a2dp_absolute_volume_initial_threshold_percent);
2945ef52da260f8b4c1baed22bceb2983a694bb022cJack He            if (thresholdPercent >= 0 && thresholdPercent <= 100) {
2955ef52da260f8b4c1baed22bceb2983a694bb022cJack He                mAbsVolThreshold = (thresholdPercent * mAudioStreamMax) / 100;
296241337c1482c484e1a3a5fb24bc642937ab1a47cPavlin Radoslavov            }
29711798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
298e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
299e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // Register for package removal intent broadcasts for media button receiver persistence
300e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        IntentFilter pkgFilter = new IntentFilter();
301e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
302e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
303e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
304e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
305e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addDataScheme("package");
306e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        context.registerReceiver(mAvrcpReceiver, pkgFilter);
3070427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker
3080427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        IntentFilter bootFilter = new IntentFilter();
3099c2ff5bb5082c653ee91d336dcd7f95e4c25e833Ajay Panicker        bootFilter.addAction(Intent.ACTION_USER_UNLOCKED);
3100427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        context.registerReceiver(mBootReceiver, bootFilter);
311c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
312c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
3139a5f80a6528d76153a7e97821f114f3370df89a5Marie Janssen    private synchronized void start() {
314c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler");
315c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        thread.start();
316c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Looper looper = thread.getLooper();
317c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler = new AvrcpMessageHandler(looper);
318a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov        mAudioManagerPlaybackHandler = new Handler(looper);
319a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov        mAudioManagerPlaybackCb = new AudioManagerPlaybackListener();
3209d4035307b85e78f10fba961e225ca09bfb7d0c7Jakub Pawlowski        mMediaControllerCb = new MediaControllerListener();
321e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAvrcpMediaRsp = new AvrcpMediaRsp();
322eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        mMediaPlayerInfoList = new TreeMap<Integer, MediaPlayerInfo>();
323f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen        mAvailablePlayerViewChanged = false;
3245146bd27869df5473aa53e6271266f51733971efMarie Janssen        mBrowsePlayerInfoList = Collections.synchronizedList(new ArrayList<BrowsePlayerInfo>());
32505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        mPassthroughDispatched = 0;
32605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        mPassthroughLogs = new EvictingQueue<MediaKeyLog>(PASSTHROUGH_LOG_MAX_SIZE);
32778d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        mPassthroughPending = Collections.synchronizedList(new ArrayList<MediaKeyLog>());
328f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen        if (mMediaSessionManager != null) {
329f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen            mMediaSessionManager.addOnActiveSessionsChangedListener(mActiveSessionListener, null,
330f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen                    mHandler);
33105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mMediaSessionManager.setCallback(mButtonDispatchCallback, null);
332f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen        }
333e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mPackageManager = mContext.getApplicationContext().getPackageManager();
334e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
335e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* create object to communicate with addressed player */
336e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAddressedMediaPlayer = new AddressedMediaPlayer(mAvrcpMediaRsp);
337e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
338e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* initialize BrowseMananger which manages Browse commands and response */
339e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAvrcpBrowseManager = new AvrcpBrowseManager(mContext, mAvrcpMediaRsp);
3400427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker
34105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        initMediaPlayersList();
34211bf73ff614f48a41dc379763bc007f271197b26Ajay Panicker
3430427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        UserManager manager = UserManager.get(mContext);
3440427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        if (manager == null || manager.isUserUnlocked()) {
345c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
346c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.d(TAG, "User already unlocked, initializing player lists");
347c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
3483843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            // initialize browsable player list and build media player list
349754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker            buildBrowsablePlayerList();
3500427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        }
351a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov
352c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        mAudioManager.registerAudioPlaybackCallback(mAudioManagerPlaybackCb,
353c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                mAudioManagerPlaybackHandler);
354c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
355c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
356066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    public static Avrcp make(Context context) {
357c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
358c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.v(TAG, "make");
359c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
360c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Avrcp ar = new Avrcp(context);
361c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ar.start();
362c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return ar;
363c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
364c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
3659a5f80a6528d76153a7e97821f114f3370df89a5Marie Janssen    public synchronized void doQuit() {
366c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
367c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, "doQuit");
368c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
369a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov        if (mAudioManager != null) {
370a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            mAudioManager.unregisterAudioPlaybackCallback(mAudioManagerPlaybackCb);
371a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov        }
372c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (mMediaController != null) {
373c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            mMediaController.unregisterCallback(mMediaControllerCb);
374c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
3757c7cc128e93e7e1db8a5ed7f69583ddc6d99493eMarie Janssen        if (mMediaSessionManager != null) {
3767c7cc128e93e7e1db8a5ed7f69583ddc6d99493eMarie Janssen            mMediaSessionManager.setCallback(null, null);
3777c7cc128e93e7e1db8a5ed7f69583ddc6d99493eMarie Janssen            mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveSessionListener);
3787c7cc128e93e7e1db8a5ed7f69583ddc6d99493eMarie Janssen        }
3797c7cc128e93e7e1db8a5ed7f69583ddc6d99493eMarie Janssen
380a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov        mAudioManagerPlaybackHandler.removeCallbacksAndMessages(null);
381c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.removeCallbacksAndMessages(null);
382c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Looper looper = mHandler.getLooper();
383ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        mHandler = null;
384c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (looper != null) {
385ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            looper.quitSafely();
386c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
387e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
388a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov        mAudioManagerPlaybackHandler = null;
389e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mContext.unregisterReceiver(mAvrcpReceiver);
3900427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        mContext.unregisterReceiver(mBootReceiver);
391e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
392e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAddressedMediaPlayer.cleanup();
393e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAvrcpBrowseManager.cleanup();
394c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
395c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
396c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    public void cleanup() {
397c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
398c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, "cleanup");
399c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
400c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        cleanupNative();
401c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (mVolumeMapping != null) {
40211798b011c962b602217b479130d413f3b30f19aLiejun Tao            mVolumeMapping.clear();
403c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
404c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
405c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
406a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov    private class AudioManagerPlaybackListener extends AudioManager.AudioPlaybackCallback {
407a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov        @Override
408a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov        public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
409a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            super.onPlaybackConfigChanged(configs);
410a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            boolean isPlaying = false;
411a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            for (AudioPlaybackConfiguration config : configs) {
412a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov                if (DEBUG) {
413c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.d(TAG, "AudioManager Player: "
414c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            + AudioPlaybackConfiguration.toLogFriendlyString(config));
415a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov                }
416a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov                if (config.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
417a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov                    isPlaying = true;
418a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov                    break;
419a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov                }
420a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            }
421c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
422c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.d(TAG, "AudioManager isPlaying: " + isPlaying);
423c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
424a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            if (mAudioManagerIsPlaying != isPlaying) {
425a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov                mAudioManagerIsPlaying = isPlaying;
426a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov                updateCurrentMediaState();
427a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            }
428a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov        }
429a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov    }
430a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov
4310e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen    private class MediaControllerListener extends MediaController.Callback {
4320e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        @Override
4330e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        public void onMetadataChanged(MediaMetadata metadata) {
434c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
435c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.v(TAG, "onMetadataChanged");
436c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
43785aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            updateCurrentMediaState();
438c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
439c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
440bc10e7d58aa55da25c18d8056a0254a2b736146aZhihai Xu        @Override
441e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public synchronized void onPlaybackStateChanged(PlaybackState state) {
442c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
443c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.v(TAG, "onPlaybackStateChanged: state " + state.toString());
444c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
445cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker
44685aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            updateCurrentMediaState();
447c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
448c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
449c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
4500e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        public void onSessionDestroyed() {
4510e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            Log.v(TAG, "MediaController session destroyed");
452ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen            synchronized (Avrcp.this) {
453c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (mMediaController != null) {
454ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                    removeMediaController(mMediaController.getWrappedInstance());
455c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
456384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            }
457c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
458c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
459c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
460e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void onQueueChanged(List<MediaSession.QueueItem> queue) {
461e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (queue == null) {
462e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.v(TAG, "onQueueChanged: received null queue");
463e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return;
464e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
4652b903c7262c9b8c0493e36b93b37831e7e075bfcMarie Janssen
466ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            final AvrcpMessageHandler handler = mHandler;
467ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (handler == null) {
468ded973620f204f11f20d40928735a4d87e00afedHansong Zhang                if (DEBUG) Log.d(TAG, "onQueueChanged: mHandler is already null");
469ded973620f204f11f20d40928735a4d87e00afedHansong Zhang                return;
470ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            }
471ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
472ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            Log.v(TAG, "onQueueChanged: NowPlaying list changed, Queue Size = "
473ded973620f204f11f20d40928735a4d87e00afedHansong Zhang                    + queue.size());
474ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            handler.sendEmptyMessage(MSG_NOW_PLAYING_CHANGED_RSP);
475c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
476c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
477c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
478c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    /** Handles Avrcp messages. */
479c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private final class AvrcpMessageHandler extends Handler {
480c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        private AvrcpMessageHandler(Looper looper) {
481c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            super(looper);
482c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
483c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
484c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
485c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public void handleMessage(Message msg) {
486c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            switch (msg.what) {
487c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_GET_RC_FEATURES: {
488c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    String address = (String) msg.obj;
489c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    mFeatures = msg.arg1;
490c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    mFeatures = modifyRcFeatureFromBlacklist(mFeatures, address);
491c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
492c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG,
493c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                "MSG_NATIVE_REQ_GET_RC_FEATURES: address=" + address + ", features="
494c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                        + msg.arg1 + ", mFeatures=" + mFeatures);
495c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
496c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    mAudioManager.avrcpSupportsAbsoluteVolume(address, isAbsoluteVolumeSupported());
497c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    mLastLocalVolume = -1;
498c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    mRemoteVolume = -1;
499c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    mLocalVolume = -1;
500c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    mInitialRemoteVolume = -1;
501c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    mAddress = address;
502c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (mVolumeMapping != null) {
503c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        mVolumeMapping.clear();
504c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
505c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
506414480de643b551c1d2dd7db971cc24cff29a605Pavlin Radoslavov                }
50717675906064bb72fdcca75baa56cdf8bb8968d01John Du
508c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_GET_PLAY_STATUS: {
509c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    byte[] address = (byte[]) msg.obj;
510c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    int btstate = getBluetoothPlayState(mCurrentPlayState);
511c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    int length = (int) mMediaAttributes.getLength();
512c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    int position = (int) getPlayPosition();
513c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
514c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG,
515c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                "MSG_NATIVE_REQ_GET_PLAY_STATUS, responding with state " + btstate
516c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                        + " len " + length + " pos " + position);
517cc07ee436d00418ecc69ae3aace986f7fbf0823aMarie Janssen                    }
518c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    getPlayStatusRspNative(address, btstate, length, position);
519c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
520c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                }
521c1124a7c6679f612b80926a19084655f9a71580aMarie Janssen
522c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_GET_ELEM_ATTRS: {
523c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    String[] textArray;
524c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    AvrcpCmd.ElementAttrCmd elem = (AvrcpCmd.ElementAttrCmd) msg.obj;
525c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    byte numAttr = elem.mNumAttr;
526c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    int[] attrIds = elem.mAttrIDs;
527c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
528c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_NATIVE_REQ_GET_ELEM_ATTRS:numAttr=" + numAttr);
529c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
530c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    textArray = new String[numAttr];
531c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    StringBuilder responseDebug = new StringBuilder();
532c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    responseDebug.append("getElementAttr response: ");
533c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    for (int i = 0; i < numAttr; ++i) {
534c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        textArray[i] = mMediaAttributes.getString(attrIds[i]);
535c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        responseDebug.append("[" + attrIds[i] + "=");
536c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (attrIds[i] == AvrcpConstants.ATTRID_TITLE
537c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                || attrIds[i] == AvrcpConstants.ATTRID_ARTIST
538c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                || attrIds[i] == AvrcpConstants.ATTRID_ALBUM) {
539c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            responseDebug.append(Utils.ellipsize(textArray[i]) + "] ");
540c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        } else {
541c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            responseDebug.append(textArray[i] + "] ");
542c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
543c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
544c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.v(TAG, responseDebug.toString());
545c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    byte[] bdaddr = elem.mAddress;
546c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    getElementAttrRspNative(bdaddr, numAttr, attrIds, textArray);
547c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
548c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
549c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
550c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_REGISTER_NOTIFICATION:
551c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
552c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG,
553c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                "MSG_NATIVE_REQ_REGISTER_NOTIFICATION:event=" + msg.arg1 + " param="
554c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                        + msg.arg2);
555c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
556c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    processRegisterNotification((byte[]) msg.obj, msg.arg1, msg.arg2);
557c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
558e2619781c799435cf0273d381069c754c5f89a20Marie Janssen
559c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NOW_PLAYING_CHANGED_RSP:
560c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
561c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_NOW_PLAYING_CHANGED_RSP");
562c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
563c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    removeMessages(MSG_NOW_PLAYING_CHANGED_RSP);
564c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    updateCurrentMediaState();
565c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
566aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
567c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_PLAY_INTERVAL_TIMEOUT:
568c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    sendPlayPosNotificationRsp(false);
56911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
570c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
571c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_VOLUME_CHANGE:
572c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (!isAbsoluteVolumeSupported()) {
573c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (DEBUG) {
574c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            Log.v(TAG, "MSG_NATIVE_REQ_VOLUME_CHANGE ignored, not supported");
575c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
57617675906064bb72fdcca75baa56cdf8bb8968d01John Du                        break;
57717675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
578c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    byte absVol = (byte) ((byte) msg.arg1 & 0x7f); // discard MSB as it is RFD
579c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
580c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_NATIVE_REQ_VOLUME_CHANGE: volume=" + absVol + " ctype="
581c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                + msg.arg2);
582c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
58311798b011c962b602217b479130d413f3b30f19aLiejun Tao
584c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (msg.arg2 == AVRC_RSP_ACCEPT || msg.arg2 == AVRC_RSP_REJ) {
585ff77fb7108403626cfd2a8b0c90601e431a5dc09Ajay Panicker                        if (!mVolCmdSetInProgress) {
586c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            Log.e(TAG, "Unsolicited response, ignored");
587c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            break;
588c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
589c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        removeMessages(MSG_ABS_VOL_TIMEOUT);
59011798b011c962b602217b479130d413f3b30f19aLiejun Tao
591c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        mVolCmdSetInProgress = false;
592c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        mAbsVolRetryTimes = 0;
593c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
594c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
595c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    // convert remote volume to local volume
596c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    int volIndex = convertToAudioStreamVolume(absVol);
597c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (mInitialRemoteVolume == -1) {
598c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        mInitialRemoteVolume = absVol;
599c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (mAbsVolThreshold > 0 && mAbsVolThreshold < mAudioStreamMax
600c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                && volIndex > mAbsVolThreshold) {
601c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            if (DEBUG) {
602c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                Log.v(TAG, "remote inital volume too high " + volIndex + ">"
603c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                        + mAbsVolThreshold);
604c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            }
605ded973620f204f11f20d40928735a4d87e00afedHansong Zhang                            Message msg1 = this.obtainMessage(MSG_SET_ABSOLUTE_VOLUME,
606c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                    mAbsVolThreshold, 0);
607ded973620f204f11f20d40928735a4d87e00afedHansong Zhang                            this.sendMessage(msg1);
608c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            mRemoteVolume = absVol;
609c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            mLocalVolume = volIndex;
610c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            break;
611c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
61211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
61311798b011c962b602217b479130d413f3b30f19aLiejun Tao
614c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (mLocalVolume != volIndex && (msg.arg2 == AVRC_RSP_ACCEPT
615c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            || msg.arg2 == AVRC_RSP_CHANGED || msg.arg2 == AVRC_RSP_INTERIM)) {
61611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    /* If the volume has successfully changed */
617c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        mLocalVolume = volIndex;
618c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (mLastLocalVolume != -1 && msg.arg2 == AVRC_RSP_ACCEPT) {
619c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            if (mLastLocalVolume != volIndex) {
62011798b011c962b602217b479130d413f3b30f19aLiejun Tao                            /* remote volume changed more than requested due to
62111798b011c962b602217b479130d413f3b30f19aLiejun Tao                             * local and remote has different volume steps */
622c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                if (DEBUG) {
623c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                    Log.d(TAG,
624c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                            "Remote returned volume does not match desired volume "
625c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                                    + mLastLocalVolume + " vs " + volIndex);
626c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                }
627c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                mLastLocalVolume = mLocalVolume;
628c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            }
62911798b011c962b602217b479130d413f3b30f19aLiejun Tao                        }
63011798b011c962b602217b479130d413f3b30f19aLiejun Tao
631c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        notifyVolumeChanged(mLocalVolume);
632c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        mRemoteVolume = absVol;
633c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        long pecentVolChanged = ((long) absVol * 100) / 0x7f;
634c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.e(TAG, "percent volume changed: " + pecentVolChanged + "%");
635c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    } else if (msg.arg2 == AVRC_RSP_REJ) {
636c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.e(TAG, "setAbsoluteVolume call rejected");
63717675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
63811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
63911798b011c962b602217b479130d413f3b30f19aLiejun Tao
640c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_SET_ABSOLUTE_VOLUME:
641c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (!isAbsoluteVolumeSupported()) {
642c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (DEBUG) {
643c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            Log.v(TAG, "ignore MSG_SET_ABSOLUTE_VOLUME");
644c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
645c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        break;
646c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
64711798b011c962b602217b479130d413f3b30f19aLiejun Tao
648c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
649c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_SET_ABSOLUTE_VOLUME");
650c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
65111798b011c962b602217b479130d413f3b30f19aLiejun Tao
652ff77fb7108403626cfd2a8b0c90601e431a5dc09Ajay Panicker                    if (mVolCmdSetInProgress) {
653c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (DEBUG) {
654c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            Log.w(TAG, "There is already a volume command in progress.");
655c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
656c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        break;
657c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
65811798b011c962b602217b479130d413f3b30f19aLiejun Tao
659c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    // Remote device didn't set initial volume. Let's black list it
660c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (mInitialRemoteVolume == -1) {
661c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (DEBUG) {
662c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            Log.d(TAG, "remote " + mAddress
663c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                    + " never tell us initial volume, black list it.");
664c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
665fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov                        blackListCurrentDevice("MSG_SET_ABSOLUTE_VOLUME");
666c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        break;
667c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
66817675906064bb72fdcca75baa56cdf8bb8968d01John Du
669c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    int avrcpVolume = convertToAvrcpVolume(msg.arg1);
670c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    avrcpVolume = Math.min(AVRCP_MAX_VOL, Math.max(0, avrcpVolume));
671c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
672c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.d(TAG, "Setting volume to " + msg.arg1 + "-" + avrcpVolume);
673c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
674c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (setVolumeNative(avrcpVolume)) {
675e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
67611798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mVolCmdSetInProgress = true;
677c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        mLastRemoteVolume = avrcpVolume;
678c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        mLastLocalVolume = msg.arg1;
679c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    } else {
680c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (DEBUG) {
681c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            Log.d(TAG, "setVolumeNative failed");
682c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
68317675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
684c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
68517675906064bb72fdcca75baa56cdf8bb8968d01John Du
686c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_ABS_VOL_TIMEOUT:
687c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
688c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_ABS_VOL_TIMEOUT: Volume change cmd timed out.");
689c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
690c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    mVolCmdSetInProgress = false;
691c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (mAbsVolRetryTimes >= MAX_ERROR_RETRY_TIMES) {
692c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        mAbsVolRetryTimes = 0;
693c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    /* too many volume change failures, black list the device */
694fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov                        blackListCurrentDevice("MSG_ABS_VOL_TIMEOUT");
695c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    } else {
696c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        mAbsVolRetryTimes += 1;
697c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (setVolumeNative(mLastRemoteVolume)) {
698c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT),
699c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                    CMD_TIMEOUT_DELAY);
700c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            mVolCmdSetInProgress = true;
701c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
702c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
703c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
704e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
705c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_SET_A2DP_AUDIO_STATE:
706c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
707c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_SET_A2DP_AUDIO_STATE:" + msg.arg1);
708c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
709c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    mA2dpState = msg.arg1;
710c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    updateCurrentMediaState();
711c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
712c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
713c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_GET_FOLDER_ITEMS: {
714c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    AvrcpCmd.FolderItemsCmd folderObj = (AvrcpCmd.FolderItemsCmd) msg.obj;
715c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
716c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_NATIVE_REQ_GET_FOLDER_ITEMS " + folderObj);
717c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
718c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    switch (folderObj.mScope) {
719c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        case AvrcpConstants.BTRC_SCOPE_PLAYER_LIST:
720c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            handleMediaPlayerListRsp(folderObj);
721c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            break;
722c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        case AvrcpConstants.BTRC_SCOPE_FILE_SYSTEM:
723c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        case AvrcpConstants.BTRC_SCOPE_NOW_PLAYING:
724c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            handleGetFolderItemBrowseResponse(folderObj, folderObj.mAddress);
725c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            break;
726c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        default:
727c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            Log.e(TAG, "unknown scope for getfolderitems. scope = "
728c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                    + folderObj.mScope);
729c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            getFolderItemsRspNative(folderObj.mAddress,
730c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                    AvrcpConstants.RSP_INV_SCOPE, (short) 0, (byte) 0, 0, null,
731c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                    null, null, null, null, null, null, null);
732c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
733c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
734e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
735e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
736c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_SET_ADDR_PLAYER:
737c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    // object is bdaddr, argument 1 is the selected player id
738c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
739c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_NATIVE_REQ_SET_ADDR_PLAYER id=" + msg.arg1);
740c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
741c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    setAddressedPlayer((byte[]) msg.obj, msg.arg1);
742c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
743e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
744c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_GET_ITEM_ATTR:
745c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    // msg object contains the item attribute object
746c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    AvrcpCmd.ItemAttrCmd cmd = (AvrcpCmd.ItemAttrCmd) msg.obj;
747c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
748c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_NATIVE_REQ_GET_ITEM_ATTR " + cmd);
749c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
750c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    handleGetItemAttr(cmd);
751c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
752e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
753c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_SET_BR_PLAYER:
754c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    // argument 1 is the selected player id
755c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
756c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_NATIVE_REQ_SET_BR_PLAYER id=" + msg.arg1);
757c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
758c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    setBrowsedPlayer((byte[]) msg.obj, msg.arg1);
759c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
760e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
761c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_CHANGE_PATH: {
762c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
763c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_NATIVE_REQ_CHANGE_PATH");
764c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
765c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Bundle data = msg.getData();
766c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    byte[] bdaddr = data.getByteArray("BdAddress");
767c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    byte[] folderUid = data.getByteArray("folderUid");
768c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    byte direction = data.getByte("direction");
769c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) {
770c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr)
771c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                .changePath(folderUid, direction);
772c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    } else {
773c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.e(TAG, "Remote requesting change path before setbrowsedplayer");
774c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        changePathRspNative(bdaddr, AvrcpConstants.RSP_BAD_CMD, 0);
775c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
776c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
777e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
778e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
779c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_PLAY_ITEM: {
780c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Bundle data = msg.getData();
781c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    byte[] bdaddr = data.getByteArray("BdAddress");
782c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    byte[] uid = data.getByteArray("uid");
783c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    byte scope = data.getByte("scope");
784c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
785c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_NATIVE_REQ_PLAY_ITEM scope=" + scope + " id="
786c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                + Utils.byteArrayToString(uid));
787c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
788c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    handlePlayItemResponse(bdaddr, uid, scope);
789c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
790c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
791e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
792c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS:
793c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
794c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS scope=" + msg.arg1);
795c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
796c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    // argument 1 is scope, object is bdaddr
797c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    handleGetTotalNumOfItemsResponse((byte[]) msg.obj, (byte) msg.arg1);
798c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
799e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
800c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                case MSG_NATIVE_REQ_PASS_THROUGH:
801c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
802c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG,
803c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                "MSG_NATIVE_REQ_PASS_THROUGH: id=" + msg.arg1 + " st=" + msg.arg2);
804c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
805c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    // argument 1 is id, argument 2 is keyState
806c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    handlePassthroughCmd(msg.arg1, msg.arg2);
807c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
808e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
809c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                default:
810c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.e(TAG, "unknown message! msg.what=" + msg.what);
811c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    break;
812c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
813c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
814c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
815c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
81659b1c77f883bd97816332046a3a98be4431cceddMarie Janssen    private PlaybackState updatePlaybackState() {
817c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        PlaybackState newState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE,
818c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build();
81959b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        synchronized (this) {
82059b1c77f883bd97816332046a3a98be4431cceddMarie Janssen            PlaybackState controllerState = null;
82159b1c77f883bd97816332046a3a98be4431cceddMarie Janssen            if (mMediaController != null) {
82259b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                controllerState = mMediaController.getPlaybackState();
82359b1c77f883bd97816332046a3a98be4431cceddMarie Janssen            }
82459b1c77f883bd97816332046a3a98be4431cceddMarie Janssen
82559b1c77f883bd97816332046a3a98be4431cceddMarie Janssen            if (controllerState != null) {
82659b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                newState = controllerState;
827a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            }
828a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            // Use the AudioManager to update the playback state.
829a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            // NOTE: We cannot use the
830a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            //    (mA2dpState == BluetoothA2dp.STATE_PLAYING)
831a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            // check, because after Pause, the A2DP state remains in
832a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            // STATE_PLAYING for 3 more seconds.
833a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            // As a result of that, if we pause the music, on carkits the
834a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            // Play status indicator will continue to display "Playing"
835a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov            // for 3 more seconds which can be confusing.
836c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if ((mAudioManagerIsPlaying && newState.getState() != PlaybackState.STATE_PLAYING) || (
837c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    controllerState == null && mAudioManager != null
838c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            && mAudioManager.isMusicActive())) {
839a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov                // Use AudioManager playback state if we don't have the state
840a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov                // from MediaControlller
84159b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                PlaybackState.Builder builder = new PlaybackState.Builder();
842a24231afabc31d1e7c903441108e19931d52a599Pavlin Radoslavov                if (mAudioManagerIsPlaying) {
84359b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                    builder.setState(PlaybackState.STATE_PLAYING,
84459b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                            PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f);
84559b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                } else {
84659b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                    builder.setState(PlaybackState.STATE_PAUSED,
84759b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                            PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f);
84859b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                }
84959b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                newState = builder.build();
85059b1c77f883bd97816332046a3a98be4431cceddMarie Janssen            }
8510e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        }
852f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
85359b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        byte newPlayStatus = getBluetoothPlayState(newState);
8540a429916782c20980e7f0893c503c633b8341f88Marie Janssen
85559b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        /* update play status in global media player list */
8560a429916782c20980e7f0893c503c633b8341f88Marie Janssen        MediaPlayerInfo player = getAddressedPlayerInfo();
8570a429916782c20980e7f0893c503c633b8341f88Marie Janssen        if (player != null) {
85859b1c77f883bd97816332046a3a98be4431cceddMarie Janssen            player.setPlayStatus(newPlayStatus);
8590a429916782c20980e7f0893c503c633b8341f88Marie Janssen        }
8600a429916782c20980e7f0893c503c633b8341f88Marie Janssen
861fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        if (DEBUG) {
86259b1c77f883bd97816332046a3a98be4431cceddMarie Janssen            Log.v(TAG, "updatePlaybackState (" + mPlayStatusChangedNT + "): " + mReportedPlayStatus
863c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    + "➡" + newPlayStatus + "(" + newState + ")");
864fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        }
865fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen
866c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (newState != null) {
867c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            mCurrentPlayState = newState;
868c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
869aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
87059b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        return mCurrentPlayState;
87159b1c77f883bd97816332046a3a98be4431cceddMarie Janssen    }
87259b1c77f883bd97816332046a3a98be4431cceddMarie Janssen
87359b1c77f883bd97816332046a3a98be4431cceddMarie Janssen    private void sendPlaybackStatus(int playStatusChangedNT, byte playbackState) {
87459b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        registerNotificationRspPlayStatusNative(playStatusChangedNT, playbackState);
87559b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        mPlayStatusChangedNT = playStatusChangedNT;
87659b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        mReportedPlayStatus = playbackState;
877c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
878c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
879c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void updateTransportControls(int transportControlFlags) {
880c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mTransportControlFlags = transportControlFlags;
881c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
882c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
8833b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen    class MediaAttributes {
8848bc413b0b749ea9df59e858493273e05087fe887Jack He        private boolean mExists;
8858bc413b0b749ea9df59e858493273e05087fe887Jack He        private String mTitle;
8868bc413b0b749ea9df59e858493273e05087fe887Jack He        private String mArtistName;
8878bc413b0b749ea9df59e858493273e05087fe887Jack He        private String mAlbumName;
8888bc413b0b749ea9df59e858493273e05087fe887Jack He        private String mMediaNumber;
8898bc413b0b749ea9df59e858493273e05087fe887Jack He        private String mMediaTotalNumber;
8908bc413b0b749ea9df59e858493273e05087fe887Jack He        private String mGenre;
8918bc413b0b749ea9df59e858493273e05087fe887Jack He        private long mPlayingTimeMs;
8923b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
8933b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_TITLE = 1;
8943b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_ARTIST_NAME = 2;
8953b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_ALBUM_NAME = 3;
8963b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_MEDIA_NUMBER = 4;
8973b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_MEDIA_TOTAL_NUMBER = 5;
8983b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_GENRE = 6;
8993b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_PLAYING_TIME_MS = 7;
9003b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9013b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
902d04c0a8609b39f891d5787f051b1dfb105ceee93Jack He        MediaAttributes(MediaMetadata data) {
9038bc413b0b749ea9df59e858493273e05087fe887Jack He            mExists = data != null;
904c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (!mExists) {
9053b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return;
906c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
9073b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9088bc413b0b749ea9df59e858493273e05087fe887Jack He            mArtistName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ARTIST));
9098bc413b0b749ea9df59e858493273e05087fe887Jack He            mAlbumName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ALBUM));
9108bc413b0b749ea9df59e858493273e05087fe887Jack He            mMediaNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER));
911c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            mMediaTotalNumber =
912c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS));
9138bc413b0b749ea9df59e858493273e05087fe887Jack He            mGenre = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_GENRE));
9148bc413b0b749ea9df59e858493273e05087fe887Jack He            mPlayingTimeMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION);
9153b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9163b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            // Try harder for the title.
9178bc413b0b749ea9df59e858493273e05087fe887Jack He            mTitle = data.getString(MediaMetadata.METADATA_KEY_TITLE);
9183b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9198bc413b0b749ea9df59e858493273e05087fe887Jack He            if (mTitle == null) {
9203b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                MediaDescription desc = data.getDescription();
9213b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                if (desc != null) {
9223b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    CharSequence val = desc.getDescription();
923c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (val != null) {
9248bc413b0b749ea9df59e858493273e05087fe887Jack He                        mTitle = val.toString();
925c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
9263b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                }
9273b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            }
9283b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
929c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (mTitle == null) {
9308bc413b0b749ea9df59e858493273e05087fe887Jack He                mTitle = new String();
931c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
9323b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
9333b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9340a429916782c20980e7f0893c503c633b8341f88Marie Janssen        public long getLength() {
935c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (!mExists) {
936c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                return 0L;
937c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
9388bc413b0b749ea9df59e858493273e05087fe887Jack He            return mPlayingTimeMs;
9390a429916782c20980e7f0893c503c633b8341f88Marie Janssen        }
9400a429916782c20980e7f0893c503c633b8341f88Marie Janssen
9413b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        public boolean equals(MediaAttributes other) {
942c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (other == null) {
9433b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return false;
944c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
9453b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
946c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (mExists != other.mExists) {
9473b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return false;
948c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
9493b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
950c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (!mExists) {
9513b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return true;
952c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
9533b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9548bc413b0b749ea9df59e858493273e05087fe887Jack He            return (mTitle.equals(other.mTitle)) && (mArtistName.equals(other.mArtistName))
955c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    && (mAlbumName.equals(other.mAlbumName)) && (mMediaNumber.equals(
956c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    other.mMediaNumber)) && (mMediaTotalNumber.equals(other.mMediaTotalNumber))
9578bc413b0b749ea9df59e858493273e05087fe887Jack He                    && (mGenre.equals(other.mGenre)) && (mPlayingTimeMs == other.mPlayingTimeMs);
9583b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
9593b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9603b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        public String getString(int attrId) {
961c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (!mExists) {
9623b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return new String();
963c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
9643b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9653b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            switch (attrId) {
9663b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_TITLE:
9678bc413b0b749ea9df59e858493273e05087fe887Jack He                    return mTitle;
9683b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_ARTIST_NAME:
9698bc413b0b749ea9df59e858493273e05087fe887Jack He                    return mArtistName;
9703b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_ALBUM_NAME:
9718bc413b0b749ea9df59e858493273e05087fe887Jack He                    return mAlbumName;
9723b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_MEDIA_NUMBER:
9738bc413b0b749ea9df59e858493273e05087fe887Jack He                    return mMediaNumber;
9743b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_MEDIA_TOTAL_NUMBER:
9758bc413b0b749ea9df59e858493273e05087fe887Jack He                    return mMediaTotalNumber;
9763b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_GENRE:
9778bc413b0b749ea9df59e858493273e05087fe887Jack He                    return mGenre;
9783b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_PLAYING_TIME_MS:
9798bc413b0b749ea9df59e858493273e05087fe887Jack He                    return Long.toString(mPlayingTimeMs);
9803b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                default:
9813b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return new String();
9823b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            }
9833b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
9843b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9853b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String stringOrBlank(String s) {
9863b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            return s == null ? new String() : s;
9873b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
988c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
9893b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String longStringOrBlank(Long s) {
9903b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            return s == null ? new String() : s.toString();
991c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
992c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
9932fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
994c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public String toString() {
9958bc413b0b749ea9df59e858493273e05087fe887Jack He            if (!mExists) {
9963b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return "[MediaAttributes: none]";
997e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
9983b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9998bc413b0b749ea9df59e858493273e05087fe887Jack He            return "[MediaAttributes: " + mTitle + " - " + mAlbumName + " by " + mArtistName + " ("
10008bc413b0b749ea9df59e858493273e05087fe887Jack He                    + mPlayingTimeMs + " " + mMediaNumber + "/" + mMediaTotalNumber + ") " + mGenre
10010a429916782c20980e7f0893c503c633b8341f88Marie Janssen                    + "]";
1002c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1003cc07ee436d00418ecc69ae3aace986f7fbf0823aMarie Janssen
1004cc07ee436d00418ecc69ae3aace986f7fbf0823aMarie Janssen        public String toRedactedString() {
10058bc413b0b749ea9df59e858493273e05087fe887Jack He            if (!mExists) {
1006cc07ee436d00418ecc69ae3aace986f7fbf0823aMarie Janssen                return "[MediaAttributes: none]";
1007cc07ee436d00418ecc69ae3aace986f7fbf0823aMarie Janssen            }
1008cc07ee436d00418ecc69ae3aace986f7fbf0823aMarie Janssen
1009c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            return "[MediaAttributes: " + Utils.ellipsize(mTitle) + " - " + Utils.ellipsize(
1010c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    mAlbumName) + " by " + Utils.ellipsize(mArtistName) + " (" + mPlayingTimeMs
1011c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    + " " + mMediaNumber + "/" + mMediaTotalNumber + ") " + mGenre + "]";
1012cc07ee436d00418ecc69ae3aace986f7fbf0823aMarie Janssen        }
1013c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1014c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
101585aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker    private void updateCurrentMediaState() {
1016f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen        // Only do player updates when we aren't registering for track changes.
10175aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen        MediaAttributes currentAttributes;
101859b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        PlaybackState newState = updatePlaybackState();
101959b1c77f883bd97816332046a3a98be4431cceddMarie Janssen
1020ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen        synchronized (this) {
1021ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen            if (mMediaController == null) {
10225aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen                currentAttributes = new MediaAttributes(null);
1023c9f4e0d24e39b372452fa809b12f9c588b29abd9Marie Janssen            } else {
10245aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen                currentAttributes = new MediaAttributes(mMediaController.getMetadata());
10250a429916782c20980e7f0893c503c633b8341f88Marie Janssen            }
10260e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        }
1027e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1028cb00f2feb8405508707e41e463a79bf77eac7bc7Ajay Panicker        byte newPlayStatus = getBluetoothPlayState(newState);
1029cb00f2feb8405508707e41e463a79bf77eac7bc7Ajay Panicker
1030cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker        if (newState.getState() != PlaybackState.STATE_BUFFERING
1031cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker                && newState.getState() != PlaybackState.STATE_NONE) {
1032cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker            long newQueueId = MediaSession.QueueItem.UNKNOWN_ID;
1033c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (newState != null) {
1034c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                newQueueId = newState.getActiveQueueItemId();
1035c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
103606457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski            if (DEBUG) {
103706457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski                Log.v(TAG,
103806457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski                        "Media update: id " + mLastQueueId + "➡" + newQueueId + "? " + currentAttributes
103906457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski                                .toRedactedString() + " : " + mMediaAttributes.toRedactedString());
104006457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski            }
1041cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker
104285aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            if (mAvailablePlayerViewChanged) {
104385aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                registerNotificationRspAvalPlayerChangedNative(
104485aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                        AvrcpConstants.NOTIFICATION_TYPE_CHANGED);
104585aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                mAvailablePlayerViewChanged = false;
104685aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                return;
104785aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            }
104885aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker
104985aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            if (mAddrPlayerChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM
105085aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                    && mReportedPlayerID != mCurrAddrPlayerID) {
105185aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                registerNotificationRspAvalPlayerChangedNative(
105285aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                        AvrcpConstants.NOTIFICATION_TYPE_CHANGED);
105385aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                registerNotificationRspAddrPlayerChangedNative(
105485aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                        AvrcpConstants.NOTIFICATION_TYPE_CHANGED, mCurrAddrPlayerID, sUIDCounter);
105585aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker
105685aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                mAvailablePlayerViewChanged = false;
105785aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                mAddrPlayerChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
105885aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                mReportedPlayerID = mCurrAddrPlayerID;
105985aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker
106085aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                // Update the now playing list without sending the notification
106185aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                mNowPlayingListChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
106285aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                mAddressedMediaPlayer.updateNowPlayingList(mMediaController);
106385aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                mNowPlayingListChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
106485aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            }
106585aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker
1066cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker            // Dont send now playing list changed if the player doesn't support browsing
1067cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker            MediaPlayerInfo info = getAddressedPlayerInfo();
1068cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker            if (info != null && info.isBrowseSupported()) {
106906457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski                if (DEBUG) {
107006457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski                    Log.v(TAG, "Check if NowPlayingList is updated");
107106457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski                }
1072cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker                mAddressedMediaPlayer.updateNowPlayingList(mMediaController);
1073cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker            }
1074cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker
1075cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker            // Notify track changed if:
107685aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            //  - The CT is registered for the notification
1077cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker            //  - Queue ID is UNKNOWN and MediaMetadata is different
107885aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            //  - Queue ID is valid and different from last Queue ID sent
107985aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            if ((newQueueId == -1 || newQueueId != mLastQueueId)
108085aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                    && mTrackChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM
108185aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                    && !currentAttributes.equals(mMediaAttributes)
108285aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                    && newPlayStatus == PLAYSTATUS_PLAYING) {
1083cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker                Log.v(TAG, "Send track changed");
1084cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker                mMediaAttributes = currentAttributes;
1085cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker                mLastQueueId = newQueueId;
108685aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                sendTrackChangedRsp(false);
1087cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker            }
1088cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker        } else {
1089cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker            Log.i(TAG, "Skipping update due to invalid playback state");
1090c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1091cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker
1092cb00f2feb8405508707e41e463a79bf77eac7bc7Ajay Panicker        // still send the updated play state if the playback state is none or buffering
109306457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski        if (DEBUG) {
109406457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski            Log.v(TAG, "play status change " + mReportedPlayStatus + "➡" + newPlayStatus
109506457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski                    + " mPlayStatusChangedNT: " + mPlayStatusChangedNT);
109606457b672e7182b66230e9da553f261494b9bc03Jakub Pawlowski        }
1097c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (mPlayStatusChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM || (mReportedPlayStatus
1098c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                != newPlayStatus)) {
1099cb00f2feb8405508707e41e463a79bf77eac7bc7Ajay Panicker            sendPlaybackStatus(AvrcpConstants.NOTIFICATION_TYPE_CHANGED, newPlayStatus);
1100cb00f2feb8405508707e41e463a79bf77eac7bc7Ajay Panicker        }
1101cb00f2feb8405508707e41e463a79bf77eac7bc7Ajay Panicker
110259b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        sendPlayPosNotificationRsp(false);
1103c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1104c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1105e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void getRcFeaturesRequestFromNative(byte[] address, int features) {
1106ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1107ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1108ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "getRcFeaturesRequestFromNative: mHandler is already null");
1109ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1110ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1111ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1112ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_GET_RC_FEATURES, features, 0,
1113e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Utils.getAddressStringFromByte(address));
1114ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
111517675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
111617675906064bb72fdcca75baa56cdf8bb8968d01John Du
1117e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void getPlayStatusRequestFromNative(byte[] address) {
1118ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1119ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1120ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "getPlayStatusRequestFromNative: mHandler is already null");
1121ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1122ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1123ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1124ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_GET_PLAY_STATUS);
1125e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1126ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
1127c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1128c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
112989728a4d50001ac76d05efa1c916711ef9f9c2b4Marie Janssen    private void getElementAttrRequestFromNative(byte[] address, byte numAttr, int[] attrs) {
1130e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd avrcpCmdobj = new AvrcpCmd();
1131e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd.ElementAttrCmd elemAttr = avrcpCmdobj.new ElementAttrCmd(address, numAttr, attrs);
1132e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_ELEM_ATTRS);
1133e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = elemAttr;
1134c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
1135c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1136c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1137c4fbd756e2645147470c486ae96f2253f5e13a52Jack He    private void registerNotificationRequestFromNative(byte[] address, int eventId, int param) {
1138ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1139ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1140ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) {
1141ded973620f204f11f20d40928735a4d87e00afedHansong Zhang                Log.d(TAG, "registerNotificationRequestFromNative: mHandler is already null");
1142ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            }
1143ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1144ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1145ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_REGISTER_NOTIFICATION, eventId, param);
1146e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1147ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
1148c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1149c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1150e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void processRegisterNotification(byte[] address, int eventId, int param) {
1151c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        switch (eventId) {
1152c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case EVT_PLAY_STATUS_CHANGED:
115359b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
115459b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                updatePlaybackState();
1155cb00f2feb8405508707e41e463a79bf77eac7bc7Ajay Panicker                sendPlaybackStatus(AvrcpConstants.NOTIFICATION_TYPE_INTERIM, mReportedPlayStatus);
1156c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1157c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1158c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case EVT_TRACK_CHANGED:
11590e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                Log.v(TAG, "Track changed notification enabled");
1160e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
1161cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker                sendTrackChangedRsp(true);
1162c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1163c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1164aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            case EVT_PLAY_POS_CHANGED:
1165e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
1166e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mPlaybackIntervalMs = (long) param * 1000L;
1167fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen                sendPlayPosNotificationRsp(true);
1168aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                break;
1169aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
1170e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVT_AVBL_PLAYERS_CHANGED:
1171e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                /* Notify remote available players changed */
1172c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
1173c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.d(TAG, "Available Players notification enabled");
1174c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
1175e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                registerNotificationRspAvalPlayerChangedNative(
1176e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        AvrcpConstants.NOTIFICATION_TYPE_INTERIM);
1177e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1178e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1179e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVT_ADDR_PLAYER_CHANGED:
1180e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                /* Notify remote addressed players changed */
1181c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
1182c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.d(TAG, "Addressed Player notification enabled");
1183c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
1184e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                registerNotificationRspAddrPlayerChangedNative(
1185c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        AvrcpConstants.NOTIFICATION_TYPE_INTERIM, mCurrAddrPlayerID, sUIDCounter);
118659b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                mAddrPlayerChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
118759b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                mReportedPlayerID = mCurrAddrPlayerID;
1188e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1189e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1190e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVENT_UIDS_CHANGED:
1191c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
1192c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.d(TAG, "UIDs changed notification enabled");
1193c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
1194c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                registerNotificationRspUIDsChangedNative(AvrcpConstants.NOTIFICATION_TYPE_INTERIM,
1195c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        sUIDCounter);
1196e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1197e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1198e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVENT_NOW_PLAYING_CONTENT_CHANGED:
1199c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
1200c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.d(TAG, "Now Playing List changed notification enabled");
1201c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
1202e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                /* send interim response to remote device */
120305723ee9e6619814876a6cce5004d11b38c3f648Ajay Panicker                mNowPlayingListChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
1204e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!registerNotificationRspNowPlayingChangedNative(
1205e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        AvrcpConstants.NOTIFICATION_TYPE_INTERIM)) {
1206c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.e(TAG, "EVENT_NOW_PLAYING_CONTENT_CHANGED: "
1207c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            + "registerNotificationRspNowPlayingChangedNative for Interim rsp "
1208c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            + "failed!");
1209e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
1210e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1211c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1212c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1213c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1214e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handlePassthroughCmdRequestFromNative(byte[] address, int id, int keyState) {
1215ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1216ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1217ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) {
1218ded973620f204f11f20d40928735a4d87e00afedHansong Zhang                Log.d(TAG, "handlePassthroughCmdRequestFromNative: mHandler is already null");
1219ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            }
1220ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1221ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1222ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1223ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_PASS_THROUGH, id, keyState);
1224ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
1225ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
1226ace834feb02adabd61f628c4471147aea02d939cJohn Du
12275aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen    private void sendTrackChangedRsp(boolean registering) {
12285aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen        if (!registering && mTrackChangedNT != AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
1229c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
1230c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.d(TAG, "sendTrackChangedRsp: Not registered or registering.");
1231c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
12328ac88214fdbf5e5197033b89ba82a6bf728706a4Marie Janssen            return;
12338ac88214fdbf5e5197033b89ba82a6bf728706a4Marie Janssen        }
12345aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen
12355aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen        mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
1236c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (registering) {
1237c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
1238c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
12395aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen
12405aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen        MediaPlayerInfo info = getAddressedPlayerInfo();
12415aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen        // for non-browsable players or no player
1242eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        if (info != null && !info.isBrowseSupported()) {
12435aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen            byte[] track = AvrcpConstants.TRACK_IS_SELECTED;
1244c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (!mMediaAttributes.mExists) {
1245c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                track = AvrcpConstants.NO_TRACK_SELECTED;
1246c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
12475aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen            registerNotificationRspTrackChangeNative(mTrackChangedNT, track);
12485aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen            return;
1249e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou        }
1250e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou
12515aca05c1d79f3412b6964b3b6335ad6f2d558756Marie Janssen        mAddressedMediaPlayer.sendTrackChangeWithId(mTrackChangedNT, mMediaController);
1252c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1253c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1254aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long getPlayPosition() {
1255e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (mCurrentPlayState == null) {
1256f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            return -1L;
1257e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1258f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1259e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (mCurrentPlayState.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
1260f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            return -1L;
1261e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1262f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1263f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        if (isPlayingState(mCurrentPlayState)) {
12640a429916782c20980e7f0893c503c633b8341f88Marie Janssen            long sinceUpdate =
12650a429916782c20980e7f0893c503c633b8341f88Marie Janssen                    (SystemClock.elapsedRealtime() - mCurrentPlayState.getLastPositionUpdateTime());
12660a429916782c20980e7f0893c503c633b8341f88Marie Janssen            return sinceUpdate + mCurrentPlayState.getPosition();
1267aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        }
1268f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
12693635a926bd7316a55b288a54d409a1070a9c19e8Marie Janssen        return mCurrentPlayState.getPosition();
1270aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    }
1271aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
127259b1c77f883bd97816332046a3a98be4431cceddMarie Janssen    private boolean isPlayingState(@Nullable PlaybackState state) {
1273c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (state == null) {
1274c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            return false;
1275c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
1276cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker        return (state != null) && (state.getState() == PlaybackState.STATE_PLAYING);
1277188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
1278188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
127917675906064bb72fdcca75baa56cdf8bb8968d01John Du    /**
1280f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * Sends a play position notification, or schedules one to be
1281f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * sent later at an appropriate time. If |requested| is true,
1282f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * does both because this was called in reponse to a request from the
1283f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * TG.
1284f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     */
1285f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    private void sendPlayPosNotificationRsp(boolean requested) {
1286e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!requested && mPlayPosChangedNT != AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
1287c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
1288c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.d(TAG, "sendPlayPosNotificationRsp: Not registered or requesting.");
1289c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
1290fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen            return;
1291fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        }
1292fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen
1293ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1294ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1295ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: handler is already null");
1296ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1297ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1298ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1299f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        long playPositionMs = getPlayPosition();
13000ace2d5941549e466ada4258c6c6fbb1debdf48dMarie Janssen        String debugLine = "sendPlayPosNotificationRsp: ";
1301f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1302f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // mNextPosMs is set to -1 when the previous position was invalid
1303f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // so this will be true if the new position is valid & old was invalid.
1304f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // mPlayPositionMs is set to -1 when the new position is invalid,
1305f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // and the old mPrevPosMs is >= 0 so this is true when the new is invalid
1306f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // and the old was valid.
13070ace2d5941549e466ada4258c6c6fbb1debdf48dMarie Janssen        if (DEBUG) {
13080ace2d5941549e466ada4258c6c6fbb1debdf48dMarie Janssen            debugLine += "(" + requested + ") " + mPrevPosMs + " <=? " + playPositionMs + " <=? "
13090ace2d5941549e466ada4258c6c6fbb1debdf48dMarie Janssen                    + mNextPosMs;
1310c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (isPlayingState(mCurrentPlayState)) {
1311c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                debugLine += " Playing";
1312c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
13130ace2d5941549e466ada4258c6c6fbb1debdf48dMarie Janssen            debugLine += " State: " + mCurrentPlayState.getState();
13140ace2d5941549e466ada4258c6c6fbb1debdf48dMarie Janssen        }
1315c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (requested || (
1316c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                (mLastReportedPosition != playPositionMs) && (playPositionMs >= mNextPosMs) || (
1317c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        playPositionMs <= mPrevPosMs))) {
1318c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (!requested) {
1319c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
1320c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
1321e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int) playPositionMs);
1322fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen            mLastReportedPosition = playPositionMs;
1323f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            if (playPositionMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
1324f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mNextPosMs = playPositionMs + mPlaybackIntervalMs;
1325f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mPrevPosMs = playPositionMs - mPlaybackIntervalMs;
1326f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            } else {
1327f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mNextPosMs = -1;
1328f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mPrevPosMs = -1;
1329f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            }
1330f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        }
1331f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1332ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.removeMessages(MSG_PLAY_INTERVAL_TIMEOUT);
1333c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (mPlayPosChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM && isPlayingState(
1334c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                mCurrentPlayState)) {
1335ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            Message msg = handler.obtainMessage(MSG_PLAY_INTERVAL_TIMEOUT);
1336f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            long delay = mPlaybackIntervalMs;
1337f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            if (mNextPosMs != -1) {
1338f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                delay = mNextPosMs - (playPositionMs > 0 ? playPositionMs : 0);
1339f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            }
1340c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
1341c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                debugLine += " Timeout " + delay + "ms";
1342c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
1343ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            handler.sendMessageDelayed(msg, delay);
1344f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        }
1345c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
1346c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, debugLine);
1347c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
1348f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    }
1349f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1350f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    /**
135117675906064bb72fdcca75baa56cdf8bb8968d01John Du     * This is called from AudioService. It will return whether this device supports abs volume.
135217675906064bb72fdcca75baa56cdf8bb8968d01John Du     * NOT USED AT THE MOMENT.
135317675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
135417675906064bb72fdcca75baa56cdf8bb8968d01John Du    public boolean isAbsoluteVolumeSupported() {
135517675906064bb72fdcca75baa56cdf8bb8968d01John Du        return ((mFeatures & BTRC_FEAT_ABSOLUTE_VOLUME) != 0);
135617675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
135717675906064bb72fdcca75baa56cdf8bb8968d01John Du
135817675906064bb72fdcca75baa56cdf8bb8968d01John Du    /**
135917675906064bb72fdcca75baa56cdf8bb8968d01John Du     * We get this call from AudioService. This will send a message to our handler object,
136017675906064bb72fdcca75baa56cdf8bb8968d01John Du     * requesting our handler to call setVolumeNative()
136117675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
136217675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void setAbsoluteVolume(int volume) {
136311798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (volume == mLocalVolume) {
1364c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
1365c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.v(TAG, "setAbsoluteVolume is setting same index, ignore " + volume);
1366c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
136711798b011c962b602217b479130d413f3b30f19aLiejun Tao            return;
136811798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
136911798b011c962b602217b479130d413f3b30f19aLiejun Tao
1370ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1371ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1372ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "setAbsoluteVolume: mHandler is already null");
1373ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1374ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1375ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1376ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_SET_ABSOLUTE_VOLUME, volume, 0);
1377ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
13785c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta    }
13795c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta
138017675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* Called in the native layer as a btrc_callback to return the volume set on the carkit in the
138117675906064bb72fdcca75baa56cdf8bb8968d01John Du     * case when the volume is change locally on the carkit. This notification is not called when
138217675906064bb72fdcca75baa56cdf8bb8968d01John Du     * the volume is changed from the phone.
138317675906064bb72fdcca75baa56cdf8bb8968d01John Du     *
138417675906064bb72fdcca75baa56cdf8bb8968d01John Du     * This method will send a message to our handler to change the local stored volume and notify
138517675906064bb72fdcca75baa56cdf8bb8968d01John Du     * AudioService to update the UI
138617675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
1387e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void volumeChangeRequestFromNative(byte[] address, int volume, int ctype) {
1388ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1389ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1390ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "volumeChangeRequestFromNative: mHandler is already null");
1391ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1392ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1393ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1394ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_VOLUME_CHANGE, volume, ctype);
1395e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1396c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        data.putByteArray("BdAddress", address);
1397e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.setData(data);
1398ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
1399e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1400e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1401c4fbd756e2645147470c486ae96f2253f5e13a52Jack He    private void getFolderItemsRequestFromNative(byte[] address, byte scope, long startItem,
1402c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            long endItem, byte numAttr, int[] attrIds) {
1403ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1404ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1405ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "getFolderItemsRequestFromNative: mHandler is already null");
1406ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1407ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1408e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd avrcpCmdobj = new AvrcpCmd();
1409c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        AvrcpCmd.FolderItemsCmd folderObj =
1410c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                avrcpCmdobj.new FolderItemsCmd(address, scope, startItem, endItem, numAttr,
1411c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        attrIds);
1412ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_GET_FOLDER_ITEMS, 0, 0);
1413e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = folderObj;
1414ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
1415e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1416e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1417e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setAddressedPlayerRequestFromNative(byte[] address, int playerId) {
1418ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1419ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1420ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "setAddressedPlayerRequestFromNative: mHandler is already null");
1421ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1422ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1423ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1424ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_SET_ADDR_PLAYER, playerId, 0);
1425e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1426ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
1427e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1428e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1429e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setBrowsedPlayerRequestFromNative(byte[] address, int playerId) {
1430ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1431ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1432ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "setBrowsedPlayerRequestFromNative: mHandler is already null");
1433ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1434ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1435ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1436ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_SET_BR_PLAYER, playerId, 0);
1437e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1438ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
1439e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1440e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1441e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void changePathRequestFromNative(byte[] address, byte direction, byte[] folderUid) {
1442ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1443ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1444ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "changePathRequestFromNative: mHandler is already null");
1445ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1446ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1447ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1448e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1449ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_CHANGE_PATH);
1450c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        data.putByteArray("BdAddress", address);
1451c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        data.putByteArray("folderUid", folderUid);
1452c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        data.putByte("direction", direction);
1453e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.setData(data);
1454ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
1455e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1456e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1457c4fbd756e2645147470c486ae96f2253f5e13a52Jack He    private void getItemAttrRequestFromNative(byte[] address, byte scope, byte[] itemUid,
1458c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            int uidCounter, byte numAttr, int[] attrs) {
1459ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1460ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1461ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "getItemAttrRequestFromNative: mHandler is already null");
1462ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1463ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1464e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd avrcpCmdobj = new AvrcpCmd();
1465c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        AvrcpCmd.ItemAttrCmd itemAttr =
1466c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                avrcpCmdobj.new ItemAttrCmd(address, scope, itemUid, uidCounter, numAttr, attrs);
1467ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_GET_ITEM_ATTR);
1468e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = itemAttr;
1469ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
1470e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1471e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1472e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void searchRequestFromNative(byte[] address, int charsetId, byte[] searchStr) {
1473e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Search is not supported */
1474e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen        Log.w(TAG, "searchRequestFromNative: search is not supported");
1475e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        searchRspNative(address, AvrcpConstants.RSP_SRCH_NOT_SPRTD, 0, 0);
1476e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1477e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1478e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void playItemRequestFromNative(byte[] address, byte scope, int uidCounter, byte[] uid) {
1479ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1480ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1481ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "playItemRequestFromNative: mHandler is already null");
1482ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1483ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1484ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1485e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1486ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_PLAY_ITEM);
1487c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        data.putByteArray("BdAddress", address);
1488c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        data.putByteArray("uid", uid);
1489c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        data.putInt("uidCounter", uidCounter);
1490c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        data.putByte("scope", scope);
1491ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1492e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.setData(data);
1493ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
1494e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1495e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1496c4fbd756e2645147470c486ae96f2253f5e13a52Jack He    private void addToPlayListRequestFromNative(byte[] address, byte scope, byte[] uid,
1497c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            int uidCounter) {
1498e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* add to NowPlaying not supported */
1499e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen        Log.w(TAG, "addToPlayListRequestFromNative: not supported! scope=" + scope);
1500e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        addToNowPlayingRspNative(address, AvrcpConstants.RSP_INTERNAL_ERR);
1501e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1502e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1503e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void getTotalNumOfItemsRequestFromNative(byte[] address, byte scope) {
1504ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1505ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1506ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "getTotalNumOfItemsRequestFromNative: mHandler is already null");
1507ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1508ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1509ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1510e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1511ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS);
1512e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.arg1 = scope;
1513e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1514ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
151517675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
151617675906064bb72fdcca75baa56cdf8bb8968d01John Du
15172e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private void notifyVolumeChanged(int volume) {
15182e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume,
1519c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
152017675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
152117675906064bb72fdcca75baa56cdf8bb8968d01John Du
152217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int convertToAudioStreamVolume(int volume) {
152317675906064bb72fdcca75baa56cdf8bb8968d01John Du        // Rescale volume to match AudioSystem's volume
1524c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        return (int) Math.floor((double) volume * mAudioStreamMax / AVRCP_MAX_VOL);
152517675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
152617675906064bb72fdcca75baa56cdf8bb8968d01John Du
152717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int convertToAvrcpVolume(int volume) {
1528c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        return (int) Math.ceil((double) volume * AVRCP_MAX_VOL / mAudioStreamMax);
152917675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
153017675906064bb72fdcca75baa56cdf8bb8968d01John Du
1531fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov    private void blackListCurrentDevice(String reason) {
153211798b011c962b602217b479130d413f3b30f19aLiejun Tao        mFeatures &= ~BTRC_FEAT_ABSOLUTE_VOLUME;
153311798b011c962b602217b479130d413f3b30f19aLiejun Tao        mAudioManager.avrcpSupportsAbsoluteVolume(mAddress, isAbsoluteVolumeSupported());
153411798b011c962b602217b479130d413f3b30f19aLiejun Tao
1535c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        SharedPreferences pref =
1536c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, Context.MODE_PRIVATE);
153711798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences.Editor editor = pref.edit();
1538fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov
1539fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov        StringBuilder sb = new StringBuilder();
1540fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov        sb.append("Time: ");
1541fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov        sb.append(android.text.format.DateFormat.format("yyyy/MM/dd HH:mm:ss",
1542fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov                                                        System.currentTimeMillis()));
1543fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov        sb.append(" Reason: ");
1544fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov        sb.append(reason);
1545fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov        editor.putString(mAddress, sb.toString());
15467eeb95b6f29a6f55e117e329468168d4bcbec0c8Jack He        editor.apply();
154711798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
154811798b011c962b602217b479130d413f3b30f19aLiejun Tao
154911798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int modifyRcFeatureFromBlacklist(int feature, String address) {
1550c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        SharedPreferences pref =
1551c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, Context.MODE_PRIVATE);
155211798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (!pref.contains(address)) {
155311798b011c962b602217b479130d413f3b30f19aLiejun Tao            return feature;
155411798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
1555fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov        return feature & ~BTRC_FEAT_ABSOLUTE_VOLUME;
155611798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
155711798b011c962b602217b479130d413f3b30f19aLiejun Tao
155811798b011c962b602217b479130d413f3b30f19aLiejun Tao    public void resetBlackList(String address) {
1559c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        SharedPreferences pref =
1560c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, Context.MODE_PRIVATE);
156111798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences.Editor editor = pref.edit();
156211798b011c962b602217b479130d413f3b30f19aLiejun Tao        editor.remove(address);
15637eeb95b6f29a6f55e117e329468168d4bcbec0c8Jack He        editor.apply();
156411798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
156511798b011c962b602217b479130d413f3b30f19aLiejun Tao
1566188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    /**
1567188f205b5f093850d4cc627917a21204be36c56aZhihai Xu     * This is called from A2dpStateMachine to set A2dp audio state.
1568188f205b5f093850d4cc627917a21204be36c56aZhihai Xu     */
1569188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    public void setA2dpAudioState(int state) {
1570ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        final AvrcpMessageHandler handler = mHandler;
1571ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        if (handler == null) {
1572ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            if (DEBUG) Log.d(TAG, "setA2dpAudioState: mHandler is already null");
1573ded973620f204f11f20d40928735a4d87e00afedHansong Zhang            return;
1574ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        }
1575ded973620f204f11f20d40928735a4d87e00afedHansong Zhang
1576ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        Message msg = handler.obtainMessage(MSG_SET_A2DP_AUDIO_STATE, state, 0);
1577ded973620f204f11f20d40928735a4d87e00afedHansong Zhang        handler.sendMessage(msg);
1578188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
1579188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
15800427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker    private class AvrcpServiceBootReceiver extends BroadcastReceiver {
15810427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        @Override
15820427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        public void onReceive(Context context, Intent intent) {
15830427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker            String action = intent.getAction();
15849c2ff5bb5082c653ee91d336dcd7f95e4c25e833Ajay Panicker            if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
1585c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
1586c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.d(TAG, "User unlocked, initializing player lists");
1587c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
15880427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker                /* initializing media player's list */
1589754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                buildBrowsablePlayerList();
15900427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker            }
15910427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        }
15920427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker    }
15930427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker
1594e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private class AvrcpServiceBroadcastReceiver extends BroadcastReceiver {
1595e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        @Override
1596e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void onReceive(Context context, Intent intent) {
1597e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String action = intent.getAction();
1598c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
1599c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.d(TAG, "AvrcpServiceBroadcastReceiver-> Action: " + action);
1600c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
1601e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1602c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (action.equals(Intent.ACTION_PACKAGE_REMOVED) || action.equals(
1603c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Intent.ACTION_PACKAGE_DATA_CLEARED)) {
1604e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1605e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    // a package is being removed, not replaced
1606e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    String packageName = intent.getData().getSchemeSpecificPart();
1607e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    if (packageName != null) {
1608e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        handlePackageModified(packageName, true);
1609e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    }
1610e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
1611e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1612c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) || action.equals(
1613c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Intent.ACTION_PACKAGE_CHANGED)) {
1614e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                String packageName = intent.getData().getSchemeSpecificPart();
1615c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
1616c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.d(TAG, "AvrcpServiceBroadcastReceiver-> packageName: " + packageName);
1617c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
1618e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (packageName != null) {
1619e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    handlePackageModified(packageName, false);
1620e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
1621e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1622e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1623838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    }
1624838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood
1625e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handlePackageModified(String packageName, boolean removed) {
1626c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
1627c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, "packageName: " + packageName + " removed: " + removed);
1628c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
1629c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1630e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (removed) {
1631384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            removeMediaPlayerInfo(packageName);
1632e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // old package is removed, updating local browsable player's list
1633e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (isBrowseSupported(packageName)) {
1634e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                removePackageFromBrowseList(packageName);
1635e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1636e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
1637e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // new package has been added.
1638e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (isBrowsableListUpdated(packageName)) {
1639e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                // Rebuilding browsable players list
1640754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                buildBrowsablePlayerList();
1641e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1642e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1643e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1644c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1645e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isBrowsableListUpdated(String newPackageName) {
1646e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // getting the browsable media players list from package manager
1647e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Intent intent = new Intent("android.media.browse.MediaBrowserService");
1648c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        List<ResolveInfo> resInfos =
1649c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                mPackageManager.queryIntentServices(intent, PackageManager.MATCH_ALL);
1650e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        for (ResolveInfo resolveInfo : resInfos) {
16513843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            if (resolveInfo.serviceInfo.packageName.equals(newPackageName)) {
1652c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
16533843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                    Log.d(TAG,
16543843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                            "isBrowsableListUpdated: package includes MediaBrowserService, true");
1655c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
16563843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                return true;
16573843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            }
1658e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1659c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
16603843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        // if list has different size
16613843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        if (resInfos.size() != mBrowsePlayerInfoList.size()) {
1662c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
1663c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.d(TAG, "isBrowsableListUpdated: browsable list size mismatch, true");
1664c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
16653843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            return true;
1666e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
16673843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen
16683843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        Log.d(TAG, "isBrowsableListUpdated: false");
16693843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        return false;
1670e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1671e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1672511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private void removePackageFromBrowseList(String packageName) {
1673c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
1674c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, "removePackageFromBrowseList: " + packageName);
1675c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
1676511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mBrowsePlayerInfoList) {
1677511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int browseInfoID = getBrowseId(packageName);
1678511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (browseInfoID != -1) {
1679511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                mBrowsePlayerInfoList.remove(browseInfoID);
1680511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
1681e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1682e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1683e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1684e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
1685e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * utility function to get the browse player index from global browsable
1686e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * list. It may return -1 if specified package name is not in the list.
1687e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
1688511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private int getBrowseId(String packageName) {
1689e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean response = false;
1690e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        int browseInfoID = 0;
1691511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mBrowsePlayerInfoList) {
1692511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (BrowsePlayerInfo info : mBrowsePlayerInfoList) {
1693511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (info.packageName.equals(packageName)) {
1694511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    response = true;
1695511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    break;
1696511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
1697511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                browseInfoID++;
1698e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1699e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1700e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1701e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!response) {
1702e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            browseInfoID = -1;
1703e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1704e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1705c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
1706c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, "getBrowseId for packageName: " + packageName + " , browseInfoID: "
1707c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    + browseInfoID);
1708c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
1709e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return browseInfoID;
1710e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1711e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1712e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setAddressedPlayer(byte[] bdaddr, int selectedId) {
1713eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen        String functionTag = "setAddressedPlayer(" + selectedId + "): ";
1714e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1715511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1716511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (mMediaPlayerInfoList.isEmpty()) {
1717eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Log.w(TAG, functionTag + "no players, send no available players");
1718eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_AVBL_PLAY);
1719eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                return;
1720eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            }
1721eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            if (!mMediaPlayerInfoList.containsKey(selectedId)) {
1722eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Log.w(TAG, functionTag + "invalid id, sending response back ");
1723eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_INV_PLAYER);
1724eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                return;
1725eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            }
1726eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen
1727eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            if (isPlayerAlreadyAddressed(selectedId)) {
1728511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                MediaPlayerInfo info = getAddressedPlayerInfo();
1729eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Log.i(TAG, functionTag + "player already addressed: " + info);
1730eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR);
1731eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                return;
1732eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            }
1733eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            // register new Media Controller Callback and update the current IDs
1734eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            if (!updateCurrentController(selectedId, mCurrBrowsePlayerID)) {
1735eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Log.e(TAG, functionTag + "updateCurrentController failed!");
1736eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR);
1737eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                return;
1738eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            }
1739eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            // If we don't have a controller, try to launch the player
1740eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            MediaPlayerInfo info = getAddressedPlayerInfo();
1741eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            if (info.getMediaController() == null) {
1742eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Intent launch = mPackageManager.getLaunchIntentForPackage(info.getPackageName());
1743eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Log.i(TAG, functionTag + "launching player " + launch);
1744eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                mContext.startActivity(launch);
1745e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1746e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1747eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen        setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR);
1748e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1749e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1750e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setBrowsedPlayer(byte[] bdaddr, int selectedId) {
1751e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        int status = AvrcpConstants.RSP_NO_ERROR;
1752e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1753e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // checking for error cases
1754511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        if (mMediaPlayerInfoList.isEmpty()) {
1755e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            status = AvrcpConstants.RSP_NO_AVBL_PLAY;
1756819122df0eff426a43d175b14098339fa9f8f648Marie Janssen            Log.w(TAG, "setBrowsedPlayer: No available players! ");
1757e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
1758819122df0eff426a43d175b14098339fa9f8f648Marie Janssen            // Workaround for broken controllers selecting ID 0
1759819122df0eff426a43d175b14098339fa9f8f648Marie Janssen            // Seen at least on Ford, Chevrolet MyLink
1760819122df0eff426a43d175b14098339fa9f8f648Marie Janssen            if (selectedId == 0) {
1761819122df0eff426a43d175b14098339fa9f8f648Marie Janssen                Log.w(TAG, "setBrowsedPlayer: workaround invalid id 0");
1762819122df0eff426a43d175b14098339fa9f8f648Marie Janssen                selectedId = mCurrAddrPlayerID;
1763819122df0eff426a43d175b14098339fa9f8f648Marie Janssen            }
1764819122df0eff426a43d175b14098339fa9f8f648Marie Janssen
1765e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // update current browse player id and start browsing service
1766e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            updateNewIds(mCurrAddrPlayerID, selectedId);
1767e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String browsedPackage = getPackageName(selectedId);
1768e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1769e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!isPackageNameValid(browsedPackage)) {
1770e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.w(TAG, " Invalid package for id:" + mCurrBrowsePlayerID);
1771e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                status = AvrcpConstants.RSP_INV_PLAYER;
1772e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else if (!isBrowseSupported(browsedPackage)) {
1773c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.w(TAG, "Browse unsupported for id:" + mCurrBrowsePlayerID + ", packagename : "
1774c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        + browsedPackage);
1775e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                status = AvrcpConstants.RSP_PLAY_NOT_BROW;
1776e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else if (!startBrowseService(bdaddr, browsedPackage)) {
1777e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "service cannot be started for browse player id:" + mCurrBrowsePlayerID
1778e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        + ", packagename : " + browsedPackage);
1779e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                status = AvrcpConstants.RSP_INTERNAL_ERR;
1780e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1781e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1782e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1783e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (status != AvrcpConstants.RSP_NO_ERROR) {
1784e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            setBrowsedPlayerRspNative(bdaddr, status, (byte) 0x00, 0, null);
1785e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1786e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1787c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
1788c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, "setBrowsedPlayer for selectedId: " + selectedId + " , status: " + status);
1789c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
1790e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1791e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
179205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private MediaSessionManager.OnActiveSessionsChangedListener mActiveSessionListener =
179305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            new MediaSessionManager.OnActiveSessionsChangedListener() {
1794e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
179505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                @Override
179605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                public void onActiveSessionsChanged(
179705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                        List<android.media.session.MediaController> newControllers) {
1798bc5aacf160c5cc7ff5a196c7c3c1cf62f322fc14Marie Janssen                    Set<String> updatedPackages = new HashSet<String>();
179905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    // Update the current players
180005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    for (android.media.session.MediaController controller : newControllers) {
1801bc5aacf160c5cc7ff5a196c7c3c1cf62f322fc14Marie Janssen                        String packageName = controller.getPackageName();
1802c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (DEBUG) {
1803de778443fdb539d38db92069661fdc18626a4c9cAjay Panicker                            Log.v(TAG, "ActiveSession: " + MediaControllerFactory.wrap(controller));
1804c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
1805bc5aacf160c5cc7ff5a196c7c3c1cf62f322fc14Marie Janssen                        // Only use the first (highest priority) controller from each package
1806c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (updatedPackages.contains(packageName)) {
1807c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            continue;
1808c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
180905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                        addMediaPlayerController(controller);
1810bc5aacf160c5cc7ff5a196c7c3c1cf62f322fc14Marie Janssen                        updatedPackages.add(packageName);
1811eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                    }
1812d996f17ea97b2c592338bcfbc93056d0224da1cdAjay Panicker
1813f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                    if (newControllers.size() > 0 && getAddressedPlayerInfo() == null) {
1814c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        if (DEBUG) {
1815f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                            Log.v(TAG, "No addressed player but active sessions, taking first.");
1816c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        }
1817f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                        setAddressedMediaSessionPackage(newControllers.get(0).getPackageName());
1818eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                    }
181985aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                    updateCurrentMediaState();
1820e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
182105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            };
182205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
182378d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen    private void setAddressedMediaSessionPackage(@Nullable String packageName) {
182441527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen        if (packageName == null) {
182541527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen            // Should only happen when there's no media players, reset to no available player.
182641527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen            updateCurrentController(0, mCurrBrowsePlayerID);
182741527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen            return;
182841527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen        }
18295e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker        if (packageName.equals("com.android.server.telecom")) {
18305e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker            Log.d(TAG, "Ignore addressed media session change to telecom");
18315e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker            return;
18325e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker        }
183305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        // No change.
1834c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (getPackageName(mCurrAddrPlayerID).equals(packageName)) {
1835c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            return;
1836c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
1837c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
1838c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.v(TAG, "Changing addressed media session to " + packageName);
1839c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
184005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        // If the player doesn't exist, we need to add it.
184105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (getMediaPlayerInfo(packageName) == null) {
184205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            addMediaPlayerPackage(packageName);
184385aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            updateCurrentMediaState();
184405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
1845511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1846511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
1847511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (entry.getValue().getPackageName().equals(packageName)) {
1848511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    int newAddrID = entry.getKey();
1849c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
1850c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "Set addressed #" + newAddrID + " " + entry.getValue());
1851c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
1852511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    updateCurrentController(newAddrID, mCurrBrowsePlayerID);
185385aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker                    updateCurrentMediaState();
1854511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    return;
1855511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
1856e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1857e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
185805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        // We shouldn't ever get here.
185905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        Log.e(TAG, "Player info for " + packageName + " doesn't exist!");
186005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
1861e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
186205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private void setActiveMediaSession(MediaSession.Token token) {
186305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        android.media.session.MediaController activeController =
186405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                new android.media.session.MediaController(mContext, token);
18655e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker        if (activeController.getPackageName().equals("com.android.server.telecom")) {
18665e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker            Log.d(TAG, "Ignore active media session change to telecom");
18675e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker            return;
18685e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker        }
1869c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
1870c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.v(TAG, "Set active media session " + activeController.getPackageName());
1871c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
187205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        addMediaPlayerController(activeController);
187305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        setAddressedMediaSessionPackage(activeController.getPackageName());
187405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
1875e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1876e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean startBrowseService(byte[] bdaddr, String packageName) {
1877e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean status = true;
1878e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1879e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* creating new instance for Browse Media Player */
1880e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browseService = getBrowseServiceName(packageName);
1881e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!browseService.isEmpty()) {
1882c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr)
1883c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    .setBrowsed(packageName, browseService);
1884e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
1885e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Log.w(TAG, "No Browser service available for " + packageName);
1886e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            status = false;
1887e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1888e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1889c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
1890c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG,
1891c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    "startBrowseService for packageName: " + packageName + ", status = " + status);
1892c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
1893e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return status;
1894e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1895e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1896511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private String getBrowseServiceName(String packageName) {
1897e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browseServiceName = "";
1898e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1899e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // getting the browse service name from browse player info
1900511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mBrowsePlayerInfoList) {
1901511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int browseInfoID = getBrowseId(packageName);
1902511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (browseInfoID != -1) {
1903511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                browseServiceName = mBrowsePlayerInfoList.get(browseInfoID).serviceClass;
1904511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
1905e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1906e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1907c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
1908c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, "getBrowseServiceName for packageName: " + packageName
1909c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    + ", browseServiceName = " + browseServiceName);
1910c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
1911e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return browseServiceName;
1912e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1913e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1914754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker    void buildBrowsablePlayerList() {
1915754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker        synchronized (mBrowsePlayerInfoList) {
19163843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            mBrowsePlayerInfoList.clear();
19173843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            Intent intent = new Intent(android.service.media.MediaBrowserService.SERVICE_INTERFACE);
1918754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker            List<ResolveInfo> playerList =
1919754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                    mPackageManager.queryIntentServices(intent, PackageManager.MATCH_ALL);
1920754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker
1921754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker            for (ResolveInfo info : playerList) {
1922754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                String displayableName = info.loadLabel(mPackageManager).toString();
1923754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                String serviceName = info.serviceInfo.name;
1924754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                String packageName = info.serviceInfo.packageName;
1925754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker
1926c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
1927c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.d(TAG, "Adding " + serviceName + " to list of browsable players");
1928c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
1929754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                BrowsePlayerInfo currentPlayer =
1930754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                        new BrowsePlayerInfo(packageName, displayableName, serviceName);
1931754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                mBrowsePlayerInfoList.add(currentPlayer);
1932754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                MediaPlayerInfo playerInfo = getMediaPlayerInfo(packageName);
1933754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                MediaController controller =
1934754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                        (playerInfo == null) ? null : playerInfo.getMediaController();
1935754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                // Refresh the media player entry so it notices we can browse
1936754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                if (controller != null) {
1937754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                    addMediaPlayerController(controller.getWrappedInstance());
1938754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                } else {
1939754c469a24029e5b9a1c921fb91e3799937eb918Ajay Panicker                    addMediaPlayerPackage(packageName);
1940eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                }
19413843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            }
194285aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            updateCurrentMediaState();
1943e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1944e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1945e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
194605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    /* Initializes list of media players identified from session manager active sessions */
1947511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private void initMediaPlayersList() {
1948511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1949511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            // Clearing old browsable player's list
1950511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            mMediaPlayerInfoList.clear();
195105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
1952511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (mMediaSessionManager == null) {
1953c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
1954c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.w(TAG, "initMediaPlayersList: no media session manager!");
1955c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
1956511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                return;
1957511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
195805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
1959511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            List<android.media.session.MediaController> controllers =
1960511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    mMediaSessionManager.getActiveSessions(null);
1961c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
1962511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                Log.v(TAG, "initMediaPlayerInfoList: " + controllers.size() + " controllers");
1963c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
1964511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            /* Initializing all media players */
1965511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (android.media.session.MediaController controller : controllers) {
1966511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                addMediaPlayerController(controller);
1967511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
1968f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen
196985aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker            updateCurrentMediaState();
1970e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1971511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (mMediaPlayerInfoList.size() > 0) {
1972511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                // Set the first one as the Addressed Player
1973511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                updateCurrentController(mMediaPlayerInfoList.firstKey(), -1);
1974511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
1975e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1976e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1977e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1978eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    private List<android.media.session.MediaController> getMediaControllers() {
1979eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        List<android.media.session.MediaController> controllers =
1980eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                new ArrayList<android.media.session.MediaController>();
1981511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1982511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (MediaPlayerInfo info : mMediaPlayerInfoList.values()) {
1983a1e42e29b15323e1a4d0559235a0987200663b2fMarie Janssen                MediaController controller = info.getMediaController();
1984a1e42e29b15323e1a4d0559235a0987200663b2fMarie Janssen                if (controller != null) {
1985a1e42e29b15323e1a4d0559235a0987200663b2fMarie Janssen                    controllers.add(controller.getWrappedInstance());
1986511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
1987eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            }
1988eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        }
1989eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        return controllers;
1990eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    }
1991eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
1992eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    /** Add (or update) a player to the media player list without a controller */
1993511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private boolean addMediaPlayerPackage(String packageName) {
1994eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        MediaPlayerInfo info = new MediaPlayerInfo(null, AvrcpConstants.PLAYER_TYPE_AUDIO,
199559b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                AvrcpConstants.PLAYER_SUBTYPE_NONE, PLAYSTATUS_STOPPED,
1996b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen                getFeatureBitMask(packageName), packageName, getAppLabel(packageName));
199705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        return addMediaPlayerInfo(info);
1998eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    }
1999eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
2000eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    /** Add (or update) a player to the media player list given an active controller */
2001511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private boolean addMediaPlayerController(android.media.session.MediaController controller) {
2002eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        String packageName = controller.getPackageName();
2003de778443fdb539d38db92069661fdc18626a4c9cAjay Panicker        MediaPlayerInfo info = new MediaPlayerInfo(MediaControllerFactory.wrap(controller),
2004eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                AvrcpConstants.PLAYER_TYPE_AUDIO, AvrcpConstants.PLAYER_SUBTYPE_NONE,
200559b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                getBluetoothPlayState(controller.getPlaybackState()),
200659b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                getFeatureBitMask(packageName), controller.getPackageName(),
200759b1c77f883bd97816332046a3a98be4431cceddMarie Janssen                getAppLabel(packageName));
200805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        return addMediaPlayerInfo(info);
2009eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    }
2010eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
201105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    /** Add or update a player to the media player list given the MediaPlayerInfo object.
201205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen     *  @return true if an item was updated, false if it was added instead
201305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen     */
2014511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private boolean addMediaPlayerInfo(MediaPlayerInfo info) {
2015b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen        int updateId = -1;
201605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        boolean updated = false;
2017f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen        boolean currentRemoved = false;
20185e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker        if (info.getPackageName().equals("com.android.server.telecom")) {
20195e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker            Log.d(TAG, "Skip adding telecom to the media player info list");
20205e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker            return updated;
20215e5cfd5f5e651367111c5553230e066fc6817942Ajay Panicker        }
2022511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
2023511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
2024f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                MediaPlayerInfo current = entry.getValue();
2025f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                int id = entry.getKey();
2026f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                if (info.getPackageName().equals(current.getPackageName())) {
2027f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                    if (!current.equalView(info)) {
2028f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                        // If we would present a different player, make it a new player
2029f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                        // so that controllers know whether a player is browsable or not.
2030f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                        mMediaPlayerInfoList.remove(id);
2031f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                        currentRemoved = (mCurrAddrPlayerID == id);
2032f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                        break;
2033f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                    }
2034f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                    updateId = id;
2035511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    updated = true;
2036511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    break;
2037511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
2038b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen            }
2039511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (updateId == -1) {
2040511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                // New player
2041511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                mLastUsedPlayerID++;
2042511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                updateId = mLastUsedPlayerID;
2043f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                mAvailablePlayerViewChanged = true;
2044511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2045511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            mMediaPlayerInfoList.put(updateId, info);
2046fecc92279a01e377962b9b33b02d5db0ff3d1440Jack He        }
2047c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
2048c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, (updated ? "update #" : "add #") + updateId + ":" + info.toString());
2049c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
2050fecc92279a01e377962b9b33b02d5db0ff3d1440Jack He        if (currentRemoved || updateId == mCurrAddrPlayerID) {
2051fecc92279a01e377962b9b33b02d5db0ff3d1440Jack He            updateCurrentController(updateId, mCurrBrowsePlayerID);
2052b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen        }
205305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        return updated;
2054eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    }
2055eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
2056eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    /** Remove all players related to |packageName| from the media player info list */
2057511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private MediaPlayerInfo removeMediaPlayerInfo(String packageName) {
2058511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
2059511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int removeKey = -1;
2060511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
2061511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (entry.getValue().getPackageName().equals(packageName)) {
2062511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    removeKey = entry.getKey();
2063511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    break;
2064511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
2065511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2066511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (removeKey != -1) {
2067c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
2068384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen                    Log.d(TAG, "remove #" + removeKey + ":" + mMediaPlayerInfoList.get(removeKey));
2069c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
2070f2f6a4ea02e9456f71ea0490112845110ca5d975Marie Janssen                mAvailablePlayerViewChanged = true;
2071511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                return mMediaPlayerInfoList.remove(removeKey);
2072eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            }
2073b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen
2074511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            return null;
2075511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        }
2076eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    }
2077eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
2078384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen    /** Remove the controller referenced by |controller| from any player in the list */
2079f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen    private void removeMediaController(@Nullable android.media.session.MediaController controller) {
2080c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (controller == null) {
2081c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            return;
2082c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
2083384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        synchronized (mMediaPlayerInfoList) {
2084f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
2085f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                MediaPlayerInfo info = entry.getValue();
2086a1e42e29b15323e1a4d0559235a0987200663b2fMarie Janssen                MediaController c = info.getMediaController();
2087f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                if (c != null && c.equals(controller)) {
2088f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    info.setMediaController(null);
2089f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    if (entry.getKey() == mCurrAddrPlayerID) {
2090f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                        updateCurrentController(mCurrAddrPlayerID, mCurrBrowsePlayerID);
2091f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    }
2092f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                }
2093384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            }
2094384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        }
2095384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen    }
2096384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen
2097e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
2098e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * utility function to get the playback state of any media player through
2099e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * media controller APIs.
2100e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
210159b1c77f883bd97816332046a3a98be4431cceddMarie Janssen    private byte getBluetoothPlayState(PlaybackState pbState) {
210259b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        if (pbState == null) {
210359b1c77f883bd97816332046a3a98be4431cceddMarie Janssen            Log.w(TAG, "playState object null, sending STOPPED");
210459b1c77f883bd97816332046a3a98be4431cceddMarie Janssen            return PLAYSTATUS_STOPPED;
2105e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2106e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
210759b1c77f883bd97816332046a3a98be4431cceddMarie Janssen        switch (pbState.getState()) {
2108e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_PLAYING:
2109e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_PLAYING;
2110e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2111cd1345961b7211ef6d130bd88b672835b52b3f60Ajay Panicker            case PlaybackState.STATE_BUFFERING:
2112e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_STOPPED:
2113e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_NONE:
2114e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_CONNECTING:
2115e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_STOPPED;
2116e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2117e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_PAUSED:
2118e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_PAUSED;
2119e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2120e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_FAST_FORWARDING:
2121e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_SKIPPING_TO_NEXT:
2122e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM:
2123e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_FWD_SEEK;
2124e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2125e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_REWINDING:
2126e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
2127e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_REV_SEEK;
2128e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2129e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_ERROR:
2130e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            default:
2131e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_ERROR;
2132e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2133e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2134e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2135e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
2136e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * utility function to get the feature bit mask of any media player through
2137e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * package name
2138e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
2139e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private short[] getFeatureBitMask(String packageName) {
2140e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2141e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ArrayList<Short> featureBitsList = new ArrayList<Short>();
2142e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2143e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* adding default feature bits */
2144e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_PLAY_BIT_NO);
2145e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_STOP_BIT_NO);
2146e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_PAUSE_BIT_NO);
2147e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_REWIND_BIT_NO);
2148e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_FAST_FWD_BIT_NO);
2149e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_FORWARD_BIT_NO);
2150e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_BACKWARD_BIT_NO);
2151e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_ADV_CTRL_BIT_NO);
2152e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2153e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Add/Modify browse player supported features. */
2154e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (isBrowseSupported(packageName)) {
2155e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_BROWSE_BIT_NO);
2156e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_UID_UNIQUE_BIT_NO);
2157e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_NOW_PLAY_BIT_NO);
2158e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_GET_NUM_OF_ITEMS_BIT_NO);
2159e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2160e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2161e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // converting arraylist to array for response
2162e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        short[] featureBitsArray = new short[featureBitsList.size()];
2163e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2164e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        for (int i = 0; i < featureBitsList.size(); i++) {
2165e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsArray[i] = featureBitsList.get(i).shortValue();
2166e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2167e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2168e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return featureBitsArray;
2169e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2170e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2171e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /**
2172e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * Checks the Package name if it supports Browsing or not.
2173e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     *
2174e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * @param packageName - name of the package to get the Id.
2175e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * @return true if it supports browsing, else false.
2176e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
2177511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private boolean isBrowseSupported(String packageName) {
2178511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mBrowsePlayerInfoList) {
2179511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            /* check if Browsable Player's list contains this package name */
2180511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (BrowsePlayerInfo info : mBrowsePlayerInfoList) {
2181511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (info.packageName.equals(packageName)) {
2182c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
2183c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "isBrowseSupported for " + packageName + ": true");
2184c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
2185511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    return true;
2186511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
2187e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2188e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2189e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2190c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
2191c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.v(TAG, "isBrowseSupported for " + packageName + ": false");
2192c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
21931b70ec148be773651d5ad00e3ce0d28b3a63306dAjay Panicker        return false;
2194e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2195e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2196e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private String getPackageName(int id) {
2197511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        MediaPlayerInfo player = null;
2198511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
2199511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            player = mMediaPlayerInfoList.getOrDefault(id, null);
2200511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        }
2201e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2202eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        if (player == null) {
2203eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            Log.w(TAG, "No package name for player (" + id + " not valid)");
2204eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            return "";
2205e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2206eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
2207eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        String packageName = player.getPackageName();
2208c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
2209c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.v(TAG, "Player " + id + " package: " + packageName);
2210c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
2211e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return packageName;
2212e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2213e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2214e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* from the global object, getting the current browsed player's package name */
2215e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private String getCurrentBrowsedPlayer(byte[] bdaddr) {
2216e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browsedPlayerPackage = "";
2217e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2218e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Map<String, BrowsedMediaPlayer> connList = mAvrcpBrowseManager.getConnList();
2219e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String bdaddrStr = new String(bdaddr);
2220c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (connList.containsKey(bdaddrStr)) {
2221e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            browsedPlayerPackage = connList.get(bdaddrStr).getPackageName();
2222e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2223c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
2224c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.v(TAG, "getCurrentBrowsedPlayerPackage: " + browsedPlayerPackage);
2225c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
2226e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return browsedPlayerPackage;
2227e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2228e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2229eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    /* Returns the MediaPlayerInfo for the currently addressed media player */
2230511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private MediaPlayerInfo getAddressedPlayerInfo() {
2231511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
2232511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            return mMediaPlayerInfoList.getOrDefault(mCurrAddrPlayerID, null);
2233511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        }
2234e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2235e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2236e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
2237e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * Utility function to get the Media player info from package name returns
2238e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * null if package name not found in media players list
2239e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
2240511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private MediaPlayerInfo getMediaPlayerInfo(String packageName) {
2241511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
2242511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (mMediaPlayerInfoList.isEmpty()) {
2243c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
2244c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.v(TAG, "getMediaPlayerInfo: Media players list empty");
2245c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
2246511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                return null;
2247511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2248eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
2249511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (MediaPlayerInfo info : mMediaPlayerInfoList.values()) {
2250511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (packageName.equals(info.getPackageName())) {
2251c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    if (DEBUG) {
2252c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        Log.v(TAG, "getMediaPlayerInfo: Found " + packageName);
2253c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    }
2254511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    return info;
2255511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
2256e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2257c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
2258c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.w(TAG, "getMediaPlayerInfo: " + packageName + " not found");
2259c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
2260511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            return null;
2261e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2262e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2263e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2264e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* prepare media list & return the media player list response object */
2265511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private MediaPlayerListRsp prepareMediaPlayerRspObj() {
2266511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
226742b19bc308e155b52e735e38efca42d5c7c6a699Ajay Panicker            // TODO(apanicke): This hack will go away as soon as a developer
226842b19bc308e155b52e735e38efca42d5c7c6a699Ajay Panicker            // option to enable or disable player selection is created. Right
226942b19bc308e155b52e735e38efca42d5c7c6a699Ajay Panicker            // now this is needed to fix BMW i3 carkits and any other carkits
227042b19bc308e155b52e735e38efca42d5c7c6a699Ajay Panicker            // that might try to connect to a player that isnt the current
227142b19bc308e155b52e735e38efca42d5c7c6a699Ajay Panicker            // player based on this list
227242b19bc308e155b52e735e38efca42d5c7c6a699Ajay Panicker            int numPlayers = 1;
2273511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen
2274511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int[] playerIds = new int[numPlayers];
2275511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            byte[] playerTypes = new byte[numPlayers];
2276511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int[] playerSubTypes = new int[numPlayers];
2277511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            String[] displayableNameArray = new String[numPlayers];
2278511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            byte[] playStatusValues = new byte[numPlayers];
2279511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            short[] featureBitMaskValues =
2280511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    new short[numPlayers * AvrcpConstants.AVRC_FEATURE_MASK_SIZE];
2281511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen
22827a44bb23aadc107c369d230fb96f4ce3374f3f5bAjay Panicker            // Reserve the first spot for the currently addressed player if
22837a44bb23aadc107c369d230fb96f4ce3374f3f5bAjay Panicker            // we have one
22847a44bb23aadc107c369d230fb96f4ce3374f3f5bAjay Panicker            int players = mMediaPlayerInfoList.containsKey(mCurrAddrPlayerID) ? 1 : 0;
2285511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
22862a9aba641d081621a373b56171938994447040e3Ajay Panicker                int idx = players;
2287c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (entry.getKey() == mCurrAddrPlayerID) {
228842b19bc308e155b52e735e38efca42d5c7c6a699Ajay Panicker                    idx = 0;
2289c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                } else {
229042b19bc308e155b52e735e38efca42d5c7c6a699Ajay Panicker                    continue; // TODO(apanicke): Remove, see above note
2291c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
2292511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                MediaPlayerInfo info = entry.getValue();
22932a9aba641d081621a373b56171938994447040e3Ajay Panicker                playerIds[idx] = entry.getKey();
22942a9aba641d081621a373b56171938994447040e3Ajay Panicker                playerTypes[idx] = info.getMajorType();
22952a9aba641d081621a373b56171938994447040e3Ajay Panicker                playerSubTypes[idx] = info.getSubType();
22962a9aba641d081621a373b56171938994447040e3Ajay Panicker                displayableNameArray[idx] = info.getDisplayableName();
22972a9aba641d081621a373b56171938994447040e3Ajay Panicker                playStatusValues[idx] = info.getPlayStatus();
2298511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen
2299511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                short[] featureBits = info.getFeatureBitMask();
2300511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                for (int numBit = 0; numBit < featureBits.length; numBit++) {
2301511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    /* gives which octet this belongs to */
2302511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    byte octet = (byte) (featureBits[numBit] / 8);
2303511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    /* gives the bit position within the octet */
2304511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    byte bit = (byte) (featureBits[numBit] % 8);
23052a9aba641d081621a373b56171938994447040e3Ajay Panicker                    featureBitMaskValues[(idx * AvrcpConstants.AVRC_FEATURE_MASK_SIZE) + octet] |=
23062a9aba641d081621a373b56171938994447040e3Ajay Panicker                            (1 << bit);
2307511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
2308e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2309511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                /* printLogs */
2310511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (DEBUG) {
23112a9aba641d081621a373b56171938994447040e3Ajay Panicker                    Log.d(TAG, "Player " + playerIds[idx] + ": " + displayableNameArray[idx]
2312c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            + " type: " + playerTypes[idx] + ", " + playerSubTypes[idx]
2313c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            + " status: " + playStatusValues[idx]);
2314511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
2315e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2316c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (idx != 0) {
2317c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    players++;
2318c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
2319511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2320e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2321c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
2322c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.d(TAG, "prepareMediaPlayerRspObj: numPlayers = " + numPlayers);
2323c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
2324e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2325511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            return new MediaPlayerListRsp(AvrcpConstants.RSP_NO_ERROR, sUIDCounter, numPlayers,
2326511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    AvrcpConstants.BTRC_ITEM_PLAYER, playerIds, playerTypes, playerSubTypes,
2327511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    playStatusValues, featureBitMaskValues, displayableNameArray);
2328511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        }
2329e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2330e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2331c4fbd756e2645147470c486ae96f2253f5e13a52Jack He    /* build media player list and send it to remote. */
2332e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handleMediaPlayerListRsp(AvrcpCmd.FolderItemsCmd folderObj) {
2333511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        MediaPlayerListRsp rspObj = null;
2334511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
2335511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int numPlayers = mMediaPlayerInfoList.size();
2336511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (numPlayers == 0) {
2337511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                mediaPlayerListRspNative(folderObj.mAddress, AvrcpConstants.RSP_NO_AVBL_PLAY,
2338511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                        (short) 0, (byte) 0, 0, null, null, null, null, null, null);
2339511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                return;
2340511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2341511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (folderObj.mStartItem >= numPlayers) {
2342511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                Log.i(TAG, "handleMediaPlayerListRsp: start = " + folderObj.mStartItem
2343c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        + " > num of items = " + numPlayers);
2344511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                mediaPlayerListRspNative(folderObj.mAddress, AvrcpConstants.RSP_INV_RANGE,
2345511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                        (short) 0, (byte) 0, 0, null, null, null, null, null, null);
2346511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                return;
2347511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2348511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            rspObj = prepareMediaPlayerRspObj();
2349e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2350c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
2351c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, "handleMediaPlayerListRsp: sending " + rspObj.mNumItems + " players");
2352c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
2353eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        mediaPlayerListRspNative(folderObj.mAddress, rspObj.mStatus, rspObj.mUIDCounter,
23548bc413b0b749ea9df59e858493273e05087fe887Jack He                rspObj.mItemType, rspObj.mNumItems, rspObj.mPlayerIds, rspObj.mPlayerTypes,
2355eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                rspObj.mPlayerSubTypes, rspObj.mPlayStatusValues, rspObj.mFeatureBitMaskValues,
2356eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                rspObj.mPlayerNameList);
2357e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2358e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2359e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* unregister to the old controller, update new IDs and register to the new controller */
2360e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean updateCurrentController(int addrId, int browseId) {
2361e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean registerRsp = true;
2362e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2363e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        updateNewIds(addrId, browseId);
2364e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2365eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        MediaController newController = null;
2366eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        MediaPlayerInfo info = getAddressedPlayerInfo();
2367c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (info != null) {
2368c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            newController = info.getMediaController();
2369c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
2370eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
2371c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
2372eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            Log.d(TAG, "updateCurrentController: " + mMediaController + " to " + newController);
2373c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
2374ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen        synchronized (this) {
2375ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen            if (mMediaController == null || (!mMediaController.equals(newController))) {
2376f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                if (mMediaController != null) {
2377f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    mMediaController.unregisterCallback(mMediaControllerCb);
2378f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                }
2379f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                mMediaController = newController;
2380f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                if (mMediaController != null) {
2381f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    mMediaController.registerCallback(mMediaControllerCb, mHandler);
2382f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                } else {
2383f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    registerRsp = false;
2384f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                }
2385eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            }
2386e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
238785aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker        updateCurrentMediaState();
2388eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        return registerRsp;
2389e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2390e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2391e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Handle getfolderitems for scope = VFS, Search, NowPlayingList */
2392c4fbd756e2645147470c486ae96f2253f5e13a52Jack He    private void handleGetFolderItemBrowseResponse(AvrcpCmd.FolderItemsCmd folderObj,
2393c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            byte[] bdaddr) {
2394e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        int status = AvrcpConstants.RSP_NO_ERROR;
2395e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2396e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Browsed player is already set */
239705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (folderObj.mScope == AvrcpConstants.BTRC_SCOPE_FILE_SYSTEM) {
239805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) == null) {
239905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                Log.e(TAG, "handleGetFolderItemBrowseResponse: no browsed player set for "
2400c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        + Utils.getAddressStringFromByte(bdaddr));
240105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                getFolderItemsRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR, (short) 0,
240205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                        (byte) 0x00, 0, null, null, null, null, null, null, null, null);
240305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return;
240405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            }
240505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).getFolderItemsVFS(folderObj);
240605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            return;
2407e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
240805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (folderObj.mScope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
240905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mAddressedMediaPlayer.getFolderItemsNowPlaying(bdaddr, folderObj, mMediaController);
241005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            return;
2411e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2412e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
241305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        /* invalid scope */
241405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        Log.e(TAG, "handleGetFolderItemBrowseResponse: unknown scope " + folderObj.mScope);
241505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        getFolderItemsRspNative(bdaddr, AvrcpConstants.RSP_INV_SCOPE, (short) 0, (byte) 0x00, 0,
241605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                null, null, null, null, null, null, null, null);
2417e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2418e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2419e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* utility function to update the global values of current Addressed and browsed player */
2420511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private void updateNewIds(int addrId, int browseId) {
2421c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
2422c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.v(TAG,
2423c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    "updateNewIds: Addressed:" + mCurrAddrPlayerID + " to " + addrId + ", Browse:"
2424c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                            + mCurrBrowsePlayerID + " to " + browseId);
2425c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
2426e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mCurrAddrPlayerID = addrId;
2427e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mCurrBrowsePlayerID = browseId;
2428e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2429e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2430e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Getting the application's displayable name from package name */
2431e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private String getAppLabel(String packageName) {
2432e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ApplicationInfo appInfo = null;
2433e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        try {
2434e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            appInfo = mPackageManager.getApplicationInfo(packageName, 0);
2435e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } catch (NameNotFoundException e) {
2436e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            e.printStackTrace();
2437e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2438e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2439c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        return (String) (appInfo != null ? mPackageManager.getApplicationLabel(appInfo)
2440c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                : "Unknown");
2441e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2442e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2443e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handlePlayItemResponse(byte[] bdaddr, byte[] uid, byte scope) {
2444294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen        if (scope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
2445294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen            mAddressedMediaPlayer.playItem(bdaddr, uid, mMediaController);
2446c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        } else {
2447c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (!isAddrPlayerSameAsBrowsed(bdaddr)) {
2448c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.w(TAG, "Remote requesting play item on uid which may not be recognized by"
2449c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        + "current addressed player");
2450e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                playItemRspNative(bdaddr, AvrcpConstants.RSP_INV_ITEM);
2451e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2452e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2453e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) {
2454e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).playItem(uid, scope);
2455e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2456c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.e(TAG, "handlePlayItemResponse: Remote requested playitem "
2457c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        + "before setbrowsedplayer");
2458e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                playItemRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR);
2459e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2460e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2461e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2462e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2463e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handleGetItemAttr(AvrcpCmd.ItemAttrCmd itemAttr) {
246445551315d39fd0bc1c5a118b4728c728ce42b412koh.changseok        if (itemAttr.mUidCounter != sUIDCounter) {
246545551315d39fd0bc1c5a118b4728c728ce42b412koh.changseok            Log.e(TAG, "handleGetItemAttr: invaild uid counter.");
2466c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            getItemAttrRspNative(itemAttr.mAddress, AvrcpConstants.RSP_UID_CHANGED, (byte) 0, null,
2467c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    null);
246845551315d39fd0bc1c5a118b4728c728ce42b412koh.changseok            return;
246945551315d39fd0bc1c5a118b4728c728ce42b412koh.changseok        }
2470384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        if (itemAttr.mScope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
2471384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            if (mCurrAddrPlayerID == NO_PLAYER_ID) {
2472c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                getItemAttrRspNative(itemAttr.mAddress, AvrcpConstants.RSP_NO_AVBL_PLAY, (byte) 0,
2473c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        null, null);
2474c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen                return;
2475384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            }
2476c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen            mAddressedMediaPlayer.getItemAttr(itemAttr.mAddress, itemAttr, mMediaController);
2477c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen            return;
2478c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen        }
2479c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen        // All other scopes use browsed player
2480c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen        if (mAvrcpBrowseManager.getBrowsedMediaPlayer(itemAttr.mAddress) != null) {
2481c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen            mAvrcpBrowseManager.getBrowsedMediaPlayer(itemAttr.mAddress).getItemAttr(itemAttr);
2482384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        } else {
2483c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen            Log.e(TAG, "Could not get attributes. mBrowsedMediaPlayer is null");
2484c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            getItemAttrRspNative(itemAttr.mAddress, AvrcpConstants.RSP_INTERNAL_ERR, (byte) 0, null,
2485c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    null);
2486e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2487e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2488e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2489e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handleGetTotalNumOfItemsResponse(byte[] bdaddr, byte scope) {
2490e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // for scope as media player list
2491e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (scope == AvrcpConstants.BTRC_SCOPE_PLAYER_LIST) {
2492511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int numPlayers = 0;
2493511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            synchronized (mMediaPlayerInfoList) {
2494511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                numPlayers = mMediaPlayerInfoList.size();
2495511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2496c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
2497c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.d(TAG, "handleGetTotalNumOfItemsResponse: " + numPlayers + " players.");
2498c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
2499511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            getTotalNumOfItemsRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, numPlayers);
2500511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        } else if (scope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
2501294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen            mAddressedMediaPlayer.getTotalNumOfItems(bdaddr, mMediaController);
2502e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
2503e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // for FileSystem browsing scopes as VFS, Now Playing
2504e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) {
2505e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).getTotalNumOfItems(scope);
2506e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2507e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "Could not get Total NumOfItems. mBrowsedMediaPlayer is null");
2508e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                getTotalNumOfItemsRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR, 0, 0);
2509e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2510e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2511e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2512e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2513e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2514e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* check if browsed player and addressed player are same */
2515e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isAddrPlayerSameAsBrowsed(byte[] bdaddr) {
2516e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browsedPlayer = getCurrentBrowsedPlayer(bdaddr);
2517e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2518e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!isPackageNameValid(browsedPlayer)) {
2519e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Log.w(TAG, "Browsed player name empty");
2520eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            return false;
2521e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2522e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2523b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen        MediaPlayerInfo info = getAddressedPlayerInfo();
2524db2d487ba559f0e4de02bc2ad4cc7e275878b2fcMarie Janssen        String packageName = (info == null) ? "<none>" : info.getPackageName();
2525db2d487ba559f0e4de02bc2ad4cc7e275878b2fcMarie Janssen        if (info == null || !packageName.equals(browsedPlayer)) {
2526c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (DEBUG) {
2527c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                Log.d(TAG, browsedPlayer + " is not addressed player " + packageName);
2528c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
2529eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            return false;
2530eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        }
2531eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        return true;
2532e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2533e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2534e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* checks if package name is not null or empty */
2535e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isPackageNameValid(String browsedPackage) {
2536e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean isValid = (browsedPackage != null && browsedPackage.length() > 0);
2537c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
2538c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, "isPackageNameValid: browsedPackage = " + browsedPackage + "isValid = "
2539c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    + isValid);
2540c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
2541e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return isValid;
2542e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2543e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2544e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* checks if selected addressed player is already addressed */
2545e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isPlayerAlreadyAddressed(int selectedId) {
2546e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // checking if selected ID is same as the current addressed player id
2547e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean isAddressed = (mCurrAddrPlayerID == selectedId);
2548c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (DEBUG) {
2549c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            Log.d(TAG, "isPlayerAlreadyAddressed: isAddressed = " + isAddressed);
2550c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
2551e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return isAddressed;
2552e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2553e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2554e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    public void dump(StringBuilder sb) {
2555e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        sb.append("AVRCP:\n");
2556cc07ee436d00418ecc69ae3aace986f7fbf0823aMarie Janssen        ProfileService.println(sb, "mMediaAttributes: " + mMediaAttributes.toRedactedString());
2557e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags);
2558e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState);
2559e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT);
2560e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT);
2561e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs);
2562e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT);
2563e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mNextPosMs: " + mNextPosMs);
2564e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPrevPosMs: " + mPrevPosMs);
2565e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mFeatures: " + mFeatures);
2566e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mRemoteVolume: " + mRemoteVolume);
2567e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mLastRemoteVolume: " + mLastRemoteVolume);
2568e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mLastDirection: " + mLastDirection);
2569e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mVolumeStep: " + mVolumeStep);
2570e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mAudioStreamMax: " + mAudioStreamMax);
2571e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mVolCmdSetInProgress: " + mVolCmdSetInProgress);
2572e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mAbsVolRetryTimes: " + mAbsVolRetryTimes);
2573e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mVolumeMapping: " + mVolumeMapping.toString());
2574ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen        synchronized (this) {
2575c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (mMediaController != null) {
2576c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                ProfileService.println(sb,
2577c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        "mMediaController: " + mMediaController.getWrappedInstance() + " pkg "
2578ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                                + mMediaController.getPackageName());
2579c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
2580ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen        }
258178d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        ProfileService.println(sb, "");
258278d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        ProfileService.println(sb, "Media Players:");
2583511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
2584511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
2585511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                int key = entry.getKey();
2586c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                ProfileService.println(sb,
2587c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        ((mCurrAddrPlayerID == key) ? " *#" : "  #") + entry.getKey() + ": " + entry
2588c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                                .getValue());
2589511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
259005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
259105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
2592e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen        ProfileService.println(sb, "");
2593e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen        mAddressedMediaPlayer.dump(sb, mMediaController);
2594e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen
2595e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen        ProfileService.println(sb, "");
259678d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        ProfileService.println(sb, mPassthroughDispatched + " passthrough operations: ");
2597c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (mPassthroughDispatched > mPassthroughLogs.size()) {
259878d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            ProfileService.println(sb, "  (last " + mPassthroughLogs.size() + ")");
2599c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
260078d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        synchronized (mPassthroughLogs) {
260178d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            for (MediaKeyLog log : mPassthroughLogs) {
260278d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen                ProfileService.println(sb, "  " + log);
260378d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            }
260405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
260578d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        synchronized (mPassthroughPending) {
260678d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            for (MediaKeyLog log : mPassthroughPending) {
260778d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen                ProfileService.println(sb, "  " + log);
260878d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            }
2609b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen        }
2610aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov
2611aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov        // Print the blacklisted devices (for absolute volume control)
2612aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov        SharedPreferences pref =
2613aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov                mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, Context.MODE_PRIVATE);
2614aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov        Map<String, ?> allKeys = pref.getAll();
2615aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov        ProfileService.println(sb, "");
2616aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov        ProfileService.println(sb, "Runtime Blacklisted Devices (absolute volume):");
2617aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov        if (allKeys.isEmpty()) {
2618aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov            ProfileService.println(sb, "  None");
2619aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov        } else {
2620fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov            for (Map.Entry<String, ?> entry : allKeys.entrySet()) {
2621fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov                String key = entry.getKey();
2622fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov                Object value = entry.getValue();
2623fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov                if (value instanceof String) {
2624fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov                    ProfileService.println(sb, "  " + key + " " + value);
2625fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov                } else {
2626fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov                    ProfileService.println(sb, "  " + key + " Reason: Unknown");
2627fb7244393f6f3c14045d726e3c958403a7392519Pavlin Radoslavov                }
2628aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov            }
2629aad52567f7c3d4b88868f4dab95c148675c91816Pavlin Radoslavov        }
2630e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2631e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2632e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    public class AvrcpBrowseManager {
26338bc413b0b749ea9df59e858493273e05087fe887Jack He        public Map<String, BrowsedMediaPlayer> connList = new HashMap<String, BrowsedMediaPlayer>();
2634e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private AvrcpMediaRspInterface mMediaInterface;
2635e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private Context mContext;
2636e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2637e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public AvrcpBrowseManager(Context context, AvrcpMediaRspInterface mediaInterface) {
2638e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            mContext = context;
2639e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            mMediaInterface = mediaInterface;
2640e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2641e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2642e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void cleanup() {
2643e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Iterator entries = connList.entrySet().iterator();
2644e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            while (entries.hasNext()) {
2645e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Map.Entry entry = (Map.Entry) entries.next();
2646e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                BrowsedMediaPlayer browsedMediaPlayer = (BrowsedMediaPlayer) entry.getValue();
2647e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (browsedMediaPlayer != null) {
2648e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    browsedMediaPlayer.cleanup();
2649e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
2650e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2651e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // clean up the map
2652e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            connList.clear();
2653e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2654e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2655e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // get the a free media player interface based on the passed bd address
2656e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // if the no items is found for the passed media player then it assignes a
2657e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // available media player interface
2658e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public BrowsedMediaPlayer getBrowsedMediaPlayer(byte[] bdaddr) {
2659e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            BrowsedMediaPlayer mediaPlayer;
2660e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String bdaddrStr = new String(bdaddr);
266105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            if (connList.containsKey(bdaddrStr)) {
2662e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mediaPlayer = connList.get(bdaddrStr);
2663e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2664e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mediaPlayer = new BrowsedMediaPlayer(bdaddr, mContext, mMediaInterface);
2665e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                connList.put(bdaddrStr, mediaPlayer);
2666e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2667e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return mediaPlayer;
2668e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2669e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2670e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // clears the details pertaining to passed bdaddres
2671e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public boolean clearBrowsedMediaPlayer(byte[] bdaddr) {
2672e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String bdaddrStr = new String(bdaddr);
267305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            if (connList.containsKey(bdaddrStr)) {
2674e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                connList.remove(bdaddrStr);
2675e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return true;
2676e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2677e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return false;
2678e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2679e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2680e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public Map<String, BrowsedMediaPlayer> getConnList() {
2681e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return connList;
2682e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2683e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2684e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Helper function to convert colon separated bdaddr to byte string */
2685e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private byte[] hexStringToByteArray(String s) {
2686e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int len = s.length();
2687e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            byte[] data = new byte[len / 2];
2688e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            for (int i = 0; i < len; i += 2) {
2689c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(
2690c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        s.charAt(i + 1), 16));
2691e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2692e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return data;
2693e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2694e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2695e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2696e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
2697e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * private class which handles responses from AvrcpMediaManager. Maps responses to native
2698e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * responses. This class implements the AvrcpMediaRspInterface interface.
2699e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
2700e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private class AvrcpMediaRsp implements AvrcpMediaRspInterface {
2701e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private static final String TAG = "AvrcpMediaRsp";
2702e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
27032fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2704e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void setAddrPlayerRsp(byte[] address, int rspStatus) {
2705e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!setAddressedPlayerRspNative(address, rspStatus)) {
2706e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "setAddrPlayerRsp failed!");
2707e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2708e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2709e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
27102fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2711e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void setBrowsedPlayerRsp(byte[] address, int rspStatus, byte depth, int numItems,
2712e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                String[] textArray) {
2713e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!setBrowsedPlayerRspNative(address, rspStatus, depth, numItems, textArray)) {
2714e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "setBrowsedPlayerRsp failed!");
2715e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2716e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2717e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
27182fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2719e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void mediaPlayerListRsp(byte[] address, int rspStatus, MediaPlayerListRsp rspObj) {
2720e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) {
27218bc413b0b749ea9df59e858493273e05087fe887Jack He                if (!mediaPlayerListRspNative(address, rspStatus, sUIDCounter, rspObj.mItemType,
2722c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        rspObj.mNumItems, rspObj.mPlayerIds, rspObj.mPlayerTypes,
2723c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        rspObj.mPlayerSubTypes, rspObj.mPlayStatusValues,
2724c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        rspObj.mFeatureBitMaskValues, rspObj.mPlayerNameList)) {
2725eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                    Log.e(TAG, "mediaPlayerListRsp failed!");
2726c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
2727e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2728e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "mediaPlayerListRsp: rspObj is null");
2729eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                if (!mediaPlayerListRspNative(address, rspStatus, sUIDCounter, (byte) 0x00, 0, null,
2730c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        null, null, null, null, null)) {
2731eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                    Log.e(TAG, "mediaPlayerListRsp failed!");
2732c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
2733e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2734e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2735e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
27362fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2737e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void folderItemsRsp(byte[] address, int rspStatus, FolderItemsRsp rspObj) {
2738e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) {
2739e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!getFolderItemsRspNative(address, rspStatus, sUIDCounter, rspObj.mScope,
2740e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        rspObj.mNumItems, rspObj.mFolderTypes, rspObj.mPlayable, rspObj.mItemTypes,
2741e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        rspObj.mItemUid, rspObj.mDisplayNames, rspObj.mAttributesNum,
2742c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        rspObj.mAttrIds, rspObj.mAttrValues)) {
2743e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getFolderItemsRspNative failed!");
2744c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
2745e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2746e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "folderItemsRsp: rspObj is null or rspStatus is error:" + rspStatus);
2747c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (!getFolderItemsRspNative(address, rspStatus, sUIDCounter, (byte) 0x00, 0, null,
2748c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        null, null, null, null, null, null, null)) {
2749e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getFolderItemsRspNative failed!");
2750c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
2751e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2752e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2753e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2754e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
27552fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2756e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void changePathRsp(byte[] address, int rspStatus, int numItems) {
2757c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            if (!changePathRspNative(address, rspStatus, numItems)) {
2758e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "changePathRspNative failed!");
2759c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            }
2760e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2761e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
27622fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2763e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void getItemAttrRsp(byte[] address, int rspStatus, ItemAttrRsp rspObj) {
2764e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) {
2765e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!getItemAttrRspNative(address, rspStatus, rspObj.mNumAttr,
2766c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                        rspObj.mAttributesIds, rspObj.mAttributesArray)) {
2767e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getItemAttrRspNative failed!");
2768c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
2769e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2770e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "getItemAttrRsp: rspObj is null or rspStatus is error:" + rspStatus);
2771c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (!getItemAttrRspNative(address, rspStatus, (byte) 0x00, null, null)) {
2772e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getItemAttrRspNative failed!");
2773c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
2774e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2775e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2776e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
27772fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2778e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void playItemRsp(byte[] address, int rspStatus) {
2779e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!playItemRspNative(address, rspStatus)) {
2780e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "playItemRspNative failed!");
2781e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2782e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2783e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
27842fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2785e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void getTotalNumOfItemsRsp(byte[] address, int rspStatus, int uidCounter,
2786e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                int numItems) {
2787e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!getTotalNumOfItemsRspNative(address, rspStatus, sUIDCounter, numItems)) {
2788e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "getTotalNumOfItemsRspNative failed!");
2789e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2790e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2791e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
27922fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
279305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        public void addrPlayerChangedRsp(int type, int playerId, int uidCounter) {
2794e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspAddrPlayerChangedNative(type, playerId, sUIDCounter)) {
2795e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspAddrPlayerChangedNative failed!");
2796e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2797e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2798e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
27992fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2800e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void avalPlayerChangedRsp(byte[] address, int type) {
2801e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspAvalPlayerChangedNative(type)) {
2802e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspAvalPlayerChangedNative failed!");
2803e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2804e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2805e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
28062fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2807c960943641d79069f2f8177c0a3c378d8337b9c2Ajay Panicker        public void uidsChangedRsp(int type) {
2808e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspUIDsChangedNative(type, sUIDCounter)) {
2809e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspUIDsChangedNative failed!");
2810e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2811e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2812e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
28132fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2814e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void nowPlayingChangedRsp(int type) {
281505723ee9e6619814876a6cce5004d11b38c3f648Ajay Panicker            if (mNowPlayingListChangedNT != AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
2816c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                if (DEBUG) {
2817c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    Log.d(TAG, "NowPlayingListChanged: Not registered or requesting.");
2818c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                }
281905723ee9e6619814876a6cce5004d11b38c3f648Ajay Panicker                return;
282005723ee9e6619814876a6cce5004d11b38c3f648Ajay Panicker            }
282105723ee9e6619814876a6cce5004d11b38c3f648Ajay Panicker
2822e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspNowPlayingChangedNative(type)) {
2823e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspNowPlayingChangedNative failed!");
2824e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
282505723ee9e6619814876a6cce5004d11b38c3f648Ajay Panicker            mNowPlayingListChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
2826e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2827e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
28282fbb1d97d08d5d72fe824e543c714e56cd7be236Jack He        @Override
2829e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void trackChangedRsp(int type, byte[] uid) {
2830e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspTrackChangeNative(type, uid)) {
2831e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspTrackChangeNative failed!");
2832e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2833e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2834e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2835e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2836e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* getters for some private variables */
2837e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    public AvrcpBrowseManager getAvrcpBrowseManager() {
2838e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return mAvrcpBrowseManager;
2839e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2840e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
284105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    /* PASSTHROUGH COMMAND MANAGEMENT */
284205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
284305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    void handlePassthroughCmd(int op, int state) {
284405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        int code = avrcpPassthroughToKeyCode(op);
284505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (code == KeyEvent.KEYCODE_UNKNOWN) {
284605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            Log.w(TAG, "Ignoring passthrough of unknown key " + op + " state " + state);
284705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            return;
284805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
284905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        int action = KeyEvent.ACTION_DOWN;
2850c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        if (state == AvrcpConstants.KEY_STATE_RELEASE) {
2851c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            action = KeyEvent.ACTION_UP;
2852c4fbd756e2645147470c486ae96f2253f5e13a52Jack He        }
285305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        KeyEvent event = new KeyEvent(action, code);
285405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (!KeyEvent.isMediaKey(code)) {
285505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            Log.w(TAG, "Passthrough non-media key " + op + " (code " + code + ") state " + state);
285605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
285785aee8a39e8ca855b1b42724bca710aa1bfa6a7fAjay Panicker
285805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        mMediaSessionManager.dispatchMediaKeyEvent(event);
285905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        addKeyPending(event);
286005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
286105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
286205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private int avrcpPassthroughToKeyCode(int operation) {
286305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        switch (operation) {
286405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_UP:
286505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_UP;
286605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_DOWN:
286705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_DOWN;
286805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_LEFT:
286905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_LEFT;
287005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT:
287105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_RIGHT;
287205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT_UP:
287305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_UP_RIGHT;
287405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT_DOWN:
287505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_DOWN_RIGHT;
287605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_LEFT_UP:
287705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_UP_LEFT;
287805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_LEFT_DOWN:
287905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_DOWN_LEFT;
288005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_0:
288105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_0;
288205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_1:
288305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_1;
288405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_2:
288505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_2;
288605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_3:
288705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_3;
288805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_4:
288905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_4;
289005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_5:
289105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_5;
289205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_6:
289305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_6;
289405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_7:
289505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_7;
289605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_8:
289705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_8;
289805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_9:
289905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_9;
290005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_DOT:
290105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_DOT;
290205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_ENTER:
290305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_ENTER;
290405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CLEAR:
290505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_CLEAR;
290605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CHAN_UP:
290705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_CHANNEL_UP;
290805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CHAN_DOWN:
290905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_CHANNEL_DOWN;
291005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_PREV_CHAN:
291105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_LAST_CHANNEL;
291205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_INPUT_SEL:
291305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_TV_INPUT;
291405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_DISP_INFO:
291505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_INFO;
291605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_HELP:
291705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_HELP;
291805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_PAGE_UP:
291905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_PAGE_UP;
292005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_PAGE_DOWN:
292105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_PAGE_DOWN;
292205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_POWER:
292305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_POWER;
292405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_VOL_UP:
292505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_VOLUME_UP;
292605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_VOL_DOWN:
292705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_VOLUME_DOWN;
292805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_MUTE:
292905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MUTE;
29309bdbe9e309810d117c80328288a1819d39d8e7c8Andre Eisenbach            case BluetoothAvrcp.PASSTHROUGH_ID_PLAY:
29319bdbe9e309810d117c80328288a1819d39d8e7c8Andre Eisenbach                return KeyEvent.KEYCODE_MEDIA_PLAY;
293205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_STOP:
293305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_STOP;
29349bdbe9e309810d117c80328288a1819d39d8e7c8Andre Eisenbach            case BluetoothAvrcp.PASSTHROUGH_ID_PAUSE:
29359bdbe9e309810d117c80328288a1819d39d8e7c8Andre Eisenbach                return KeyEvent.KEYCODE_MEDIA_PAUSE;
293605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RECORD:
293705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_RECORD;
293805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_REWIND:
293905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_REWIND;
294005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR:
294105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
294205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_EJECT:
294305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_EJECT;
294405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_FORWARD:
294505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_NEXT;
294605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_BACKWARD:
294705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_PREVIOUS;
294805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F1:
294905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_F1;
295005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F2:
295105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_F2;
295205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F3:
295305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_F3;
295405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F4:
295505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_F4;
295605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F5:
295705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_F5;
295805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            // Fallthrough for all unknown key mappings
295905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SELECT:
296005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_ROOT_MENU:
296105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SETUP_MENU:
296205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CONT_MENU:
296305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_FAV_MENU:
296405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_EXIT:
296505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SOUND_SEL:
296605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_ANGLE:
296705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SUBPICT:
296805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_VENDOR:
296905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            default:
297005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_UNKNOWN;
297105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
297205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
297305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
297405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private void addKeyPending(KeyEvent event) {
297578d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        mPassthroughPending.add(new MediaKeyLog(System.currentTimeMillis(), event));
297605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
297705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
297805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private void recordKeyDispatched(KeyEvent event, String packageName) {
297905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        long time = System.currentTimeMillis();
298005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        Log.v(TAG, "recordKeyDispatched: " + event + " dispatched to " + packageName);
298178d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        setAddressedMediaSessionPackage(packageName);
298205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        synchronized (mPassthroughPending) {
298305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            Iterator<MediaKeyLog> pending = mPassthroughPending.iterator();
298405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            while (pending.hasNext()) {
298505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                MediaKeyLog log = pending.next();
298605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                if (log.addDispatch(time, event, packageName)) {
298705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    mPassthroughDispatched++;
298805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    mPassthroughLogs.add(log);
298905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    pending.remove();
299005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    return;
299105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                }
299205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            }
299378d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            Log.w(TAG, "recordKeyDispatch: can't find matching log!");
299405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
299505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
299605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
299705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private final MediaSessionManager.Callback mButtonDispatchCallback =
299805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            new MediaSessionManager.Callback() {
299905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                @Override
300005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                public void onMediaKeyEventDispatched(KeyEvent event, MediaSession.Token token) {
300105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    // Get the package name
300205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    android.media.session.MediaController controller =
300305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                            new android.media.session.MediaController(mContext, token);
300405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    String targetPackage = controller.getPackageName();
300505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    recordKeyDispatched(event, targetPackage);
300605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                }
300705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
300805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                @Override
300905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                public void onMediaKeyEventDispatched(KeyEvent event, ComponentName receiver) {
301005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    recordKeyDispatched(event, receiver.getPackageName());
301105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                }
301205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
301305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                @Override
301405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                public void onAddressedPlayerChanged(MediaSession.Token token) {
301505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    setActiveMediaSession(token);
301605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                }
301705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
301805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                @Override
301905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                public void onAddressedPlayerChanged(ComponentName receiver) {
302041527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                    if (receiver == null) {
302141527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                        // No active sessions, and no session to revive, give up.
302241527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                        setAddressedMediaSessionPackage(null);
302341527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                        return;
302441527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                    }
302541527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                    // We can still get a passthrough which will revive this player.
302605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    setAddressedMediaSessionPackage(receiver.getPackageName());
302705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                }
302805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            };
302905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
3030e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // Do not modify without updating the HAL bt_rc.h files.
3031e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
3032e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // match up with btrc_play_status_t enum of bt_rc.h
3033dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final byte PLAYSTATUS_STOPPED = 0;
3034dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final byte PLAYSTATUS_PLAYING = 1;
3035dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final byte PLAYSTATUS_PAUSED = 2;
3036dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final byte PLAYSTATUS_FWD_SEEK = 3;
3037dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final byte PLAYSTATUS_REV_SEEK = 4;
3038dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final byte PLAYSTATUS_ERROR = (byte) 255;
3039e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
3040e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // match up with btrc_media_attr_t enum of bt_rc.h
3041dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int MEDIA_ATTR_TITLE = 1;
3042dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int MEDIA_ATTR_ARTIST = 2;
3043dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int MEDIA_ATTR_ALBUM = 3;
3044dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int MEDIA_ATTR_TRACK_NUM = 4;
3045dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int MEDIA_ATTR_NUM_TRACKS = 5;
3046dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int MEDIA_ATTR_GENRE = 6;
3047dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int MEDIA_ATTR_PLAYING_TIME = 7;
3048e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
3049e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // match up with btrc_event_id_t enum of bt_rc.h
3050dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVT_PLAY_STATUS_CHANGED = 1;
3051dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVT_TRACK_CHANGED = 2;
3052dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVT_TRACK_REACHED_END = 3;
3053dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVT_TRACK_REACHED_START = 4;
3054dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVT_PLAY_POS_CHANGED = 5;
3055dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVT_BATT_STATUS_CHANGED = 6;
3056dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVT_SYSTEM_STATUS_CHANGED = 7;
3057dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVT_APP_SETTINGS_CHANGED = 8;
3058dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVENT_NOW_PLAYING_CONTENT_CHANGED = 9;
3059dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVT_AVBL_PLAYERS_CHANGED = 0xa;
3060dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVT_ADDR_PLAYER_CHANGED = 0xb;
3061dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    static final int EVENT_UIDS_CHANGED = 0x0c;
3062dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He
3063dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He    private static native void classInitNative();
3064c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3065c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native void initNative();
3066c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3067c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native void cleanupNative();
3068c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3069e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getPlayStatusRspNative(byte[] address, int playStatus, int songLen,
3070e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int songPos);
3071c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3072e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getElementAttrRspNative(byte[] address, byte numAttr, int[] attrIds,
3073e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String[] textArray);
3074c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3075c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean registerNotificationRspPlayStatusNative(int type, int playStatus);
3076c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3077c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean registerNotificationRspTrackChangeNative(int type, byte[] track);
3078c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3079aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private native boolean registerNotificationRspPlayPosNative(int type, int playPos);
3080c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
308117675906064bb72fdcca75baa56cdf8bb8968d01John Du    private native boolean setVolumeNative(int volume);
3082c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
30835c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta    private native boolean sendPassThroughCommandNative(int keyCode, int keyState);
3084c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3085e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean setAddressedPlayerRspNative(byte[] address, int rspStatus);
3086c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3087e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean setBrowsedPlayerRspNative(byte[] address, int rspStatus, byte depth,
3088e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int numItems, String[] textArray);
3089c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3090e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean mediaPlayerListRspNative(byte[] address, int rsStatus, int uidCounter,
3091b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He            byte itemType, int numItems, int[] playerIds, byte[] playerTypes, int[] playerSubTypes,
3092eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            byte[] playStatusValues, short[] featureBitMaskValues, String[] textArray);
3093c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3094e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getFolderItemsRspNative(byte[] address, int rspStatus, short uidCounter,
3095e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            byte scope, int numItems, byte[] folderTypes, byte[] playable, byte[] itemTypes,
3096b7461b17cad5476a7a528cbf2a0b9c9706c6faefJack He            byte[] itemUidArray, String[] textArray, int[] attributesNum, int[] attributesIds,
3097e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String[] attributesArray);
3098c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3099e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean changePathRspNative(byte[] address, int rspStatus, int numItems);
3100c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3101e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getItemAttrRspNative(byte[] address, int rspStatus, byte numAttr,
3102e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int[] attrIds, String[] textArray);
3103c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3104e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean playItemRspNative(byte[] address, int rspStatus);
3105c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3106e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getTotalNumOfItemsRspNative(byte[] address, int rspStatus,
3107e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int uidCounter, int numItems);
3108c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3109e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean searchRspNative(byte[] address, int rspStatus, int uidCounter,
3110e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int numItems);
3111c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3112e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean addToNowPlayingRspNative(byte[] address, int rspStatus);
3113c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3114c4fbd756e2645147470c486ae96f2253f5e13a52Jack He    private native boolean registerNotificationRspAddrPlayerChangedNative(int type, int playerId,
3115c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            int uidCounter);
3116c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3117e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean registerNotificationRspAvalPlayerChangedNative(int type);
3118c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3119e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean registerNotificationRspUIDsChangedNative(int type, int uidCounter);
3120c4fbd756e2645147470c486ae96f2253f5e13a52Jack He
3121e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean registerNotificationRspNowPlayingChangedNative(int type);
31225c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta
3123c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
3124