Avrcp.java revision 8ac88214fdbf5e5197033b89ba82a6bf728706a4
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.bluetooth.BluetoothDevice;
24e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.BroadcastReceiver;
25e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.ComponentName;
26c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.content.Context;
27e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.Intent;
28e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.IntentFilter;
29e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.pm.ApplicationInfo;
30e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.pm.PackageManager;
31e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.pm.PackageManager.NameNotFoundException;
32e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.content.pm.ResolveInfo;
3311798b011c962b602217b479130d413f3b30f19aLiejun Taoimport android.content.res.Resources;
3411798b011c962b602217b479130d413f3b30f19aLiejun Taoimport android.content.SharedPreferences;
35c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.AudioManager;
363b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssenimport android.media.MediaDescription;
370e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssenimport android.media.MediaMetadata;
383843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssenimport android.media.browse.MediaBrowser;
39e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.media.session.MediaSession;
40e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.media.session.MediaSession.QueueItem;
410e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssenimport android.media.session.MediaSessionManager;
420e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssenimport android.media.session.PlaybackState;
43e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport android.os.Bundle;
44c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Handler;
45c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.HandlerThread;
46c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Looper;
47c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Message;
48aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport android.os.SystemClock;
490427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panickerimport android.os.UserManager;
50c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.util.Log;
51881675b362bde18acbbcf69c513175addca4a8baZhenye Zhuimport android.view.KeyEvent;
526e29e12add362546784126119f26f04fc760f021RoboErik
53c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.bluetooth.btservice.ProfileService;
54e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport com.android.bluetooth.R;
55aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport com.android.bluetooth.Utils;
566e29e12add362546784126119f26f04fc760f021RoboErik
57c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.ArrayList;
5878d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssenimport java.util.Collections;
5911798b011c962b602217b479130d413f3b30f19aLiejun Taoimport java.util.HashMap;
60e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport java.util.Iterator;
61c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.List;
62e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shahimport java.util.Map;
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 {
721b70ec148be773651d5ad00e3ce0d28b3a63306dAjay Panicker    private static final boolean DEBUG = true;
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;
78c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private AvrcpMessageHandler mHandler;
790e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen    private MediaSessionManager mMediaSessionManager;
8029174eb9ad6e255d7ec216ab9a2ce8d20e2fe13cMarie Janssen    private @Nullable MediaController mMediaController;
810e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen    private MediaControllerListener mMediaControllerCb;
823b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen    private MediaAttributes mMediaAttributes;
83e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private PackageManager mPackageManager;
84c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mTransportControlFlags;
8529174eb9ad6e255d7ec216ab9a2ce8d20e2fe13cMarie Janssen    private @NonNull PlaybackState mCurrentPlayState;
860a429916782c20980e7f0893c503c633b8341f88Marie Janssen    private int mA2dpState;
87c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mPlayStatusChangedNT;
88c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mTrackChangedNT;
89f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    private int mPlayPosChangedNT;
90aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPlaybackIntervalMs;
91fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen    private long mLastReportedPosition;
92aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mNextPosMs;
93aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPrevPosMs;
9417675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mFeatures;
9511798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mRemoteVolume;
9611798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLastRemoteVolume;
9711798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mInitialRemoteVolume;
98be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen    private BrowsablePlayerListBuilder mBrowsableListBuilder;
9911798b011c962b602217b479130d413f3b30f19aLiejun Tao
10011798b011c962b602217b479130d413f3b30f19aLiejun Tao    /* Local volume in audio index 0-15 */
10111798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLocalVolume;
10211798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLastLocalVolume;
10311798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mAbsVolThreshold;
10411798b011c962b602217b479130d413f3b30f19aLiejun Tao
10511798b011c962b602217b479130d413f3b30f19aLiejun Tao    private String mAddress;
10611798b011c962b602217b479130d413f3b30f19aLiejun Tao    private HashMap<Integer, Integer> mVolumeMapping;
10711798b011c962b602217b479130d413f3b30f19aLiejun Tao
10817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mLastDirection;
1092e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private final int mVolumeStep;
1102e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private final int mAudioStreamMax;
11111798b011c962b602217b479130d413f3b30f19aLiejun Tao    private boolean mVolCmdAdjustInProgress;
11211798b011c962b602217b479130d413f3b30f19aLiejun Tao    private boolean mVolCmdSetInProgress;
11317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mAbsVolRetryTimes;
114eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
115384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen    private static final int NO_PLAYER_ID = 0;
116384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen
117e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private int mCurrAddrPlayerID;
118e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private int mCurrBrowsePlayerID;
119eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    private int mLastUsedPlayerID;
120e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private AvrcpMediaRsp mAvrcpMediaRsp;
121e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
122e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* UID counter to be shared across different files. */
123e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    static short sUIDCounter;
124ace834feb02adabd61f628c4471147aea02d939cJohn Du
12517675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* BTRC features */
12617675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_METADATA = 0x01;
12717675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02;
12817675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_BROWSE = 0x04;
12917675906064bb72fdcca75baa56cdf8bb8968d01John Du
13017675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* AVRC response codes, from avrc_defs */
13117675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_NOT_IMPL = 8;
13217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_ACCEPT = 9;
13317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_REJ = 10;
13417675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_IN_TRANS = 11;
13517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_IMPL_STBL = 12;
13617675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_CHANGED = 13;
13717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_INTERIM = 15;
13817675906064bb72fdcca75baa56cdf8bb8968d01John Du
139e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* AVRC request commands from Native */
140e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_RC_FEATURES = 1;
141e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_PLAY_STATUS = 2;
142e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_ELEM_ATTRS = 3;
143e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_REGISTER_NOTIFICATION = 4;
144e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_VOLUME_CHANGE = 5;
145e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_FOLDER_ITEMS = 6;
146e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_SET_ADDR_PLAYER = 7;
147e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_SET_BR_PLAYER = 8;
148e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_CHANGE_PATH = 9;
149e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_PLAY_ITEM = 10;
150e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_ITEM_ATTR = 11;
151e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS = 12;
152e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_NATIVE_REQ_PASS_THROUGH = 13;
153e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
154e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* other AVRC messages */
155e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_PLAY_INTERVAL_TIMEOUT = 14;
156e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_ADJUST_VOLUME = 15;
157e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_SET_ABSOLUTE_VOLUME = 16;
158e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_ABS_VOL_TIMEOUT = 17;
159e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_FAST_FORWARD = 18;
160e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private static final int MSG_REWIND = 19;
16105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private static final int MSG_SET_A2DP_AUDIO_STATE = 20;
16205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private static final int MSG_ADDRESSED_PLAYER_CHANGED_RSP = 21;
16305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private static final int MSG_AVAILABLE_PLAYERS_CHANGED_RSP = 22;
16405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private static final int MSG_NOW_PLAYING_CHANGED_RSP = 23;
16505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
16617675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int CMD_TIMEOUT_DELAY = 2000;
167f8201e1c6bf7fadc0a332151a652325a7f31255aLiejun Tao    private static final int MAX_ERROR_RETRY_TIMES = 6;
16817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRCP_MAX_VOL = 127;
16917675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRCP_BASE_VOLUME_STEP = 1;
170ace834feb02adabd61f628c4471147aea02d939cJohn Du
171e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Communicates with MediaPlayer to fetch media content */
172e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private BrowsedMediaPlayer mBrowsedMediaPlayer;
173e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
17405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    /* Addressed player handling */
175e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private AddressedMediaPlayer mAddressedMediaPlayer;
176e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
177e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* List of Media player instances, useful for retrieving MediaPlayerList or MediaPlayerInfo */
178eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    private SortedMap<Integer, MediaPlayerInfo> mMediaPlayerInfoList;
179e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
180e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* List of media players which supports browse */
1815146bd27869df5473aa53e6271266f51733971efMarie Janssen    private List<BrowsePlayerInfo> mBrowsePlayerInfoList;
182e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
183e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Manage browsed players */
184e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private AvrcpBrowseManager mAvrcpBrowseManager;
185e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
186e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Broadcast receiver for device connections intent broadcasts */
187e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private final BroadcastReceiver mAvrcpReceiver = new AvrcpServiceBroadcastReceiver();
1880427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker    private final BroadcastReceiver mBootReceiver = new AvrcpServiceBootReceiver();
189e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
19005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    /* Recording passthrough key dispatches */
19105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    static private final int PASSTHROUGH_LOG_MAX_SIZE = DEBUG ? 50 : 10;
19205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private EvictingQueue<MediaKeyLog> mPassthroughLogs; // Passthorugh keys dispatched
19378d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen    private List<MediaKeyLog> mPassthroughPending; // Passthrough keys sent not dispatched yet
19405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private int mPassthroughDispatched; // Number of keys dispatched
19505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
19605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private class MediaKeyLog {
19705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        private long mTimeSent;
19805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        private long mTimeProcessed;
19905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        private String mPackage;
20005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        private KeyEvent mEvent;
20105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
20205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        public MediaKeyLog(long time, KeyEvent event) {
20305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mEvent = event;
20405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mTimeSent = time;
20505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
20605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
20705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        public boolean addDispatch(long time, KeyEvent event, String packageName) {
20805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            if (mPackage != null) return false;
20905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            if (event.getAction() != mEvent.getAction()) return false;
21005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            if (event.getKeyCode() != mEvent.getKeyCode()) return false;
21105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mPackage = packageName;
21205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mTimeProcessed = time;
21305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            return true;
21405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
21505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
21605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        public String toString() {
21705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            StringBuilder sb = new StringBuilder();
21805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            sb.append(android.text.format.DateFormat.format("MM-dd HH:mm:ss", mTimeSent));
21905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            sb.append(" " + mEvent.toString());
22005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            if (mPackage == null) {
22105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                sb.append(" (undispatched)");
22205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            } else {
22305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                sb.append(" to " + mPackage);
22405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                sb.append(" in " + (mTimeProcessed - mTimeSent) + "ms");
22505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            }
22605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            return sb.toString();
22705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
22805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
22905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
230c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    static {
231c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        classInitNative();
232c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
233c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
234c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Avrcp(Context context) {
2353b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        mMediaAttributes = new MediaAttributes(null);
2360e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        mCurrentPlayState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build();
2370a429916782c20980e7f0893c503c633b8341f88Marie Janssen        mA2dpState = BluetoothA2dp.STATE_NOT_PLAYING;
238e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
239e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
240aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        mPlaybackIntervalMs = 0L;
241e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
242fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        mLastReportedPosition = -1;
2433635a926bd7316a55b288a54d409a1070a9c19e8Marie Janssen        mNextPosMs = -1;
2443635a926bd7316a55b288a54d409a1070a9c19e8Marie Janssen        mPrevPosMs = -1;
24517675906064bb72fdcca75baa56cdf8bb8968d01John Du        mFeatures = 0;
24611798b011c962b602217b479130d413f3b30f19aLiejun Tao        mRemoteVolume = -1;
24711798b011c962b602217b479130d413f3b30f19aLiejun Tao        mInitialRemoteVolume = -1;
24811798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLastRemoteVolume = -1;
24917675906064bb72fdcca75baa56cdf8bb8968d01John Du        mLastDirection = 0;
25011798b011c962b602217b479130d413f3b30f19aLiejun Tao        mVolCmdAdjustInProgress = false;
25111798b011c962b602217b479130d413f3b30f19aLiejun Tao        mVolCmdSetInProgress = false;
25217675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAbsVolRetryTimes = 0;
25311798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLocalVolume = -1;
25411798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLastLocalVolume = -1;
25511798b011c962b602217b479130d413f3b30f19aLiejun Tao        mAbsVolThreshold = 0;
25611798b011c962b602217b479130d413f3b30f19aLiejun Tao        mVolumeMapping = new HashMap<Integer, Integer>();
257e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        sUIDCounter = AvrcpConstants.DEFAULT_UID_COUNTER;
258384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        mCurrAddrPlayerID = NO_PLAYER_ID;
259294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen        mCurrBrowsePlayerID = 0;
260c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mContext = context;
261eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        mLastUsedPlayerID = 0;
262e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAddressedMediaPlayer = null;
263c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
264c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        initNative();
265c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
266e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mMediaSessionManager = (MediaSessionManager) context.getSystemService(
267e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Context.MEDIA_SESSION_SERVICE);
268c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
2692e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mAudioStreamMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
2702e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mVolumeStep = Math.max(AVRCP_BASE_VOLUME_STEP, AVRCP_MAX_VOL/mAudioStreamMax);
271e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
27211798b011c962b602217b479130d413f3b30f19aLiejun Tao        Resources resources = context.getResources();
27311798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (resources != null) {
27411798b011c962b602217b479130d413f3b30f19aLiejun Tao            mAbsVolThreshold = resources.getInteger(R.integer.a2dp_absolute_volume_initial_threshold);
27511798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
276e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
277be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen        mBrowsableListBuilder = new BrowsablePlayerListBuilder();
278be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen
279e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // Register for package removal intent broadcasts for media button receiver persistence
280e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        IntentFilter pkgFilter = new IntentFilter();
281e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
282e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
283e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
284e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
285e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        pkgFilter.addDataScheme("package");
286e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        context.registerReceiver(mAvrcpReceiver, pkgFilter);
2870427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker
2880427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        IntentFilter bootFilter = new IntentFilter();
2890427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        bootFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
2900427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        context.registerReceiver(mBootReceiver, bootFilter);
291c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
292c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
293c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void start() {
294c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler");
295c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        thread.start();
296c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Looper looper = thread.getLooper();
297c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler = new AvrcpMessageHandler(looper);
2989d4035307b85e78f10fba961e225ca09bfb7d0c7Jakub Pawlowski        mMediaControllerCb = new MediaControllerListener();
299e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAvrcpMediaRsp = new AvrcpMediaRsp();
300eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        mMediaPlayerInfoList = new TreeMap<Integer, MediaPlayerInfo>();
3015146bd27869df5473aa53e6271266f51733971efMarie Janssen        mBrowsePlayerInfoList = Collections.synchronizedList(new ArrayList<BrowsePlayerInfo>());
30205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        mPassthroughDispatched = 0;
30305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        mPassthroughLogs = new EvictingQueue<MediaKeyLog>(PASSTHROUGH_LOG_MAX_SIZE);
30478d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        mPassthroughPending = Collections.synchronizedList(new ArrayList<MediaKeyLog>());
305f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen        if (mMediaSessionManager != null) {
306f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen            mMediaSessionManager.addOnActiveSessionsChangedListener(mActiveSessionListener, null,
307f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen                    mHandler);
30805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mMediaSessionManager.setCallback(mButtonDispatchCallback, null);
309f65765e71b2a6552c319eb5199914045a1ecdb04Marie Janssen        }
310e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mPackageManager = mContext.getApplicationContext().getPackageManager();
311e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
312e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* create object to communicate with addressed player */
313e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAddressedMediaPlayer = new AddressedMediaPlayer(mAvrcpMediaRsp);
314e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
315e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* initialize BrowseMananger which manages Browse commands and response */
316e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAvrcpBrowseManager = new AvrcpBrowseManager(mContext, mAvrcpMediaRsp);
3170427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker
31805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        initMediaPlayersList();
31911bf73ff614f48a41dc379763bc007f271197b26Ajay Panicker
3200427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        UserManager manager = UserManager.get(mContext);
3210427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        if (manager == null || manager.isUserUnlocked()) {
3220427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker            if (DEBUG) Log.d(TAG, "User already unlocked, initializing player lists");
3233843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            // initialize browsable player list and build media player list
324be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen            mBrowsableListBuilder.start();
3250427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        }
326c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
327c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
328066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    public static Avrcp make(Context context) {
329c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (DEBUG) Log.v(TAG, "make");
330c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Avrcp ar = new Avrcp(context);
331c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ar.start();
332c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return ar;
333c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
334c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
335c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    public void doQuit() {
336e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "doQuit");
337ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen        synchronized (this) {
338ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen            if (mMediaController != null) mMediaController.unregisterCallback(mMediaControllerCb);
339ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen        }
3407c7cc128e93e7e1db8a5ed7f69583ddc6d99493eMarie Janssen        if (mMediaSessionManager != null) {
3417c7cc128e93e7e1db8a5ed7f69583ddc6d99493eMarie Janssen            mMediaSessionManager.setCallback(null, null);
3427c7cc128e93e7e1db8a5ed7f69583ddc6d99493eMarie Janssen            mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveSessionListener);
3437c7cc128e93e7e1db8a5ed7f69583ddc6d99493eMarie Janssen        }
3447c7cc128e93e7e1db8a5ed7f69583ddc6d99493eMarie Janssen
345c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.removeCallbacksAndMessages(null);
346c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Looper looper = mHandler.getLooper();
347c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (looper != null) {
348c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            looper.quit();
349c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
350e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
351e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler = null;
352e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mContext.unregisterReceiver(mAvrcpReceiver);
3530427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        mContext.unregisterReceiver(mBootReceiver);
354e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
355be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen        mBrowsableListBuilder.cleanup();
356e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAddressedMediaPlayer.cleanup();
357e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mAvrcpBrowseManager.cleanup();
358c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
359c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
360c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    public void cleanup() {
361e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "cleanup");
362c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        cleanupNative();
36311798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (mVolumeMapping != null)
36411798b011c962b602217b479130d413f3b30f19aLiejun Tao            mVolumeMapping.clear();
365c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
366c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
3670e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen    private class MediaControllerListener extends MediaController.Callback {
3680e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        @Override
3690e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        public void onMetadataChanged(MediaMetadata metadata) {
37029174eb9ad6e255d7ec216ab9a2ce8d20e2fe13cMarie Janssen            if (DEBUG) Log.v(TAG, "onMetadataChanged");
3710a429916782c20980e7f0893c503c633b8341f88Marie Janssen            updateCurrentMediaState();
372c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
373bc10e7d58aa55da25c18d8056a0254a2b736146aZhihai Xu        @Override
374e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public synchronized void onPlaybackStateChanged(PlaybackState state) {
375eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            if (DEBUG) Log.v(TAG, "onPlaybackStateChanged: state " + state.toString());
3760a429916782c20980e7f0893c503c633b8341f88Marie Janssen            updateCurrentMediaState();
377c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
378c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
379c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
3800e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        public void onSessionDestroyed() {
3810e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            Log.v(TAG, "MediaController session destroyed");
382ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen            synchronized (Avrcp.this) {
383ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                if (mMediaController != null)
384ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                    removeMediaController(mMediaController.getWrappedInstance());
385384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            }
386c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
387c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
388c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
389e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void onQueueChanged(List<MediaSession.QueueItem> queue) {
390e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (queue == null) {
391e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.v(TAG, "onQueueChanged: received null queue");
392e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return;
393e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
3942b903c7262c9b8c0493e36b93b37831e7e075bfcMarie Janssen
395e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Log.v(TAG, "onQueueChanged: NowPlaying list changed, Queue Size = "+ queue.size());
396e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            mAddressedMediaPlayer.updateNowPlayingList(queue);
397e2619781c799435cf0273d381069c754c5f89a20Marie Janssen            mHandler.sendEmptyMessage(MSG_NOW_PLAYING_CHANGED_RSP);
398c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
399c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
400c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
401c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    /** Handles Avrcp messages. */
402c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private final class AvrcpMessageHandler extends Handler {
403c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        private AvrcpMessageHandler(Looper looper) {
404c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            super(looper);
405c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
406c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
407c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
408c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public void handleMessage(Message msg) {
409c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            switch (msg.what) {
410e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_RC_FEATURES:
411e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            {
41217675906064bb72fdcca75baa56cdf8bb8968d01John Du                String address = (String) msg.obj;
413e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_RC_FEATURES: address="+address+
414e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        ", features="+msg.arg1);
41517675906064bb72fdcca75baa56cdf8bb8968d01John Du                mFeatures = msg.arg1;
41611798b011c962b602217b479130d413f3b30f19aLiejun Tao                mFeatures = modifyRcFeatureFromBlacklist(mFeatures, address);
41717675906064bb72fdcca75baa56cdf8bb8968d01John Du                mAudioManager.avrcpSupportsAbsoluteVolume(address, isAbsoluteVolumeSupported());
41811798b011c962b602217b479130d413f3b30f19aLiejun Tao                mLastLocalVolume = -1;
41911798b011c962b602217b479130d413f3b30f19aLiejun Tao                mRemoteVolume = -1;
42011798b011c962b602217b479130d413f3b30f19aLiejun Tao                mLocalVolume = -1;
42111798b011c962b602217b479130d413f3b30f19aLiejun Tao                mInitialRemoteVolume = -1;
42211798b011c962b602217b479130d413f3b30f19aLiejun Tao                mAddress = address;
42311798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mVolumeMapping != null)
42411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolumeMapping.clear();
42517675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
426e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
42717675906064bb72fdcca75baa56cdf8bb8968d01John Du
428e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_PLAY_STATUS:
429e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            {
430e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] address = (byte[]) msg.obj;
431e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                int btstate = convertPlayStateToPlayStatus(mCurrentPlayState);
432e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                int length = (int) mMediaAttributes.getLength();
433e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                int position = (int) getPlayPosition();
434e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                if (DEBUG)
435e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                    Log.v(TAG, "MSG_NATIVE_REQ_GET_PLAY_STATUS, responding with state " + btstate
436e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                                    + " len " + length + " pos " + position);
437e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                getPlayStatusRspNative(address, btstate, length, position);
438c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
439e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
440c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
441e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_ELEM_ATTRS:
442e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            {
443c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                String[] textArray;
444e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                AvrcpCmd.ElementAttrCmd elem = (AvrcpCmd.ElementAttrCmd) msg.obj;
445e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte numAttr = elem.mNumAttr;
446e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                int[] attrIds = elem.mAttrIDs;
447e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_ELEM_ATTRS:numAttr=" + numAttr);
448c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                textArray = new String[numAttr];
449e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                StringBuilder responseDebug = new StringBuilder();
450e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                responseDebug.append("getElementAttr response: ");
451c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                for (int i = 0; i < numAttr; ++i) {
4523b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    textArray[i] = mMediaAttributes.getString(attrIds[i]);
453e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                    responseDebug.append("[" + attrIds[i] + "=" + textArray[i] + "] ");
454c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                }
455e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                Log.v(TAG, responseDebug.toString());
456e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] bdaddr = elem.mAddress;
457e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                getElementAttrRspNative(bdaddr, numAttr, attrIds, textArray);
458c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
459e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
460c1124a7c6679f612b80926a19084655f9a71580aMarie Janssen
461e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_REGISTER_NOTIFICATION:
462e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_REGISTER_NOTIFICATION:event=" + msg.arg1 +
463e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        " param=" + msg.arg2);
464e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                processRegisterNotification((byte[]) msg.obj, msg.arg1, msg.arg2);
465c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
466c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
467e2619781c799435cf0273d381069c754c5f89a20Marie Janssen            case MSG_AVAILABLE_PLAYERS_CHANGED_RSP:
468e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                if (DEBUG) Log.v(TAG, "MSG_AVAILABLE_PLAYERS_CHANGED_RSP");
469e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                removeMessages(MSG_AVAILABLE_PLAYERS_CHANGED_RSP);
470e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                registerNotificationRspAvalPlayerChangedNative(
471e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                        AvrcpConstants.NOTIFICATION_TYPE_CHANGED);
472e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                break;
473e2619781c799435cf0273d381069c754c5f89a20Marie Janssen
474e2619781c799435cf0273d381069c754c5f89a20Marie Janssen            case MSG_NOW_PLAYING_CHANGED_RSP:
475e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                if (DEBUG) Log.v(TAG, "MSG_NOW_PLAYING_CHANGED_RSP");
476e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                removeMessages(MSG_NOW_PLAYING_CHANGED_RSP);
477e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                registerNotificationRspNowPlayingChangedNative(
478e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                        AvrcpConstants.NOTIFICATION_TYPE_CHANGED);
479e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                break;
480e2619781c799435cf0273d381069c754c5f89a20Marie Janssen
481e2619781c799435cf0273d381069c754c5f89a20Marie Janssen            case MSG_ADDRESSED_PLAYER_CHANGED_RSP:
482e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                // Later addressed players override earlier ones.
483e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                if (hasMessages(MSG_ADDRESSED_PLAYER_CHANGED_RSP)) {
484e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                    Log.i(TAG, "MSG_ADDRESSED_PLAYER_CHANGED_RSP: skip, more changes in queue");
485e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                    break;
486e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                }
487e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                if (DEBUG)
488e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                    Log.v(TAG, "MSG_ADDRESSED_PLAYER_CHANGED_RSP: newAddrPlayer = " + msg.arg1);
489e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                registerNotificationRspAddrPlayerChangedNative(
490e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                        AvrcpConstants.NOTIFICATION_TYPE_CHANGED, msg.arg1, sUIDCounter);
491e2619781c799435cf0273d381069c754c5f89a20Marie Janssen                break;
492e2619781c799435cf0273d381069c754c5f89a20Marie Janssen
493e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_PLAY_INTERVAL_TIMEOUT:
494e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_PLAY_INTERVAL_TIMEOUT");
495f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                sendPlayPosNotificationRsp(false);
496aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                break;
497aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
498e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_VOLUME_CHANGE:
49911798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (!isAbsoluteVolumeSupported()) {
500e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                    if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_VOLUME_CHANGE ignored, not supported");
50111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
50211798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
503e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                byte absVol = (byte) ((byte) msg.arg1 & 0x7f); // discard MSB as it is RFD
504e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                if (DEBUG)
505e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                    Log.v(TAG, "MSG_NATIVE_REQ_VOLUME_CHANGE: volume=" + absVol + " ctype="
506e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen                                    + msg.arg2);
50711798b011c962b602217b479130d413f3b30f19aLiejun Tao
50811798b011c962b602217b479130d413f3b30f19aLiejun Tao                boolean volAdj = false;
50917675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (msg.arg2 == AVRC_RSP_ACCEPT || msg.arg2 == AVRC_RSP_REJ) {
51011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mVolCmdAdjustInProgress == false && mVolCmdSetInProgress == false) {
51117675906064bb72fdcca75baa56cdf8bb8968d01John Du                        Log.e(TAG, "Unsolicited response, ignored");
51217675906064bb72fdcca75baa56cdf8bb8968d01John Du                        break;
51317675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
514e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    removeMessages(MSG_ABS_VOL_TIMEOUT);
51511798b011c962b602217b479130d413f3b30f19aLiejun Tao
51611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    volAdj = mVolCmdAdjustInProgress;
51711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolCmdAdjustInProgress = false;
51811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolCmdSetInProgress = false;
51917675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes = 0;
52017675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
52111798b011c962b602217b479130d413f3b30f19aLiejun Tao
52211798b011c962b602217b479130d413f3b30f19aLiejun Tao                // convert remote volume to local volume
52311798b011c962b602217b479130d413f3b30f19aLiejun Tao                int volIndex = convertToAudioStreamVolume(absVol);
52411798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mInitialRemoteVolume == -1) {
52511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mInitialRemoteVolume = absVol;
52611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mAbsVolThreshold > 0 && mAbsVolThreshold < mAudioStreamMax && volIndex > mAbsVolThreshold) {
52711798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.v(TAG, "remote inital volume too high " + volIndex + ">" + mAbsVolThreshold);
528e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        Message msg1 = mHandler.obtainMessage(MSG_SET_ABSOLUTE_VOLUME, mAbsVolThreshold , 0);
52911798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mHandler.sendMessage(msg1);
53011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mRemoteVolume = absVol;
53111798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLocalVolume = volIndex;
53211798b011c962b602217b479130d413f3b30f19aLiejun Tao                        break;
53311798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
53411798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
53511798b011c962b602217b479130d413f3b30f19aLiejun Tao
5360e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                if (mLocalVolume != volIndex && (msg.arg2 == AVRC_RSP_ACCEPT ||
5370e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                                                 msg.arg2 == AVRC_RSP_CHANGED ||
5380e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                                                 msg.arg2 == AVRC_RSP_INTERIM)) {
53911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    /* If the volume has successfully changed */
54011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mLocalVolume = volIndex;
54111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mLastLocalVolume != -1 && msg.arg2 == AVRC_RSP_ACCEPT) {
54211798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (mLastLocalVolume != volIndex) {
54311798b011c962b602217b479130d413f3b30f19aLiejun Tao                            /* remote volume changed more than requested due to
54411798b011c962b602217b479130d413f3b30f19aLiejun Tao                             * local and remote has different volume steps */
54511798b011c962b602217b479130d413f3b30f19aLiejun Tao                            if (DEBUG) Log.d(TAG, "Remote returned volume does not match desired volume "
546e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                                    + mLastLocalVolume + " vs " + volIndex);
54711798b011c962b602217b479130d413f3b30f19aLiejun Tao                            mLastLocalVolume = mLocalVolume;
54811798b011c962b602217b479130d413f3b30f19aLiejun Tao                        }
54911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
55011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    // remember the remote volume value, as it's the one supported by remote
55111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (volAdj) {
55211798b011c962b602217b479130d413f3b30f19aLiejun Tao                        synchronized (mVolumeMapping) {
553e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                            mVolumeMapping.put(volIndex, (int) absVol);
55411798b011c962b602217b479130d413f3b30f19aLiejun Tao                            if (DEBUG) Log.v(TAG, "remember volume mapping " +volIndex+ "-"+absVol);
55511798b011c962b602217b479130d413f3b30f19aLiejun Tao                        }
55611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
55711798b011c962b602217b479130d413f3b30f19aLiejun Tao
55811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    notifyVolumeChanged(mLocalVolume);
55911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mRemoteVolume = absVol;
560e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    long pecentVolChanged = ((long) absVol * 100) / 0x7f;
5615c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                    Log.e(TAG, "percent volume changed: " + pecentVolChanged + "%");
56217675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else if (msg.arg2 == AVRC_RSP_REJ) {
56317675906064bb72fdcca75baa56cdf8bb8968d01John Du                    Log.e(TAG, "setAbsoluteVolume call rejected");
56411798b011c962b602217b479130d413f3b30f19aLiejun Tao                } else if (volAdj && mLastRemoteVolume > 0 && mLastRemoteVolume < AVRCP_MAX_VOL &&
5650e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                        mLocalVolume == volIndex &&
566e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        (msg.arg2 == AVRC_RSP_ACCEPT)) {
56711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    /* oops, the volume is still same, remote does not like the value
56811798b011c962b602217b479130d413f3b30f19aLiejun Tao                     * retry a volume one step up/down */
56911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.d(TAG, "Remote device didn't tune volume, let's try one more step.");
57011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    int retry_volume = Math.min(AVRCP_MAX_VOL,
57111798b011c962b602217b479130d413f3b30f19aLiejun Tao                            Math.max(0, mLastRemoteVolume + mLastDirection));
57211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (setVolumeNative(retry_volume)) {
57311798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLastRemoteVolume = retry_volume;
574e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
57511798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mVolCmdAdjustInProgress = true;
57611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
57717675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
57817675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
57917675906064bb72fdcca75baa56cdf8bb8968d01John Du
580e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_ADJUST_VOLUME:
58111798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (!isAbsoluteVolumeSupported()) {
582e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    if (DEBUG) Log.v(TAG, "ignore MSG_ADJUST_VOLUME");
58311798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
58411798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
58511798b011c962b602217b479130d413f3b30f19aLiejun Tao
586e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.d(TAG, "MSG_ADJUST_VOLUME: direction=" + msg.arg1);
58711798b011c962b602217b479130d413f3b30f19aLiejun Tao
58811798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mVolCmdAdjustInProgress || mVolCmdSetInProgress) {
58917675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
59017675906064bb72fdcca75baa56cdf8bb8968d01John Du                    break;
59117675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
59211798b011c962b602217b479130d413f3b30f19aLiejun Tao
59311798b011c962b602217b479130d413f3b30f19aLiejun Tao                // Remote device didn't set initial volume. Let's black list it
59411798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mInitialRemoteVolume == -1) {
59511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    Log.d(TAG, "remote " + mAddress + " never tell us initial volume, black list it.");
59611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    blackListCurrentDevice();
59711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
59811798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
59911798b011c962b602217b479130d413f3b30f19aLiejun Tao
60017675906064bb72fdcca75baa56cdf8bb8968d01John Du                // Wait on verification on volume from device, before changing the volume.
60111798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mRemoteVolume != -1 && (msg.arg1 == -1 || msg.arg1 == 1)) {
60211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    int setVol = -1;
60311798b011c962b602217b479130d413f3b30f19aLiejun Tao                    int targetVolIndex = -1;
60411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mLocalVolume == 0 && msg.arg1 == -1) {
60511798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.w(TAG, "No need to Vol down from 0.");
60611798b011c962b602217b479130d413f3b30f19aLiejun Tao                        break;
60711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
60811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mLocalVolume == mAudioStreamMax && msg.arg1 == 1) {
60911798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.w(TAG, "No need to Vol up from max.");
61011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        break;
61111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
61211798b011c962b602217b479130d413f3b30f19aLiejun Tao
61311798b011c962b602217b479130d413f3b30f19aLiejun Tao                    targetVolIndex = mLocalVolume + msg.arg1;
61411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.d(TAG, "Adjusting volume to  " + targetVolIndex);
61511798b011c962b602217b479130d413f3b30f19aLiejun Tao
61611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    Integer i;
61711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    synchronized (mVolumeMapping) {
61811798b011c962b602217b479130d413f3b30f19aLiejun Tao                        i = mVolumeMapping.get(targetVolIndex);
61911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
62011798b011c962b602217b479130d413f3b30f19aLiejun Tao
62111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (i != null) {
62211798b011c962b602217b479130d413f3b30f19aLiejun Tao                        /* if we already know this volume mapping, use it */
62311798b011c962b602217b479130d413f3b30f19aLiejun Tao                        setVol = i.byteValue();
62411798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (setVol == mRemoteVolume) {
62511798b011c962b602217b479130d413f3b30f19aLiejun Tao                            if (DEBUG) Log.d(TAG, "got same volume from mapping for " + targetVolIndex + ", ignore.");
62611798b011c962b602217b479130d413f3b30f19aLiejun Tao                            setVol = -1;
62711798b011c962b602217b479130d413f3b30f19aLiejun Tao                        }
62811798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.d(TAG, "set volume from mapping " + targetVolIndex + "-" + setVol);
62911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
63011798b011c962b602217b479130d413f3b30f19aLiejun Tao
63111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (setVol == -1) {
63211798b011c962b602217b479130d413f3b30f19aLiejun Tao                        /* otherwise use phone steps */
63311798b011c962b602217b479130d413f3b30f19aLiejun Tao                        setVol = Math.min(AVRCP_MAX_VOL,
634e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                                convertToAvrcpVolume(Math.max(0, targetVolIndex)));
63511798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.d(TAG, "set volume from local volume "+ targetVolIndex+"-"+ setVol);
63611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
63711798b011c962b602217b479130d413f3b30f19aLiejun Tao
63817675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (setVolumeNative(setVol)) {
639e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
64011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mVolCmdAdjustInProgress = true;
64117675906064bb72fdcca75baa56cdf8bb8968d01John Du                        mLastDirection = msg.arg1;
64211798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLastRemoteVolume = setVol;
64311798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLastLocalVolume = targetVolIndex;
64411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    } else {
64511798b011c962b602217b479130d413f3b30f19aLiejun Tao                         if (DEBUG) Log.d(TAG, "setVolumeNative failed");
64617675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
64717675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else {
648e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "Unknown direction in MSG_ADJUST_VOLUME");
64917675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
65017675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
65117675906064bb72fdcca75baa56cdf8bb8968d01John Du
652e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_SET_ABSOLUTE_VOLUME:
65311798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (!isAbsoluteVolumeSupported()) {
654e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    if (DEBUG) Log.v(TAG, "ignore MSG_SET_ABSOLUTE_VOLUME");
65511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
65611798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
65711798b011c962b602217b479130d413f3b30f19aLiejun Tao
658e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_SET_ABSOLUTE_VOLUME");
65911798b011c962b602217b479130d413f3b30f19aLiejun Tao
66011798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mVolCmdSetInProgress || mVolCmdAdjustInProgress) {
66117675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
66217675906064bb72fdcca75baa56cdf8bb8968d01John Du                    break;
66317675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
66411798b011c962b602217b479130d413f3b30f19aLiejun Tao
66511798b011c962b602217b479130d413f3b30f19aLiejun Tao                // Remote device didn't set initial volume. Let's black list it
66611798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mInitialRemoteVolume == -1) {
66711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.d(TAG, "remote " + mAddress + " never tell us initial volume, black list it.");
66811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    blackListCurrentDevice();
66911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
67011798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
67111798b011c962b602217b479130d413f3b30f19aLiejun Tao
67211798b011c962b602217b479130d413f3b30f19aLiejun Tao                int avrcpVolume = convertToAvrcpVolume(msg.arg1);
67311798b011c962b602217b479130d413f3b30f19aLiejun Tao                avrcpVolume = Math.min(AVRCP_MAX_VOL, Math.max(0, avrcpVolume));
6743b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                if (DEBUG) Log.d(TAG, "Setting volume to " + msg.arg1 + "-" + avrcpVolume);
67511798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (setVolumeNative(avrcpVolume)) {
676e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
67711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolCmdSetInProgress = true;
67811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mLastRemoteVolume = avrcpVolume;
67911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mLastLocalVolume = msg.arg1;
68011798b011c962b602217b479130d413f3b30f19aLiejun Tao                } else {
68111798b011c962b602217b479130d413f3b30f19aLiejun Tao                     if (DEBUG) Log.d(TAG, "setVolumeNative failed");
68217675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
68317675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
68417675906064bb72fdcca75baa56cdf8bb8968d01John Du
685e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_ABS_VOL_TIMEOUT:
686e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_ABS_VOL_TIMEOUT: Volume change cmd timed out.");
68711798b011c962b602217b479130d413f3b30f19aLiejun Tao                mVolCmdAdjustInProgress = false;
68811798b011c962b602217b479130d413f3b30f19aLiejun Tao                mVolCmdSetInProgress = false;
68917675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (mAbsVolRetryTimes >= MAX_ERROR_RETRY_TIMES) {
69017675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes = 0;
691f8201e1c6bf7fadc0a332151a652325a7f31255aLiejun Tao                    /* too many volume change failures, black list the device */
692f8201e1c6bf7fadc0a332151a652325a7f31255aLiejun Tao                    blackListCurrentDevice();
69317675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else {
69417675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes += 1;
69511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (setVolumeNative(mLastRemoteVolume)) {
696e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        sendMessageDelayed(obtainMessage(MSG_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
69711798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mVolCmdSetInProgress = true;
69817675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
69917675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
70017675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
70117675906064bb72fdcca75baa56cdf8bb8968d01John Du
702e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_SET_A2DP_AUDIO_STATE:
703e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.v(TAG, "MSG_SET_A2DP_AUDIO_STATE:" + msg.arg1);
7040a429916782c20980e7f0893c503c633b8341f88Marie Janssen                mA2dpState = msg.arg1;
7050a429916782c20980e7f0893c503c633b8341f88Marie Janssen                updateCurrentMediaState();
706188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                break;
707e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
708e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_FOLDER_ITEMS: {
709e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                AvrcpCmd.FolderItemsCmd folderObj = (AvrcpCmd.FolderItemsCmd) msg.obj;
71089728a4d50001ac76d05efa1c916711ef9f9c2b4Marie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_FOLDER_ITEMS " + folderObj);
711e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                switch (folderObj.mScope) {
712e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    case AvrcpConstants.BTRC_SCOPE_PLAYER_LIST:
713e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        handleMediaPlayerListRsp(folderObj);
714e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        break;
715e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    case AvrcpConstants.BTRC_SCOPE_FILE_SYSTEM:
716e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    case AvrcpConstants.BTRC_SCOPE_NOW_PLAYING:
717e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        handleGetFolderItemBrowseResponse(folderObj, folderObj.mAddress);
718e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        break;
719e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    default:
720e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        Log.e(TAG, "unknown scope for getfolderitems. scope = "
721e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                                + folderObj.mScope);
722e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        getFolderItemsRspNative(folderObj.mAddress,
723e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                                AvrcpConstants.RSP_INV_SCOPE, (short) 0, (byte) 0, 0,
724e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                                null, null, null, null, null, null, null, null);
725e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
726e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
727e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
728e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
729e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_SET_ADDR_PLAYER:
730e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                // object is bdaddr, argument 1 is the selected player id
731294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_SET_ADDR_PLAYER id=" + msg.arg1);
732e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                setAddressedPlayer((byte[]) msg.obj, msg.arg1);
733e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
734e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
735e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_ITEM_ATTR:
736e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                // msg object contains the item attribute object
73789728a4d50001ac76d05efa1c916711ef9f9c2b4Marie Janssen                AvrcpCmd.ItemAttrCmd cmd = (AvrcpCmd.ItemAttrCmd) msg.obj;
73889728a4d50001ac76d05efa1c916711ef9f9c2b4Marie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_ITEM_ATTR " + cmd);
73989728a4d50001ac76d05efa1c916711ef9f9c2b4Marie Janssen                handleGetItemAttr(cmd);
740e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
741e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
742e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_SET_BR_PLAYER:
743e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                // argument 1 is the selected player id
744294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_SET_BR_PLAYER id=" + msg.arg1);
745e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                setBrowsedPlayer((byte[]) msg.obj, msg.arg1);
746e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
747e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
748e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_CHANGE_PATH:
749e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            {
750294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_CHANGE_PATH");
751e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Bundle data = msg.getData();
752e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] bdaddr = data.getByteArray("BdAddress");
753e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] folderUid = data.getByteArray("folderUid");
754e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte direction = data.getByte("direction");
755e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) {
756e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).changePath(folderUid,
757e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        direction);
758e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                } else {
759e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "Remote requesting change path before setbrowsedplayer");
760e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    changePathRspNative(bdaddr, AvrcpConstants.RSP_BAD_CMD, 0);
761e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
762e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
763e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
764e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
765e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_PLAY_ITEM:
766e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            {
767e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Bundle data = msg.getData();
768e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] bdaddr = data.getByteArray("BdAddress");
769e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte[] uid = data.getByteArray("uid");
770e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                byte scope = data.getByte("scope");
77189728a4d50001ac76d05efa1c916711ef9f9c2b4Marie Janssen                if (DEBUG)
77289728a4d50001ac76d05efa1c916711ef9f9c2b4Marie Janssen                    Log.v(TAG, "MSG_NATIVE_REQ_PLAY_ITEM scope=" + scope + " id="
77389728a4d50001ac76d05efa1c916711ef9f9c2b4Marie Janssen                                    + Utils.byteArrayToString(uid));
774e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                handlePlayItemResponse(bdaddr, uid, scope);
775e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
776e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
777e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
778e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS:
779294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen                if (DEBUG) Log.v(TAG, "MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS scope=" + msg.arg1);
780e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                // argument 1 is scope, object is bdaddr
781e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                handleGetTotalNumOfItemsResponse((byte[]) msg.obj, (byte) msg.arg1);
782e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
783e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
784e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case MSG_NATIVE_REQ_PASS_THROUGH:
785294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen                if (DEBUG)
78605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    Log.v(TAG, "MSG_NATIVE_REQ_PASS_THROUGH: id=" + msg.arg1 + " st=" + msg.arg2);
78705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                // argument 1 is id, argument 2 is keyState
78805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                handlePassthroughCmd(msg.arg1, msg.arg2);
789e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
790e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
791e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            default:
792e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "unknown message! msg.what=" + msg.what);
793e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
794c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
795c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
796c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
797c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
798f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    private void updatePlaybackState(PlaybackState state) {
7990e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        if (state == null) {
8000e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen          state = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE,
801e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build();
8020e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        }
803f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
8040a429916782c20980e7f0893c503c633b8341f88Marie Janssen        byte stateBytes = (byte) convertPlayStateToBytes(state.getState());
8050a429916782c20980e7f0893c503c633b8341f88Marie Janssen
8060a429916782c20980e7f0893c503c633b8341f88Marie Janssen        /* updating play status in global media player list */
8070a429916782c20980e7f0893c503c633b8341f88Marie Janssen        MediaPlayerInfo player = getAddressedPlayerInfo();
8080a429916782c20980e7f0893c503c633b8341f88Marie Janssen        if (player != null) {
8090a429916782c20980e7f0893c503c633b8341f88Marie Janssen            player.setPlayStatus(stateBytes);
8100a429916782c20980e7f0893c503c633b8341f88Marie Janssen        } else {
8110a429916782c20980e7f0893c503c633b8341f88Marie Janssen            Log.w(TAG, "onPlaybackStateChanged: no addressed player id=" + mCurrAddrPlayerID);
8120a429916782c20980e7f0893c503c633b8341f88Marie Janssen        }
8130a429916782c20980e7f0893c503c633b8341f88Marie Janssen
814fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState);
815c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        int newPlayStatus = convertPlayStateToPlayStatus(state);
816f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu
817fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        if (DEBUG) {
818fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen            Log.v(TAG, "updatePlaybackState (" + mPlayStatusChangedNT + "): "+
819e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    "old=" + mCurrentPlayState + "(" + oldPlayStatus + "), "+
820e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    "new=" + state + "(" + newPlayStatus + ")");
821fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        }
822fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen
823aa6c1cb7f08a5d1fe2c878b587c62cf4dbb6ee8fZhihai Xu        mCurrentPlayState = state;
824aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
825f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        sendPlayPosNotificationRsp(false);
826aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
827e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (mPlayStatusChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM &&
828e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                (oldPlayStatus != newPlayStatus)) {
829e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
830c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, newPlayStatus);
831c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
832c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
833c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
834c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void updateTransportControls(int transportControlFlags) {
835c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mTransportControlFlags = transportControlFlags;
836c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
837c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
8383b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen    class MediaAttributes {
8393b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private boolean exists;
8403b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String title;
8413b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String artistName;
8423b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String albumName;
8433b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String mediaNumber;
8443b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String mediaTotalNumber;
8453b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String genre;
8460a429916782c20980e7f0893c503c633b8341f88Marie Janssen        private long playingTimeMs;
8473b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
8483b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_TITLE = 1;
8493b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_ARTIST_NAME = 2;
8503b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_ALBUM_NAME = 3;
8513b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_MEDIA_NUMBER = 4;
8523b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_MEDIA_TOTAL_NUMBER = 5;
8533b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_GENRE = 6;
8543b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private static final int ATTR_PLAYING_TIME_MS = 7;
8553b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
8563b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
8573b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        public MediaAttributes(MediaMetadata data) {
8583b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            exists = data != null;
8593b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (!exists)
8603b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return;
8613b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
8623b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            artistName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ARTIST));
8633b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            albumName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ALBUM));
8643b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            mediaNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER));
8653b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            mediaTotalNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS));
8663b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            genre = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_GENRE));
8670a429916782c20980e7f0893c503c633b8341f88Marie Janssen            playingTimeMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION);
8683b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
8693b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            // Try harder for the title.
8703b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            title = data.getString(MediaMetadata.METADATA_KEY_TITLE);
8713b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
8723b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (title == null) {
8733b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                MediaDescription desc = data.getDescription();
8743b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                if (desc != null) {
8753b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    CharSequence val = desc.getDescription();
8763b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    if (val != null)
8773b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                        title = val.toString();
8783b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                }
8793b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            }
8803b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
8813b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (title == null)
8823b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                title = new String();
8833b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
8843b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
8850a429916782c20980e7f0893c503c633b8341f88Marie Janssen        public long getLength() {
8860a429916782c20980e7f0893c503c633b8341f88Marie Janssen            if (!exists) return 0L;
8870a429916782c20980e7f0893c503c633b8341f88Marie Janssen            return playingTimeMs;
8880a429916782c20980e7f0893c503c633b8341f88Marie Janssen        }
8890a429916782c20980e7f0893c503c633b8341f88Marie Janssen
8903b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        public boolean equals(MediaAttributes other) {
8913b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (other == null)
8923b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return false;
8933b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
8943b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (exists != other.exists)
8953b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return false;
8963b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
8973b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (exists == false)
8983b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return true;
8993b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9000a429916782c20980e7f0893c503c633b8341f88Marie Janssen            return (title.equals(other.title)) && (artistName.equals(other.artistName))
9010a429916782c20980e7f0893c503c633b8341f88Marie Janssen                    && (albumName.equals(other.albumName))
9020a429916782c20980e7f0893c503c633b8341f88Marie Janssen                    && (mediaNumber.equals(other.mediaNumber))
9030a429916782c20980e7f0893c503c633b8341f88Marie Janssen                    && (mediaTotalNumber.equals(other.mediaTotalNumber))
9040a429916782c20980e7f0893c503c633b8341f88Marie Janssen                    && (genre.equals(other.genre)) && (playingTimeMs == other.playingTimeMs);
9053b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
9063b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9073b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        public String getString(int attrId) {
9083b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            if (!exists)
9093b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return new String();
9103b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9113b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            switch (attrId) {
9123b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_TITLE:
9133b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return title;
9143b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_ARTIST_NAME:
9153b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return artistName;
9163b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_ALBUM_NAME:
9173b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return albumName;
9183b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_MEDIA_NUMBER:
9193b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return mediaNumber;
9203b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_MEDIA_TOTAL_NUMBER:
9213b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return mediaTotalNumber;
9223b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_GENRE:
9233b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return genre;
9243b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                case ATTR_PLAYING_TIME_MS:
9250a429916782c20980e7f0893c503c633b8341f88Marie Janssen                    return Long.toString(playingTimeMs);
9263b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                default:
9273b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                    return new String();
9283b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            }
9293b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
9303b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9313b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String stringOrBlank(String s) {
9323b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            return s == null ? new String() : s;
9333b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        }
934c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
9353b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen        private String longStringOrBlank(Long s) {
9363b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen            return s == null ? new String() : s.toString();
937c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
938c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
939c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public String toString() {
940e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!exists) {
9413b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen                return "[MediaAttributes: none]";
942e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
9433b9b0ca02d74a95c3f1f5b0d7bc58a8a1f9c44dfMarie Janssen
9440a429916782c20980e7f0893c503c633b8341f88Marie Janssen            return "[MediaAttributes: " + title + " - " + albumName + " by " + artistName + " ("
9450a429916782c20980e7f0893c503c633b8341f88Marie Janssen                    + playingTimeMs + " " + mediaNumber + "/" + mediaTotalNumber + ") " + genre
9460a429916782c20980e7f0893c503c633b8341f88Marie Janssen                    + "]";
947c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
948c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
949c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
9500a429916782c20980e7f0893c503c633b8341f88Marie Janssen    private void updateCurrentMediaState() {
951384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        MediaAttributes currentAttributes = mMediaAttributes;
952c9f4e0d24e39b372452fa809b12f9c588b29abd9Marie Janssen        PlaybackState newState = null;
953ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen        synchronized (this) {
954ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen            if (mMediaController == null) {
955ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                // Use A2DP state if we don't have a MediaControlller
956ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                boolean isPlaying = (mA2dpState == BluetoothA2dp.STATE_PLAYING)
957ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                        && mAudioManager.isMusicActive();
958ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                PlaybackState.Builder builder = new PlaybackState.Builder();
959ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                if (isPlaying) {
960ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                    builder.setState(PlaybackState.STATE_PLAYING,
961ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                            PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f);
962ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                } else {
963ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                    builder.setState(PlaybackState.STATE_PAUSED,
964ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                            PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f);
965ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                }
966ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                newState = builder.build();
967ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                mMediaAttributes = new MediaAttributes(null);
968c9f4e0d24e39b372452fa809b12f9c588b29abd9Marie Janssen            } else {
969ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                newState = mMediaController.getPlaybackState();
970ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                mMediaAttributes = new MediaAttributes(mMediaController.getMetadata());
9710a429916782c20980e7f0893c503c633b8341f88Marie Janssen            }
9720e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        }
973e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
97429174eb9ad6e255d7ec216ab9a2ce8d20e2fe13cMarie Janssen        long oldQueueId = mCurrentPlayState.getActiveQueueItemId();
97529174eb9ad6e255d7ec216ab9a2ce8d20e2fe13cMarie Janssen        long newQueueId = MediaSession.QueueItem.UNKNOWN_ID;
97629174eb9ad6e255d7ec216ab9a2ce8d20e2fe13cMarie Janssen        if (newState != null) newQueueId = newState.getActiveQueueItemId();
9778ac88214fdbf5e5197033b89ba82a6bf728706a4Marie Janssen        Log.v(TAG, "Media update: id " + oldQueueId + "➡" + newQueueId + ":"
9788ac88214fdbf5e5197033b89ba82a6bf728706a4Marie Janssen                        + mMediaAttributes.toString());
9798ac88214fdbf5e5197033b89ba82a6bf728706a4Marie Janssen        if (oldQueueId != newQueueId || !currentAttributes.equals(mMediaAttributes)) {
9800a429916782c20980e7f0893c503c633b8341f88Marie Janssen            sendTrackChangedRsp(false);
981c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
982aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
983384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        updatePlaybackState(newState);
984c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
985c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
986e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void getRcFeaturesRequestFromNative(byte[] address, int features) {
987e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_RC_FEATURES, features, 0,
988e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Utils.getAddressStringFromByte(address));
98917675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
99017675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
99117675906064bb72fdcca75baa56cdf8bb8968d01John Du
992e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void getPlayStatusRequestFromNative(byte[] address) {
993e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_PLAY_STATUS);
994e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
995c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
996c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
997c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
99889728a4d50001ac76d05efa1c916711ef9f9c2b4Marie Janssen    private void getElementAttrRequestFromNative(byte[] address, byte numAttr, int[] attrs) {
999e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd avrcpCmdobj = new AvrcpCmd();
1000e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd.ElementAttrCmd elemAttr = avrcpCmdobj.new ElementAttrCmd(address, numAttr, attrs);
1001e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_ELEM_ATTRS);
1002e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = elemAttr;
1003c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
1004c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1005c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1006e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void registerNotificationRequestFromNative(byte[] address,int eventId, int param) {
1007e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_REGISTER_NOTIFICATION, eventId, param);
1008e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1009c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
1010c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1011c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1012e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void processRegisterNotification(byte[] address, int eventId, int param) {
1013c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        switch (eventId) {
1014c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case EVT_PLAY_STATUS_CHANGED:
1015e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mPlayStatusChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
1016c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                registerNotificationRspPlayStatusNative(mPlayStatusChangedNT,
10170e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                        convertPlayStateToPlayStatus(mCurrentPlayState));
1018c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1019c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1020c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case EVT_TRACK_CHANGED:
10210e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen                Log.v(TAG, "Track changed notification enabled");
1022e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
10230a429916782c20980e7f0893c503c633b8341f88Marie Janssen                sendTrackChangedRsp(true);
1024c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1025c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1026aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            case EVT_PLAY_POS_CHANGED:
1027e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_INTERIM;
1028e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mPlaybackIntervalMs = (long) param * 1000L;
1029fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen                sendPlayPosNotificationRsp(true);
1030aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                break;
1031aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
1032e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVT_AVBL_PLAYERS_CHANGED:
1033e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                /* Notify remote available players changed */
1034e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.d (TAG, "sending availablePlayersChanged to remote ");
1035e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                registerNotificationRspAvalPlayerChangedNative(
1036e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        AvrcpConstants.NOTIFICATION_TYPE_INTERIM);
1037e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1038e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1039e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVT_ADDR_PLAYER_CHANGED:
1040e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                /* Notify remote addressed players changed */
1041e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.d (TAG, "sending addressedPlayersChanged to remote ");
1042e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                registerNotificationRspAddrPlayerChangedNative(
1043e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        AvrcpConstants.NOTIFICATION_TYPE_INTERIM,
1044e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        mCurrAddrPlayerID, sUIDCounter);
1045e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1046e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1047e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVENT_UIDS_CHANGED:
1048e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.d(TAG, "sending UIDs changed to remote");
1049e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                registerNotificationRspUIDsChangedNative(
1050e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        AvrcpConstants.NOTIFICATION_TYPE_INTERIM, sUIDCounter);
1051e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1052e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1053e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case EVENT_NOW_PLAYING_CONTENT_CHANGED:
1054e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.d(TAG, "sending NowPlayingList changed to remote");
1055e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                /* send interim response to remote device */
1056e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!registerNotificationRspNowPlayingChangedNative(
1057e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        AvrcpConstants.NOTIFICATION_TYPE_INTERIM)) {
1058e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "EVENT_NOW_PLAYING_CONTENT_CHANGED: " +
1059e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                            "registerNotificationRspNowPlayingChangedNative for Interim rsp failed!");
1060e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
1061e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                break;
1062c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1063c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1064c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1065e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handlePassthroughCmdRequestFromNative(byte[] address, int id, int keyState) {
106605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_PASS_THROUGH, id, keyState);
1067e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1068ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
1069ace834feb02adabd61f628c4471147aea02d939cJohn Du
10700a429916782c20980e7f0893c503c633b8341f88Marie Janssen    private void sendTrackChangedRsp(boolean requested) {
1071eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        MediaPlayerInfo info = getAddressedPlayerInfo();
10728ac88214fdbf5e5197033b89ba82a6bf728706a4Marie Janssen        if (!requested && mTrackChangedNT != AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
10738ac88214fdbf5e5197033b89ba82a6bf728706a4Marie Janssen            if (DEBUG) Log.d(TAG, "sendTrackChangedRsp: Not registered or requesting.");
10748ac88214fdbf5e5197033b89ba82a6bf728706a4Marie Janssen            return;
10758ac88214fdbf5e5197033b89ba82a6bf728706a4Marie Janssen        }
1076eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        if (info != null && !info.isBrowseSupported()) {
1077eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            // for players which does not support Browse or when no track is currently selected
10780a429916782c20980e7f0893c503c633b8341f88Marie Janssen            trackChangeRspForBrowseUnsupported(requested);
1079e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
10800a429916782c20980e7f0893c503c633b8341f88Marie Janssen            boolean changed =
10810a429916782c20980e7f0893c503c633b8341f88Marie Janssen                    mAddressedMediaPlayer.sendTrackChangeWithId(requested, mMediaController);
1082e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // for players which support browsing
10830a429916782c20980e7f0893c503c633b8341f88Marie Janssen            if (changed) mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
1084e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou        }
1085e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1086e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou
10870a429916782c20980e7f0893c503c633b8341f88Marie Janssen    private void trackChangeRspForBrowseUnsupported(boolean requested) {
1088e23a886e79f60a3f7f5b8e87f8c5ffc26134bd32Marie Janssen        byte[] track = AvrcpConstants.TRACK_IS_SELECTED;
10890a429916782c20980e7f0893c503c633b8341f88Marie Janssen        if (requested && !mMediaAttributes.exists) {
1090e23a886e79f60a3f7f5b8e87f8c5ffc26134bd32Marie Janssen            track = AvrcpConstants.NO_TRACK_SELECTED;
10910a429916782c20980e7f0893c503c633b8341f88Marie Janssen        } else if (!requested) {
10920a429916782c20980e7f0893c503c633b8341f88Marie Janssen            mTrackChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
1093c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1094c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        registerNotificationRspTrackChangeNative(mTrackChangedNT, track);
1095c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1096c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1097aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long getPlayPosition() {
1098e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (mCurrentPlayState == null) {
1099f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            return -1L;
1100e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1101f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1102e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (mCurrentPlayState.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
1103f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            return -1L;
1104e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1105f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1106f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        if (isPlayingState(mCurrentPlayState)) {
11070a429916782c20980e7f0893c503c633b8341f88Marie Janssen            long sinceUpdate =
11080a429916782c20980e7f0893c503c633b8341f88Marie Janssen                    (SystemClock.elapsedRealtime() - mCurrentPlayState.getLastPositionUpdateTime());
11090a429916782c20980e7f0893c503c633b8341f88Marie Janssen            return sinceUpdate + mCurrentPlayState.getPosition();
1110aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        }
1111f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
11123635a926bd7316a55b288a54d409a1070a9c19e8Marie Janssen        return mCurrentPlayState.getPosition();
1113aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    }
1114aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
11150e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen    private int convertPlayStateToPlayStatus(PlaybackState state) {
1116c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        int playStatus = PLAYSTATUS_ERROR;
11170e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        switch (state.getState()) {
11180e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            case PlaybackState.STATE_PLAYING:
11190e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            case PlaybackState.STATE_BUFFERING:
1120c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_PLAYING;
1121c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1122c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
11230e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            case PlaybackState.STATE_STOPPED:
11240e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            case PlaybackState.STATE_NONE:
1125c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_STOPPED;
1126c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1127c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
11280e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            case PlaybackState.STATE_PAUSED:
1129c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_PAUSED;
1130c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1131c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
11320e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            case PlaybackState.STATE_FAST_FORWARDING:
11330e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            case PlaybackState.STATE_SKIPPING_TO_NEXT:
11340e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM:
1135c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_FWD_SEEK;
1136c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1137c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
11380e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            case PlaybackState.STATE_REWINDING:
11390e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
1140c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_REV_SEEK;
1141c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1142c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
11430e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen            case PlaybackState.STATE_ERROR:
1144c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_ERROR;
1145c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
1146c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1147c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1148c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return playStatus;
1149c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
1150c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
11510e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen    private boolean isPlayingState(PlaybackState state) {
11520e949676c5097e1f259caa2e549ecedf0c09269dMarie Janssen        return (state.getState() == PlaybackState.STATE_PLAYING) ||
1153e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                (state.getState() == PlaybackState.STATE_BUFFERING);
1154188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
1155188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
115617675906064bb72fdcca75baa56cdf8bb8968d01John Du    /**
1157f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * Sends a play position notification, or schedules one to be
1158f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * sent later at an appropriate time. If |requested| is true,
1159f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * does both because this was called in reponse to a request from the
1160f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     * TG.
1161f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen     */
1162f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    private void sendPlayPosNotificationRsp(boolean requested) {
1163e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!requested && mPlayPosChangedNT != AvrcpConstants.NOTIFICATION_TYPE_INTERIM) {
1164fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen            if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: Not registered or requesting.");
1165fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen            return;
1166fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        }
1167fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen
1168f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        long playPositionMs = getPlayPosition();
1169f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1170f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // mNextPosMs is set to -1 when the previous position was invalid
1171f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // so this will be true if the new position is valid & old was invalid.
1172f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // mPlayPositionMs is set to -1 when the new position is invalid,
1173f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // and the old mPrevPosMs is >= 0 so this is true when the new is invalid
1174f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        // and the old was valid.
1175fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: (" + requested + ") "
1176e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                + mPrevPosMs + " <=? " + playPositionMs + " <=? " + mNextPosMs);
117705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: currentPlayState " + mCurrentPlayState);
1178fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen        if (requested || ((mLastReportedPosition != playPositionMs) &&
1179e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                (playPositionMs >= mNextPosMs) || (playPositionMs <= mPrevPosMs))) {
1180e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!requested) mPlayPosChangedNT = AvrcpConstants.NOTIFICATION_TYPE_CHANGED;
1181e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int) playPositionMs);
1182fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen            mLastReportedPosition = playPositionMs;
1183f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            if (playPositionMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
1184f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mNextPosMs = playPositionMs + mPlaybackIntervalMs;
1185f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mPrevPosMs = playPositionMs - mPlaybackIntervalMs;
1186f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            } else {
1187f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mNextPosMs = -1;
1188f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                mPrevPosMs = -1;
1189f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            }
1190f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        }
1191f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1192e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.removeMessages(MSG_PLAY_INTERVAL_TIMEOUT);
1193e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (mPlayPosChangedNT == AvrcpConstants.NOTIFICATION_TYPE_INTERIM && isPlayingState(mCurrentPlayState)) {
1194e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Message msg = mHandler.obtainMessage(MSG_PLAY_INTERVAL_TIMEOUT);
1195f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            long delay = mPlaybackIntervalMs;
1196f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            if (mNextPosMs != -1) {
1197f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen                delay = mNextPosMs - (playPositionMs > 0 ? playPositionMs : 0);
1198f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            }
1199fa81085f6cda571d56c62eb1d646ae4a52cb90eeMarie Janssen            if (DEBUG) Log.d(TAG, "PLAY_INTERVAL_TIMEOUT set for " + delay + "ms from now");
1200f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen            mHandler.sendMessageDelayed(msg, delay);
1201f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen        }
1202f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    }
1203f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen
1204f7942360dd9d807bea087c4ef42773f5e800c0c4Marie Janssen    /**
120517675906064bb72fdcca75baa56cdf8bb8968d01John Du     * This is called from AudioService. It will return whether this device supports abs volume.
120617675906064bb72fdcca75baa56cdf8bb8968d01John Du     * NOT USED AT THE MOMENT.
120717675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
120817675906064bb72fdcca75baa56cdf8bb8968d01John Du    public boolean isAbsoluteVolumeSupported() {
120917675906064bb72fdcca75baa56cdf8bb8968d01John Du        return ((mFeatures & BTRC_FEAT_ABSOLUTE_VOLUME) != 0);
121017675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
121117675906064bb72fdcca75baa56cdf8bb8968d01John Du
121217675906064bb72fdcca75baa56cdf8bb8968d01John Du    /**
121317675906064bb72fdcca75baa56cdf8bb8968d01John Du     * We get this call from AudioService. This will send a message to our handler object,
121417675906064bb72fdcca75baa56cdf8bb8968d01John Du     * requesting our handler to call setVolumeNative()
121517675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
121617675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void adjustVolume(int direction) {
1217e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_ADJUST_VOLUME, direction, 0);
121817675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
121917675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
122017675906064bb72fdcca75baa56cdf8bb8968d01John Du
122117675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void setAbsoluteVolume(int volume) {
122211798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (volume == mLocalVolume) {
122311798b011c962b602217b479130d413f3b30f19aLiejun Tao            if (DEBUG) Log.v(TAG, "setAbsoluteVolume is setting same index, ignore "+volume);
122411798b011c962b602217b479130d413f3b30f19aLiejun Tao            return;
122511798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
122611798b011c962b602217b479130d413f3b30f19aLiejun Tao
1227e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.removeMessages(MSG_ADJUST_VOLUME);
1228e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_SET_ABSOLUTE_VOLUME, volume, 0);
122917675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
12305c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta    }
12315c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta
123217675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* Called in the native layer as a btrc_callback to return the volume set on the carkit in the
123317675906064bb72fdcca75baa56cdf8bb8968d01John Du     * case when the volume is change locally on the carkit. This notification is not called when
123417675906064bb72fdcca75baa56cdf8bb8968d01John Du     * the volume is changed from the phone.
123517675906064bb72fdcca75baa56cdf8bb8968d01John Du     *
123617675906064bb72fdcca75baa56cdf8bb8968d01John Du     * This method will send a message to our handler to change the local stored volume and notify
123717675906064bb72fdcca75baa56cdf8bb8968d01John Du     * AudioService to update the UI
123817675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
1239e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void volumeChangeRequestFromNative(byte[] address, int volume, int ctype) {
1240e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_VOLUME_CHANGE, volume, ctype);
1241e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1242e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByteArray("BdAddress" , address);
1243e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.setData(data);
1244e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1245e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1246e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
124719a05f008446506069b34265d57bcf421447e7e3Marie Janssen    private void getFolderItemsRequestFromNative(
124819a05f008446506069b34265d57bcf421447e7e3Marie Janssen            byte[] address, byte scope, long startItem, long endItem, byte numAttr, int[] attrIds) {
1249e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd avrcpCmdobj = new AvrcpCmd();
1250e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd.FolderItemsCmd folderObj = avrcpCmdobj.new FolderItemsCmd(address, scope,
1251e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                startItem, endItem, numAttr, attrIds);
1252e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_FOLDER_ITEMS, 0, 0);
1253e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = folderObj;
1254e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1255e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1256e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1257e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setAddressedPlayerRequestFromNative(byte[] address, int playerId) {
1258e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_SET_ADDR_PLAYER, playerId, 0);
1259e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1260e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1261e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1262e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1263e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setBrowsedPlayerRequestFromNative(byte[] address, int playerId) {
1264e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_SET_BR_PLAYER, playerId, 0);
1265e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
1266e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1267e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1268e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1269e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void changePathRequestFromNative(byte[] address, byte direction, byte[] folderUid) {
1270e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1271e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_CHANGE_PATH);
1272e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByteArray("BdAddress" , address);
1273e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByteArray("folderUid" , folderUid);
1274e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByte("direction" , direction);
1275e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.setData(data);
1276e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1277e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1278e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1279e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void getItemAttrRequestFromNative(byte[] address, byte scope, byte[] itemUid, int uidCounter,
1280e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            byte numAttr, int[] attrs) {
1281e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd avrcpCmdobj = new AvrcpCmd();
1282e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        AvrcpCmd.ItemAttrCmd itemAttr = avrcpCmdobj.new ItemAttrCmd(address, scope,
1283e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                itemUid, uidCounter, numAttr, attrs);
1284e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_ITEM_ATTR);
1285e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = itemAttr;
1286e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1287e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1288e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1289e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void searchRequestFromNative(byte[] address, int charsetId, byte[] searchStr) {
1290e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Search is not supported */
1291e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen        Log.w(TAG, "searchRequestFromNative: search is not supported");
1292e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        searchRspNative(address, AvrcpConstants.RSP_SRCH_NOT_SPRTD, 0, 0);
1293e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1294e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1295e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void playItemRequestFromNative(byte[] address, byte scope, int uidCounter, byte[] uid) {
1296e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1297e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_PLAY_ITEM);
1298e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByteArray("BdAddress" , address);
1299e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByteArray("uid" , uid);
1300e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putInt("uidCounter" , uidCounter);
1301e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        data.putByte("scope" , scope);
1302e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.setData(data);
1303e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mHandler.sendMessage(msg);
1304e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1305e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1306e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void addToPlayListRequestFromNative(byte[] address, byte scope, byte[] uid, int uidCounter) {
1307e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* add to NowPlaying not supported */
1308e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen        Log.w(TAG, "addToPlayListRequestFromNative: not supported! scope=" + scope);
1309e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        addToNowPlayingRspNative(address, AvrcpConstants.RSP_INTERNAL_ERR);
1310e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1311e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1312e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void getTotalNumOfItemsRequestFromNative(byte[] address, byte scope) {
1313e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Bundle data = new Bundle();
1314e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_NATIVE_REQ_GET_TOTAL_NUM_OF_ITEMS);
1315e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.arg1 = scope;
1316e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        msg.obj = address;
131717675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
131817675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
131917675906064bb72fdcca75baa56cdf8bb8968d01John Du
13202e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private void notifyVolumeChanged(int volume) {
13212e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume,
13222e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie                      AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
132317675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
132417675906064bb72fdcca75baa56cdf8bb8968d01John Du
132517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int convertToAudioStreamVolume(int volume) {
132617675906064bb72fdcca75baa56cdf8bb8968d01John Du        // Rescale volume to match AudioSystem's volume
132711798b011c962b602217b479130d413f3b30f19aLiejun Tao        return (int) Math.floor((double) volume*mAudioStreamMax/AVRCP_MAX_VOL);
132817675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
132917675906064bb72fdcca75baa56cdf8bb8968d01John Du
133017675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int convertToAvrcpVolume(int volume) {
13312e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        return (int) Math.ceil((double) volume*AVRCP_MAX_VOL/mAudioStreamMax);
133217675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
133317675906064bb72fdcca75baa56cdf8bb8968d01John Du
133411798b011c962b602217b479130d413f3b30f19aLiejun Tao    private void blackListCurrentDevice() {
133511798b011c962b602217b479130d413f3b30f19aLiejun Tao        mFeatures &= ~BTRC_FEAT_ABSOLUTE_VOLUME;
133611798b011c962b602217b479130d413f3b30f19aLiejun Tao        mAudioManager.avrcpSupportsAbsoluteVolume(mAddress, isAbsoluteVolumeSupported());
133711798b011c962b602217b479130d413f3b30f19aLiejun Tao
133811798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST,
133911798b011c962b602217b479130d413f3b30f19aLiejun Tao                Context.MODE_PRIVATE);
134011798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences.Editor editor = pref.edit();
134111798b011c962b602217b479130d413f3b30f19aLiejun Tao        editor.putBoolean(mAddress, true);
13427eeb95b6f29a6f55e117e329468168d4bcbec0c8Jack He        editor.apply();
134311798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
134411798b011c962b602217b479130d413f3b30f19aLiejun Tao
134511798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int modifyRcFeatureFromBlacklist(int feature, String address) {
134611798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST,
134711798b011c962b602217b479130d413f3b30f19aLiejun Tao                Context.MODE_PRIVATE);
134811798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (!pref.contains(address)) {
134911798b011c962b602217b479130d413f3b30f19aLiejun Tao            return feature;
135011798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
135111798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (pref.getBoolean(address, false)) {
135211798b011c962b602217b479130d413f3b30f19aLiejun Tao            feature &= ~BTRC_FEAT_ABSOLUTE_VOLUME;
135311798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
135411798b011c962b602217b479130d413f3b30f19aLiejun Tao        return feature;
135511798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
135611798b011c962b602217b479130d413f3b30f19aLiejun Tao
135711798b011c962b602217b479130d413f3b30f19aLiejun Tao    public void resetBlackList(String address) {
135811798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST,
135911798b011c962b602217b479130d413f3b30f19aLiejun Tao                Context.MODE_PRIVATE);
136011798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences.Editor editor = pref.edit();
136111798b011c962b602217b479130d413f3b30f19aLiejun Tao        editor.remove(address);
13627eeb95b6f29a6f55e117e329468168d4bcbec0c8Jack He        editor.apply();
136311798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
136411798b011c962b602217b479130d413f3b30f19aLiejun Tao
1365188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    /**
1366188f205b5f093850d4cc627917a21204be36c56aZhihai Xu     * This is called from A2dpStateMachine to set A2dp audio state.
1367188f205b5f093850d4cc627917a21204be36c56aZhihai Xu     */
1368188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    public void setA2dpAudioState(int state) {
1369e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Message msg = mHandler.obtainMessage(MSG_SET_A2DP_AUDIO_STATE, state, 0);
1370188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        mHandler.sendMessage(msg);
1371188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
1372188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
13730427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker    private class AvrcpServiceBootReceiver extends BroadcastReceiver {
13740427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        @Override
13750427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        public void onReceive(Context context, Intent intent) {
13760427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker            String action = intent.getAction();
13770427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker            if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
13780427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker                if (DEBUG) Log.d(TAG, "Boot completed, initializing player lists");
13790427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker                /* initializing media player's list */
1380be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen                mBrowsableListBuilder.start();
13810427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker            }
13820427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        }
13830427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker    }
13840427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker
1385e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private class AvrcpServiceBroadcastReceiver extends BroadcastReceiver {
1386e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        @Override
1387e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void onReceive(Context context, Intent intent) {
1388e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String action = intent.getAction();
1389e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (DEBUG) Log.d(TAG, "AvrcpServiceBroadcastReceiver-> Action: " + action);
1390e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1391e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
1392e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) {
1393e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1394e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    // a package is being removed, not replaced
1395e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    String packageName = intent.getData().getSchemeSpecificPart();
1396e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    if (packageName != null) {
1397e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        handlePackageModified(packageName, true);
1398e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    }
1399e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
1400e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1401e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else if (action.equals(Intent.ACTION_PACKAGE_ADDED)
1402e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    || action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
1403e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                String packageName = intent.getData().getSchemeSpecificPart();
1404e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (DEBUG) Log.d(TAG,"AvrcpServiceBroadcastReceiver-> packageName: "
1405e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        + packageName);
1406e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (packageName != null) {
1407e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    handlePackageModified(packageName, false);
1408e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
1409e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1410e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1411838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    }
1412838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood
1413e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handlePackageModified(String packageName, boolean removed) {
1414e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "packageName: " + packageName + " removed: " + removed);
1415c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1416e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (removed) {
1417384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            removeMediaPlayerInfo(packageName);
1418e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // old package is removed, updating local browsable player's list
1419e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (isBrowseSupported(packageName)) {
1420e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                removePackageFromBrowseList(packageName);
1421e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1422e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
1423e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // new package has been added.
1424e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (isBrowsableListUpdated(packageName)) {
1425e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                // Rebuilding browsable players list
1426be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen                mBrowsableListBuilder.start();
1427e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1428e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1429e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1430c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1431e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isBrowsableListUpdated(String newPackageName) {
1432e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // getting the browsable media players list from package manager
1433e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Intent intent = new Intent("android.media.browse.MediaBrowserService");
14340427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker        List<ResolveInfo> resInfos = mPackageManager.queryIntentServices(intent,
14350427c02017744a749b99230b5bd080e2d4cfa3e1Ajay Panicker                                         PackageManager.MATCH_ALL);
1436e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        for (ResolveInfo resolveInfo : resInfos) {
14373843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            if (resolveInfo.serviceInfo.packageName.equals(newPackageName)) {
14383843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                if (DEBUG)
14393843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                    Log.d(TAG,
14403843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                            "isBrowsableListUpdated: package includes MediaBrowserService, true");
14413843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                return true;
14423843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            }
1443e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1444c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
14453843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        // if list has different size
14463843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        if (resInfos.size() != mBrowsePlayerInfoList.size()) {
14473843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            if (DEBUG) Log.d(TAG, "isBrowsableListUpdated: browsable list size mismatch, true");
14483843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            return true;
1449e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
14503843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen
14513843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        Log.d(TAG, "isBrowsableListUpdated: false");
14523843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        return false;
1453e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1454e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1455511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private void removePackageFromBrowseList(String packageName) {
1456e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "removePackageFromBrowseList: " + packageName);
1457511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mBrowsePlayerInfoList) {
1458511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int browseInfoID = getBrowseId(packageName);
1459511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (browseInfoID != -1) {
1460511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                mBrowsePlayerInfoList.remove(browseInfoID);
1461511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
1462e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1463e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1464e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1465e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
1466e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * utility function to get the browse player index from global browsable
1467e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * list. It may return -1 if specified package name is not in the list.
1468e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
1469511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private int getBrowseId(String packageName) {
1470e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean response = false;
1471e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        int browseInfoID = 0;
1472511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mBrowsePlayerInfoList) {
1473511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (BrowsePlayerInfo info : mBrowsePlayerInfoList) {
1474511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (info.packageName.equals(packageName)) {
1475511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    response = true;
1476511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    break;
1477511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
1478511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                browseInfoID++;
1479e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1480e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1481e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1482e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!response) {
1483e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            browseInfoID = -1;
1484e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1485e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1486e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "getBrowseId for packageName: " + packageName +
1487e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                " , browseInfoID: " + browseInfoID);
1488e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return browseInfoID;
1489e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1490e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1491e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setAddressedPlayer(byte[] bdaddr, int selectedId) {
1492eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen        String functionTag = "setAddressedPlayer(" + selectedId + "): ";
1493e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1494511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1495511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (mMediaPlayerInfoList.isEmpty()) {
1496eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Log.w(TAG, functionTag + "no players, send no available players");
1497eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_AVBL_PLAY);
1498eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                return;
1499eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            }
1500eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            if (!mMediaPlayerInfoList.containsKey(selectedId)) {
1501eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Log.w(TAG, functionTag + "invalid id, sending response back ");
1502eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_INV_PLAYER);
1503eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                return;
1504eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            }
1505eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen
1506eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            if (isPlayerAlreadyAddressed(selectedId)) {
1507511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                MediaPlayerInfo info = getAddressedPlayerInfo();
1508eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Log.i(TAG, functionTag + "player already addressed: " + info);
1509eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR);
1510eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                return;
1511eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            }
1512eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            // register new Media Controller Callback and update the current IDs
1513eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            if (!updateCurrentController(selectedId, mCurrBrowsePlayerID)) {
1514eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Log.e(TAG, functionTag + "updateCurrentController failed!");
1515eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR);
1516eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                return;
1517eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            }
1518eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            // If we don't have a controller, try to launch the player
1519eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            MediaPlayerInfo info = getAddressedPlayerInfo();
1520eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen            if (info.getMediaController() == null) {
1521eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Intent launch = mPackageManager.getLaunchIntentForPackage(info.getPackageName());
1522eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                Log.i(TAG, functionTag + "launching player " + launch);
1523eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen                mContext.startActivity(launch);
1524e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1525e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1526eb3c55797d3ba16916327effa6b36acec5f1de36Marie Janssen        setAddressedPlayerRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR);
1527e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1528e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1529e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void setBrowsedPlayer(byte[] bdaddr, int selectedId) {
1530e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        int status = AvrcpConstants.RSP_NO_ERROR;
1531e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1532e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // checking for error cases
1533511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        if (mMediaPlayerInfoList.isEmpty()) {
1534e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            status = AvrcpConstants.RSP_NO_AVBL_PLAY;
1535e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Log.w(TAG, " No Available Players to set, sending response back ");
1536e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
1537e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // update current browse player id and start browsing service
1538e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            updateNewIds(mCurrAddrPlayerID, selectedId);
1539e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String browsedPackage = getPackageName(selectedId);
1540e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1541e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!isPackageNameValid(browsedPackage)) {
1542e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.w(TAG, " Invalid package for id:" + mCurrBrowsePlayerID);
1543e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                status = AvrcpConstants.RSP_INV_PLAYER;
1544e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else if (!isBrowseSupported(browsedPackage)) {
1545e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.w(TAG, "Browse unsupported for id:" + mCurrBrowsePlayerID
1546e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        + ", packagename : " + browsedPackage);
1547e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                status = AvrcpConstants.RSP_PLAY_NOT_BROW;
1548e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else if (!startBrowseService(bdaddr, browsedPackage)) {
1549e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "service cannot be started for browse player id:" + mCurrBrowsePlayerID
1550e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        + ", packagename : " + browsedPackage);
1551e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                status = AvrcpConstants.RSP_INTERNAL_ERR;
1552e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1553e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1554e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1555e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (status != AvrcpConstants.RSP_NO_ERROR) {
1556e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            setBrowsedPlayerRspNative(bdaddr, status, (byte) 0x00, 0, null);
1557e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1558e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1559e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "setBrowsedPlayer for selectedId: " + selectedId +
1560e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                " , status: " + status);
1561e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1562e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
156305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private MediaSessionManager.OnActiveSessionsChangedListener mActiveSessionListener =
156405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            new MediaSessionManager.OnActiveSessionsChangedListener() {
1565e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
156605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                @Override
156705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                public void onActiveSessionsChanged(
156805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                        List<android.media.session.MediaController> newControllers) {
156905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    boolean playersChanged = false;
157005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
157105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    // Update the current players
157205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    for (android.media.session.MediaController controller : newControllers) {
157305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                        addMediaPlayerController(controller);
157405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                        playersChanged = true;
1575eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                    }
1576d996f17ea97b2c592338bcfbc93056d0224da1cdAjay Panicker
157705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    if (playersChanged) {
157805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                        mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP);
1579384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen                        if (newControllers.size() > 0 && getAddressedPlayerInfo() == null) {
158005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                            if (DEBUG)
158105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                                Log.v(TAG,
158205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                                        "No addressed player but active sessions, taking first.");
158305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                            setAddressedMediaSessionPackage(newControllers.get(0).getPackageName());
1584eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                        }
1585eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                    }
1586e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
158705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            };
158805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
158978d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen    private void setAddressedMediaSessionPackage(@Nullable String packageName) {
159041527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen        if (packageName == null) {
159141527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen            // Should only happen when there's no media players, reset to no available player.
159241527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen            updateCurrentController(0, mCurrBrowsePlayerID);
159341527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen            return;
159441527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen        }
159505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        // No change.
159605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (getPackageName(mCurrAddrPlayerID).equals(packageName)) return;
159778d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        if (DEBUG) Log.v(TAG, "Changing addressed media session to " + packageName);
159805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        // If the player doesn't exist, we need to add it.
159905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (getMediaPlayerInfo(packageName) == null) {
160005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            addMediaPlayerPackage(packageName);
160105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP);
160205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
1603511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1604511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
1605511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (entry.getValue().getPackageName().equals(packageName)) {
1606511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    int newAddrID = entry.getKey();
1607511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    if (DEBUG) Log.v(TAG, "Set addressed #" + newAddrID + " " + entry.getValue());
1608511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    updateCurrentController(newAddrID, mCurrBrowsePlayerID);
1609511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    mHandler.obtainMessage(MSG_ADDRESSED_PLAYER_CHANGED_RSP, newAddrID, 0)
1610511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                            .sendToTarget();
1611511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    return;
1612511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
1613e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1614e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
161505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        // We shouldn't ever get here.
161605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        Log.e(TAG, "Player info for " + packageName + " doesn't exist!");
161705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
1618e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
161905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private void setActiveMediaSession(MediaSession.Token token) {
162005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        android.media.session.MediaController activeController =
162105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                new android.media.session.MediaController(mContext, token);
162205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (DEBUG) Log.v(TAG, "Set active media session " + activeController.getPackageName());
162305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        addMediaPlayerController(activeController);
162405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        setAddressedMediaSessionPackage(activeController.getPackageName());
162505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
1626e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1627e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean startBrowseService(byte[] bdaddr, String packageName) {
1628e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean status = true;
1629e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1630e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* creating new instance for Browse Media Player */
1631e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browseService = getBrowseServiceName(packageName);
1632e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!browseService.isEmpty()) {
1633e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).setBrowsed(
1634e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    packageName, browseService);
1635e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
1636e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Log.w(TAG, "No Browser service available for " + packageName);
1637e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            status = false;
1638e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1639e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1640e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "startBrowseService for packageName: " + packageName +
1641e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                ", status = " + status);
1642e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return status;
1643e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1644e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1645511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private String getBrowseServiceName(String packageName) {
1646e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browseServiceName = "";
1647e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1648e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // getting the browse service name from browse player info
1649511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mBrowsePlayerInfoList) {
1650511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int browseInfoID = getBrowseId(packageName);
1651511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (browseInfoID != -1) {
1652511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                browseServiceName = mBrowsePlayerInfoList.get(browseInfoID).serviceClass;
1653511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
1654e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1655e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1656e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "getBrowseServiceName for packageName: " + packageName +
1657e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                ", browseServiceName = " + browseServiceName);
1658e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return browseServiceName;
1659e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1660e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
16613843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen    private class BrowsablePlayerListBuilder extends MediaBrowser.ConnectionCallback {
16623843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        List<ResolveInfo> mWaiting;
16633843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        BrowsePlayerInfo mCurrentPlayer;
16643843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        MediaBrowser mCurrentBrowser;
1665eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        boolean mPlayersChanged;
1666e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
16673843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        public BrowsablePlayerListBuilder() {}
1668e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
16693843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        public void start() {
16703843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            mBrowsePlayerInfoList.clear();
1671be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen            cleanup();
16723843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            Intent intent = new Intent(android.service.media.MediaBrowserService.SERVICE_INTERFACE);
16733843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            mWaiting = mPackageManager.queryIntentServices(intent, PackageManager.MATCH_ALL);
16743843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            connectNextPlayer();
16753843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        }
1676e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1677be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen        public void cleanup() {
1678be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen            if (mWaiting != null) mWaiting.clear();
1679be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen            mPlayersChanged = false;
1680be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen            if (mCurrentBrowser != null) mCurrentBrowser.disconnect();
1681be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen        }
1682be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen
16833843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        private void connectNextPlayer() {
16843843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            if (mWaiting.isEmpty()) {
1685eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                // Done. Send players changed if needed.
1686eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                if (mPlayersChanged) {
1687eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                    registerNotificationRspAvalPlayerChangedNative(
1688eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                            AvrcpConstants.NOTIFICATION_TYPE_CHANGED);
1689eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                }
16903843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                return;
16913843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            }
16923843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            ResolveInfo info = mWaiting.remove(0);
16933843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            String displayableName = info.loadLabel(mPackageManager).toString();
16943843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            String serviceName = info.serviceInfo.name;
16953843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            String packageName = info.serviceInfo.packageName;
1696e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
16973843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            mCurrentPlayer = new BrowsePlayerInfo(packageName, displayableName, serviceName);
16983843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            mCurrentBrowser = new MediaBrowser(
16993843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen                    mContext, new ComponentName(packageName, serviceName), this, null);
17003843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            if (DEBUG) Log.d(TAG, "Trying to connect to " + serviceName);
17013843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            mCurrentBrowser.connect();
17023843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        }
17033843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen
17043843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        @Override
17053843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        public void onConnected() {
17063843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            Log.d(TAG, "BrowsablePlayerListBuilder: " + mCurrentPlayer.packageName + " OK");
1707be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen            mCurrentBrowser.disconnect();
1708be66a1bf5584a2a7985666ab20c5e9b54053e17dMarie Janssen            mCurrentBrowser = null;
17093843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            mBrowsePlayerInfoList.add(mCurrentPlayer);
1710eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            MediaPlayerInfo info = getMediaPlayerInfo(mCurrentPlayer.packageName);
17115146bd27869df5473aa53e6271266f51733971efMarie Janssen            MediaController controller = (info == null) ? null : info.getMediaController();
17125146bd27869df5473aa53e6271266f51733971efMarie Janssen            // Refresh the media player entry so it notices we can browse
17135146bd27869df5473aa53e6271266f51733971efMarie Janssen            if (controller != null) {
17145146bd27869df5473aa53e6271266f51733971efMarie Janssen                addMediaPlayerController(controller.getWrappedInstance());
1715eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            } else {
171605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                addMediaPlayerPackage(mCurrentPlayer.packageName);
1717eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            }
1718eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            mPlayersChanged = true;
17193843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            connectNextPlayer();
17203843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        }
17213843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen
17223843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        @Override
17233843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen        public void onConnectionFailed() {
17243843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            Log.d(TAG, "BrowsablePlayerListBuilder: " + mCurrentPlayer.packageName + " FAIL");
17253843256f294cfd3e9b1d883e71ed7306738b6ca1Marie Janssen            connectNextPlayer();
1726e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1727e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1728e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
172905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    /* Initializes list of media players identified from session manager active sessions */
1730511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private void initMediaPlayersList() {
1731511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1732511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            // Clearing old browsable player's list
1733511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            mMediaPlayerInfoList.clear();
173405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
1735511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (mMediaSessionManager == null) {
1736511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (DEBUG) Log.w(TAG, "initMediaPlayersList: no media session manager!");
1737511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                return;
1738511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
173905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
1740511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            List<android.media.session.MediaController> controllers =
1741511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    mMediaSessionManager.getActiveSessions(null);
1742511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (DEBUG)
1743511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                Log.v(TAG, "initMediaPlayerInfoList: " + controllers.size() + " controllers");
1744511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            /* Initializing all media players */
1745511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (android.media.session.MediaController controller : controllers) {
1746511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                addMediaPlayerController(controller);
1747511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
1748511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (controllers.size() > 0) {
1749511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                mHandler.sendEmptyMessage(MSG_AVAILABLE_PLAYERS_CHANGED_RSP);
1750511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
1751e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1752511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (mMediaPlayerInfoList.size() > 0) {
1753511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                // Set the first one as the Addressed Player
1754511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                updateCurrentController(mMediaPlayerInfoList.firstKey(), -1);
1755511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
1756e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1757e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1758e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1759eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    private List<android.media.session.MediaController> getMediaControllers() {
1760eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        List<android.media.session.MediaController> controllers =
1761eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                new ArrayList<android.media.session.MediaController>();
1762511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1763511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (MediaPlayerInfo info : mMediaPlayerInfoList.values()) {
1764a1e42e29b15323e1a4d0559235a0987200663b2fMarie Janssen                MediaController controller = info.getMediaController();
1765a1e42e29b15323e1a4d0559235a0987200663b2fMarie Janssen                if (controller != null) {
1766a1e42e29b15323e1a4d0559235a0987200663b2fMarie Janssen                    controllers.add(controller.getWrappedInstance());
1767511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
1768eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            }
1769eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        }
1770eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        return controllers;
1771eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    }
1772eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
1773eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    /** Add (or update) a player to the media player list without a controller */
1774511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private boolean addMediaPlayerPackage(String packageName) {
1775eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        MediaPlayerInfo info = new MediaPlayerInfo(null, AvrcpConstants.PLAYER_TYPE_AUDIO,
1776eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                AvrcpConstants.PLAYER_SUBTYPE_NONE, getPlayStateBytes(null),
1777b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen                getFeatureBitMask(packageName), packageName, getAppLabel(packageName));
177805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        return addMediaPlayerInfo(info);
1779eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    }
1780eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
1781eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    /** Add (or update) a player to the media player list given an active controller */
1782511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private boolean addMediaPlayerController(android.media.session.MediaController controller) {
1783eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        String packageName = controller.getPackageName();
1784eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        MediaPlayerInfo info = new MediaPlayerInfo(MediaController.wrap(controller),
1785eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                AvrcpConstants.PLAYER_TYPE_AUDIO, AvrcpConstants.PLAYER_SUBTYPE_NONE,
1786eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                getPlayStateBytes(controller.getPlaybackState()), getFeatureBitMask(packageName),
1787b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen                controller.getPackageName(), getAppLabel(packageName));
178805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        return addMediaPlayerInfo(info);
1789eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    }
1790eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
179105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    /** Add or update a player to the media player list given the MediaPlayerInfo object.
179205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen     *  @return true if an item was updated, false if it was added instead
179305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen     */
1794511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private boolean addMediaPlayerInfo(MediaPlayerInfo info) {
1795b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen        int updateId = -1;
179605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        boolean updated = false;
1797511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1798511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
1799511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (info.getPackageName().equals(entry.getValue().getPackageName())) {
1800511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    updateId = entry.getKey();
1801511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    updated = true;
1802511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    break;
1803511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
1804b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen            }
1805511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (updateId == -1) {
1806511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                // New player
1807511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                mLastUsedPlayerID++;
1808511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                updateId = mLastUsedPlayerID;
1809511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
1810511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            mMediaPlayerInfoList.put(updateId, info);
1811384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            if (DEBUG)
1812384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen                Log.d(TAG, (updated ? "update #" : "add #") + updateId + ":" + info.toString());
1813384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            if (updateId == mCurrAddrPlayerID) {
1814384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen                updateCurrentController(mCurrAddrPlayerID, mCurrBrowsePlayerID);
1815384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            }
1816b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen        }
181705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        return updated;
1818eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    }
1819eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
1820eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    /** Remove all players related to |packageName| from the media player info list */
1821511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private MediaPlayerInfo removeMediaPlayerInfo(String packageName) {
1822511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1823511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int removeKey = -1;
1824511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
1825511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (entry.getValue().getPackageName().equals(packageName)) {
1826511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    removeKey = entry.getKey();
1827511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    break;
1828511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
1829511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
1830511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (removeKey != -1) {
1831384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen                if (DEBUG)
1832384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen                    Log.d(TAG, "remove #" + removeKey + ":" + mMediaPlayerInfoList.get(removeKey));
1833511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                return mMediaPlayerInfoList.remove(removeKey);
1834eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            }
1835b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen
1836511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            return null;
1837511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        }
1838eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    }
1839eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
1840384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen    /** Remove the controller referenced by |controller| from any player in the list */
1841f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen    private void removeMediaController(@Nullable android.media.session.MediaController controller) {
1842f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen        if (controller == null) return;
1843384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        synchronized (mMediaPlayerInfoList) {
1844f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
1845f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                MediaPlayerInfo info = entry.getValue();
1846a1e42e29b15323e1a4d0559235a0987200663b2fMarie Janssen                MediaController c = info.getMediaController();
1847f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                if (c != null && c.equals(controller)) {
1848f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    info.setMediaController(null);
1849f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    if (entry.getKey() == mCurrAddrPlayerID) {
1850f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                        updateCurrentController(mCurrAddrPlayerID, mCurrBrowsePlayerID);
1851f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    }
1852f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                }
1853384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            }
1854384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        }
1855384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen    }
1856384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen
1857e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
1858e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * utility function to get the playback state of any media player through
1859e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * media controller APIs.
1860e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
1861eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    private byte getPlayStateBytes(PlaybackState pbState) {
1862e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        byte playStateBytes = PLAYSTATUS_STOPPED;
1863e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1864e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (pbState != null) {
1865e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            playStateBytes = (byte)convertPlayStateToBytes(pbState.getState());
1866e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Log.v(TAG, "getPlayBackState: playStateBytes = " + playStateBytes);
1867e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
1868e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Log.w(TAG, "playState object null, sending playStateBytes = " + playStateBytes);
1869e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1870e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1871e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return playStateBytes;
1872e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1873e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1874e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
1875e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * utility function to map framework's play state values to AVRCP spec
1876e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * defined play status values
1877e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
1878e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private int convertPlayStateToBytes(int playState) {
1879e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        switch (playState) {
1880e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_PLAYING:
1881e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_BUFFERING:
1882e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_PLAYING;
1883e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1884e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_STOPPED:
1885e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_NONE:
1886e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_CONNECTING:
1887e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_STOPPED;
1888e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1889e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_PAUSED:
1890e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_PAUSED;
1891e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1892e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_FAST_FORWARDING:
1893e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_SKIPPING_TO_NEXT:
1894e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM:
1895e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_FWD_SEEK;
1896e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1897e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_REWINDING:
1898e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
1899e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_REV_SEEK;
1900e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1901e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            case PlaybackState.STATE_ERROR:
1902e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            default:
1903e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return PLAYSTATUS_ERROR;
1904e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1905e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1906e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1907e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
1908e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * utility function to get the feature bit mask of any media player through
1909e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * package name
1910e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
1911e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private short[] getFeatureBitMask(String packageName) {
1912e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1913e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ArrayList<Short> featureBitsList = new ArrayList<Short>();
1914e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1915e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* adding default feature bits */
1916e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_PLAY_BIT_NO);
1917e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_STOP_BIT_NO);
1918e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_PAUSE_BIT_NO);
1919e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_REWIND_BIT_NO);
1920e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_FAST_FWD_BIT_NO);
1921e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_FORWARD_BIT_NO);
1922e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_BACKWARD_BIT_NO);
1923e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        featureBitsList.add(AvrcpConstants.AVRC_PF_ADV_CTRL_BIT_NO);
1924e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1925e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Add/Modify browse player supported features. */
1926e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (isBrowseSupported(packageName)) {
1927e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_BROWSE_BIT_NO);
1928e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_UID_UNIQUE_BIT_NO);
1929e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_NOW_PLAY_BIT_NO);
1930e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsList.add(AvrcpConstants.AVRC_PF_GET_NUM_OF_ITEMS_BIT_NO);
1931e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1932e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1933e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // converting arraylist to array for response
1934e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        short[] featureBitsArray = new short[featureBitsList.size()];
1935e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1936e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        for (int i = 0; i < featureBitsList.size(); i++) {
1937e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            featureBitsArray[i] = featureBitsList.get(i).shortValue();
1938e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1939e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1940e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return featureBitsArray;
1941e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1942e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1943e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /**
1944e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * Checks the Package name if it supports Browsing or not.
1945e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     *
1946e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * @param packageName - name of the package to get the Id.
1947e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * @return true if it supports browsing, else false.
1948e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
1949511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private boolean isBrowseSupported(String packageName) {
1950511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mBrowsePlayerInfoList) {
1951511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            /* check if Browsable Player's list contains this package name */
1952511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (BrowsePlayerInfo info : mBrowsePlayerInfoList) {
1953511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (info.packageName.equals(packageName)) {
1954511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    if (DEBUG) Log.v(TAG, "isBrowseSupported for " + packageName + ": true");
1955511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    return true;
1956511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
1957e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
1958e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1959e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1960b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen        if (DEBUG) Log.v(TAG, "isBrowseSupported for " + packageName + ": false");
19611b70ec148be773651d5ad00e3ce0d28b3a63306dAjay Panicker        return false;
1962e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1963e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1964e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private String getPackageName(int id) {
1965511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        MediaPlayerInfo player = null;
1966511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1967511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            player = mMediaPlayerInfoList.getOrDefault(id, null);
1968511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        }
1969e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1970eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        if (player == null) {
1971eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            Log.w(TAG, "No package name for player (" + id + " not valid)");
1972eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            return "";
1973e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1974eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
1975eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        String packageName = player.getPackageName();
1976eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        if (DEBUG) Log.v(TAG, "Player " + id + " package: " + packageName);
1977e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return packageName;
1978e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1979e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1980e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* from the global object, getting the current browsed player's package name */
1981e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private String getCurrentBrowsedPlayer(byte[] bdaddr) {
1982e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browsedPlayerPackage = "";
1983e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1984e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Map<String, BrowsedMediaPlayer> connList = mAvrcpBrowseManager.getConnList();
1985e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String bdaddrStr = new String(bdaddr);
1986e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if(connList.containsKey(bdaddrStr)){
1987e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            browsedPlayerPackage = connList.get(bdaddrStr).getPackageName();
1988e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
1989e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.v(TAG, "getCurrentBrowsedPlayerPackage: " + browsedPlayerPackage);
1990e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return browsedPlayerPackage;
1991e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1992e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
1993eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen    /* Returns the MediaPlayerInfo for the currently addressed media player */
1994511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private MediaPlayerInfo getAddressedPlayerInfo() {
1995511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
1996511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            return mMediaPlayerInfoList.getOrDefault(mCurrAddrPlayerID, null);
1997511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        }
1998e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
1999e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2000e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
2001e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * Utility function to get the Media player info from package name returns
2002e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * null if package name not found in media players list
2003e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
2004511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private MediaPlayerInfo getMediaPlayerInfo(String packageName) {
2005511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
2006511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (mMediaPlayerInfoList.isEmpty()) {
2007511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (DEBUG) Log.v(TAG, "getMediaPlayerInfo: Media players list empty");
2008511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                return null;
2009511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2010eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
2011511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (MediaPlayerInfo info : mMediaPlayerInfoList.values()) {
2012511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (packageName.equals(info.getPackageName())) {
2013511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    if (DEBUG) Log.v(TAG, "getMediaPlayerInfo: Found " + packageName);
2014511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    return info;
2015511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
2016e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2017511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (DEBUG) Log.w(TAG, "getMediaPlayerInfo: " + packageName + " not found");
2018511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            return null;
2019e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2020e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2021e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2022e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* prepare media list & return the media player list response object */
2023511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private MediaPlayerListRsp prepareMediaPlayerRspObj() {
2024511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
2025511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int numPlayers = mMediaPlayerInfoList.size();
2026511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen
2027511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int[] playerIds = new int[numPlayers];
2028511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            byte[] playerTypes = new byte[numPlayers];
2029511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int[] playerSubTypes = new int[numPlayers];
2030511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            String[] displayableNameArray = new String[numPlayers];
2031511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            byte[] playStatusValues = new byte[numPlayers];
2032511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            short[] featureBitMaskValues =
2033511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    new short[numPlayers * AvrcpConstants.AVRC_FEATURE_MASK_SIZE];
2034511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen
2035511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int players = 0;
2036511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
2037511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                MediaPlayerInfo info = entry.getValue();
2038511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                playerIds[players] = entry.getKey();
2039511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                playerTypes[players] = info.getMajorType();
2040511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                playerSubTypes[players] = info.getSubType();
2041511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                displayableNameArray[players] = info.getDisplayableName();
2042511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                playStatusValues[players] = info.getPlayStatus();
2043511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen
2044511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                short[] featureBits = info.getFeatureBitMask();
2045511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                for (int numBit = 0; numBit < featureBits.length; numBit++) {
2046511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    /* gives which octet this belongs to */
2047511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    byte octet = (byte) (featureBits[numBit] / 8);
2048511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    /* gives the bit position within the octet */
2049511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    byte bit = (byte) (featureBits[numBit] % 8);
2050511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    featureBitMaskValues[(players * AvrcpConstants.AVRC_FEATURE_MASK_SIZE)
2051511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                            + octet] |= (1 << bit);
2052511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
2053e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2054511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                /* printLogs */
2055511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                if (DEBUG) {
2056511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    Log.d(TAG, "Player " + playerIds[players] + ": " + displayableNameArray[players]
2057511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                                    + " type: " + playerTypes[players] + ", "
2058511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                                    + playerSubTypes[players] + " status: "
2059511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                                    + playStatusValues[players]);
2060511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                }
2061e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2062511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                players++;
2063511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2064e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2065511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (DEBUG) Log.d(TAG, "prepareMediaPlayerRspObj: numPlayers = " + numPlayers);
2066e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2067511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            return new MediaPlayerListRsp(AvrcpConstants.RSP_NO_ERROR, sUIDCounter, numPlayers,
2068511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    AvrcpConstants.BTRC_ITEM_PLAYER, playerIds, playerTypes, playerSubTypes,
2069511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                    playStatusValues, featureBitMaskValues, displayableNameArray);
2070511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        }
2071e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2072e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2073e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     /* build media player list and send it to remote. */
2074e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handleMediaPlayerListRsp(AvrcpCmd.FolderItemsCmd folderObj) {
2075511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        MediaPlayerListRsp rspObj = null;
2076511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
2077511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int numPlayers = mMediaPlayerInfoList.size();
2078511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (numPlayers == 0) {
2079511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                mediaPlayerListRspNative(folderObj.mAddress, AvrcpConstants.RSP_NO_AVBL_PLAY,
2080511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                        (short) 0, (byte) 0, 0, null, null, null, null, null, null);
2081511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                return;
2082511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2083511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (folderObj.mStartItem >= numPlayers) {
2084511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                Log.i(TAG, "handleMediaPlayerListRsp: start = " + folderObj.mStartItem
2085511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                                + " > num of items = " + numPlayers);
2086511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                mediaPlayerListRspNative(folderObj.mAddress, AvrcpConstants.RSP_INV_RANGE,
2087511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                        (short) 0, (byte) 0, 0, null, null, null, null, null, null);
2088511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                return;
2089511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2090511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            rspObj = prepareMediaPlayerRspObj();
2091e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2092511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        if (DEBUG) Log.d(TAG, "handleMediaPlayerListRsp: sending " + rspObj.mNumItems + " players");
2093eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        mediaPlayerListRspNative(folderObj.mAddress, rspObj.mStatus, rspObj.mUIDCounter,
2094eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                rspObj.itemType, rspObj.mNumItems, rspObj.mPlayerIds, rspObj.mPlayerTypes,
2095eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                rspObj.mPlayerSubTypes, rspObj.mPlayStatusValues, rspObj.mFeatureBitMaskValues,
2096eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                rspObj.mPlayerNameList);
2097e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2098e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2099e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* unregister to the old controller, update new IDs and register to the new controller */
2100e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean updateCurrentController(int addrId, int browseId) {
2101e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean registerRsp = true;
2102e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2103e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        updateNewIds(addrId, browseId);
2104e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2105eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        MediaController newController = null;
2106eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        MediaPlayerInfo info = getAddressedPlayerInfo();
210778d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        if (info != null) newController = info.getMediaController();
2108eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen
2109eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        if (DEBUG)
2110eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            Log.d(TAG, "updateCurrentController: " + mMediaController + " to " + newController);
2111ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen        synchronized (this) {
2112ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen            if (mMediaController == null || (!mMediaController.equals(newController))) {
2113f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                if (mMediaController != null) {
2114f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    mMediaController.unregisterCallback(mMediaControllerCb);
2115f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                }
2116f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                mMediaController = newController;
2117f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                if (mMediaController != null) {
2118f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    mMediaController.registerCallback(mMediaControllerCb, mHandler);
2119f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    mAddressedMediaPlayer.updateNowPlayingList(mMediaController.getQueue());
2120f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                } else {
2121f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    mAddressedMediaPlayer.updateNowPlayingList(null);
2122f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                    registerRsp = false;
2123f6521ba818df22d8a853d25f7c6adc1e724875e6Marie Janssen                }
2124eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            }
2125e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2126ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen        updateCurrentMediaState();
2127eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        return registerRsp;
2128e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2129e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2130e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Handle getfolderitems for scope = VFS, Search, NowPlayingList */
2131e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handleGetFolderItemBrowseResponse(AvrcpCmd.FolderItemsCmd folderObj, byte[] bdaddr) {
2132e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        int status = AvrcpConstants.RSP_NO_ERROR;
2133e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2134e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Browsed player is already set */
213505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (folderObj.mScope == AvrcpConstants.BTRC_SCOPE_FILE_SYSTEM) {
213605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) == null) {
213705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                Log.e(TAG, "handleGetFolderItemBrowseResponse: no browsed player set for "
213805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                                + Utils.getAddressStringFromByte(bdaddr));
213905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                getFolderItemsRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR, (short) 0,
214005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                        (byte) 0x00, 0, null, null, null, null, null, null, null, null);
214105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return;
214205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            }
214305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).getFolderItemsVFS(folderObj);
214405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            return;
2145e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
214605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (folderObj.mScope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
214705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            mAddressedMediaPlayer.getFolderItemsNowPlaying(bdaddr, folderObj, mMediaController);
214805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            return;
2149e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2150e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
215105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        /* invalid scope */
215205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        Log.e(TAG, "handleGetFolderItemBrowseResponse: unknown scope " + folderObj.mScope);
215305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        getFolderItemsRspNative(bdaddr, AvrcpConstants.RSP_INV_SCOPE, (short) 0, (byte) 0x00, 0,
215405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                null, null, null, null, null, null, null, null);
2155e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2156e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2157e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* utility function to update the global values of current Addressed and browsed player */
2158511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen    private void updateNewIds(int addrId, int browseId) {
215978d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        if (DEBUG)
216078d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            Log.v(TAG, "updateNewIds: Addressed:" + mCurrAddrPlayerID + " to " + addrId
216178d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen                            + ", Browse:" + mCurrBrowsePlayerID + " to " + browseId);
2162e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mCurrAddrPlayerID = addrId;
2163e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        mCurrBrowsePlayerID = browseId;
2164e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2165e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2166e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* Getting the application's displayable name from package name */
2167e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private String getAppLabel(String packageName) {
2168e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ApplicationInfo appInfo = null;
2169e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        try {
2170e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            appInfo = mPackageManager.getApplicationInfo(packageName, 0);
2171e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } catch (NameNotFoundException e) {
2172e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            e.printStackTrace();
2173e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2174e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2175e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return (String) (appInfo != null ? mPackageManager
2176e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                .getApplicationLabel(appInfo) : "Unknown");
2177e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2178e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2179e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handlePlayItemResponse(byte[] bdaddr, byte[] uid, byte scope) {
2180294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen        if (scope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
2181294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen            mAddressedMediaPlayer.playItem(bdaddr, uid, mMediaController);
2182e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2183e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        else {
2184e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if(!isAddrPlayerSameAsBrowsed(bdaddr)) {
2185e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.w(TAG, "Remote requesting play item on uid which may not be recognized by" +
2186e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        "current addressed player");
2187e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                playItemRspNative(bdaddr, AvrcpConstants.RSP_INV_ITEM);
2188e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2189e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2190e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) {
2191e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).playItem(uid, scope);
2192e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2193e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "handlePlayItemResponse: Remote requested playitem " +
2194e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        "before setbrowsedplayer");
2195e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                playItemRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR);
2196e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2197e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2198e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2199e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2200e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handleGetItemAttr(AvrcpCmd.ItemAttrCmd itemAttr) {
2201384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        if (itemAttr.mScope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
2202384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            if (mCurrAddrPlayerID == NO_PLAYER_ID) {
2203384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen                getItemAttrRspNative(
2204384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen                        itemAttr.mAddress, AvrcpConstants.RSP_NO_AVBL_PLAY, (byte) 0, null, null);
2205c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen                return;
2206384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen            }
2207c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen            mAddressedMediaPlayer.getItemAttr(itemAttr.mAddress, itemAttr, mMediaController);
2208c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen            return;
2209c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen        }
2210c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen        // All other scopes use browsed player
2211c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen        if (mAvrcpBrowseManager.getBrowsedMediaPlayer(itemAttr.mAddress) != null) {
2212c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen            mAvrcpBrowseManager.getBrowsedMediaPlayer(itemAttr.mAddress).getItemAttr(itemAttr);
2213384011244f5a62ed34f198b8ba91341b4efb4fb6Marie Janssen        } else {
2214c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen            Log.e(TAG, "Could not get attributes. mBrowsedMediaPlayer is null");
2215c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen            getItemAttrRspNative(
2216c1267074b7df0d6e42cefea0ac40b584fdb1430fMarie Janssen                    itemAttr.mAddress, AvrcpConstants.RSP_INTERNAL_ERR, (byte) 0, null, null);
2217e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2218e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2219e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2220e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private void handleGetTotalNumOfItemsResponse(byte[] bdaddr, byte scope) {
2221e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // for scope as media player list
2222e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (scope == AvrcpConstants.BTRC_SCOPE_PLAYER_LIST) {
2223511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            int numPlayers = 0;
2224511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            synchronized (mMediaPlayerInfoList) {
2225511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                numPlayers = mMediaPlayerInfoList.size();
2226511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
2227511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            if (DEBUG) Log.d(TAG, "handleGetTotalNumOfItemsResponse: " + numPlayers + " players.");
2228511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            getTotalNumOfItemsRspNative(bdaddr, AvrcpConstants.RSP_NO_ERROR, 0, numPlayers);
2229511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        } else if (scope == AvrcpConstants.BTRC_SCOPE_NOW_PLAYING) {
2230294ff299ca4837fd7f56861941b274fadee97ec4Marie Janssen            mAddressedMediaPlayer.getTotalNumOfItems(bdaddr, mMediaController);
2231e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        } else {
2232e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // for FileSystem browsing scopes as VFS, Now Playing
2233e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr) != null) {
2234e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mAvrcpBrowseManager.getBrowsedMediaPlayer(bdaddr).getTotalNumOfItems(scope);
2235e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2236e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "Could not get Total NumOfItems. mBrowsedMediaPlayer is null");
2237e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                getTotalNumOfItemsRspNative(bdaddr, AvrcpConstants.RSP_INTERNAL_ERR, 0, 0);
2238e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2239e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2240e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2241e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2242e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2243e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* check if browsed player and addressed player are same */
2244e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isAddrPlayerSameAsBrowsed(byte[] bdaddr) {
2245e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        String browsedPlayer = getCurrentBrowsedPlayer(bdaddr);
2246e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2247e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (!isPackageNameValid(browsedPlayer)) {
2248e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Log.w(TAG, "Browsed player name empty");
2249eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            return false;
2250e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2251e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2252b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen        MediaPlayerInfo info = getAddressedPlayerInfo();
2253db2d487ba559f0e4de02bc2ad4cc7e275878b2fcMarie Janssen        String packageName = (info == null) ? "<none>" : info.getPackageName();
2254db2d487ba559f0e4de02bc2ad4cc7e275878b2fcMarie Janssen        if (info == null || !packageName.equals(browsedPlayer)) {
2255db2d487ba559f0e4de02bc2ad4cc7e275878b2fcMarie Janssen            if (DEBUG) Log.d(TAG, browsedPlayer + " is not addressed player " + packageName);
2256eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            return false;
2257eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        }
2258eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen        return true;
2259e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2260e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2261e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* checks if package name is not null or empty */
2262e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isPackageNameValid(String browsedPackage) {
2263e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean isValid = (browsedPackage != null && browsedPackage.length() > 0);
2264e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "isPackageNameValid: browsedPackage = " + browsedPackage +
2265e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                "isValid = " + isValid);
2266e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return isValid;
2267e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2268e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2269e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* checks if selected addressed player is already addressed */
2270e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private boolean isPlayerAlreadyAddressed(int selectedId) {
2271e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // checking if selected ID is same as the current addressed player id
2272e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        boolean isAddressed = (mCurrAddrPlayerID == selectedId);
2273e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        if (DEBUG) Log.d(TAG, "isPlayerAlreadyAddressed: isAddressed = " + isAddressed);
2274e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return isAddressed;
2275e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2276e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2277e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    public void dump(StringBuilder sb) {
2278e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        sb.append("AVRCP:\n");
2279e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mMediaAttributes: " + mMediaAttributes);
2280e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags);
2281e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState);
2282e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT);
2283e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT);
2284e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs);
2285e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT);
2286e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mNextPosMs: " + mNextPosMs);
2287e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mPrevPosMs: " + mPrevPosMs);
2288e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mFeatures: " + mFeatures);
2289e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mRemoteVolume: " + mRemoteVolume);
2290e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mLastRemoteVolume: " + mLastRemoteVolume);
2291e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mLastDirection: " + mLastDirection);
2292e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mVolumeStep: " + mVolumeStep);
2293e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mAudioStreamMax: " + mAudioStreamMax);
2294e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mVolCmdAdjustInProgress: " + mVolCmdAdjustInProgress);
2295e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mVolCmdSetInProgress: " + mVolCmdSetInProgress);
2296e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mAbsVolRetryTimes: " + mAbsVolRetryTimes);
2297e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        ProfileService.println(sb, "mVolumeMapping: " + mVolumeMapping.toString());
2298ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen        synchronized (this) {
2299ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen            if (mMediaController != null)
2300ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                ProfileService.println(sb, "mMediaController: "
2301ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                                + mMediaController.getWrappedInstance() + " pkg "
2302ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen                                + mMediaController.getPackageName());
2303ad7a50ece55752b9b7e47cd86dc45de368c8c6d5Marie Janssen        }
230478d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        ProfileService.println(sb, "");
230578d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        ProfileService.println(sb, "Media Players:");
2306511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen        synchronized (mMediaPlayerInfoList) {
2307511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            for (Map.Entry<Integer, MediaPlayerInfo> entry : mMediaPlayerInfoList.entrySet()) {
2308511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                int key = entry.getKey();
2309511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                ProfileService.println(sb, ((mCurrAddrPlayerID == key) ? " *#" : "  #")
2310511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen                                + entry.getKey() + ": " + entry.getValue());
2311511ebf9e8dfa9f39315de93ad9a5dcf72556676eMarie Janssen            }
231205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
231305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
2314e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen        ProfileService.println(sb, "");
2315e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen        mAddressedMediaPlayer.dump(sb, mMediaController);
2316e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen
2317e5384f02ec837a8f274ed59548cb6879849239f5Marie Janssen        ProfileService.println(sb, "");
231878d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        ProfileService.println(sb, mPassthroughDispatched + " passthrough operations: ");
231978d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        if (mPassthroughDispatched > mPassthroughLogs.size())
232078d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            ProfileService.println(sb, "  (last " + mPassthroughLogs.size() + ")");
232178d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        synchronized (mPassthroughLogs) {
232278d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            for (MediaKeyLog log : mPassthroughLogs) {
232378d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen                ProfileService.println(sb, "  " + log);
232478d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            }
232505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
232678d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        synchronized (mPassthroughPending) {
232778d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            for (MediaKeyLog log : mPassthroughPending) {
232878d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen                ProfileService.println(sb, "  " + log);
232978d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            }
2330b8faaf4863cfae62c32af644765a9190512925c9Marie Janssen        }
2331e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2332e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2333e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    public class AvrcpBrowseManager {
2334e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        Map<String, BrowsedMediaPlayer> connList = new HashMap<String, BrowsedMediaPlayer>();
2335e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private AvrcpMediaRspInterface mMediaInterface;
2336e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private Context mContext;
2337e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2338e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public AvrcpBrowseManager(Context context, AvrcpMediaRspInterface mediaInterface) {
2339e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            mContext = context;
2340e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            mMediaInterface = mediaInterface;
2341e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2342e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2343e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void cleanup() {
2344e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            Iterator entries = connList.entrySet().iterator();
2345e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            while (entries.hasNext()) {
2346e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Map.Entry entry = (Map.Entry) entries.next();
2347e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                BrowsedMediaPlayer browsedMediaPlayer = (BrowsedMediaPlayer) entry.getValue();
2348e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (browsedMediaPlayer != null) {
2349e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    browsedMediaPlayer.cleanup();
2350e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                }
2351e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2352e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            // clean up the map
2353e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            connList.clear();
2354e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2355e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2356e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // get the a free media player interface based on the passed bd address
2357e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // if the no items is found for the passed media player then it assignes a
2358e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // available media player interface
2359e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public BrowsedMediaPlayer getBrowsedMediaPlayer(byte[] bdaddr) {
2360e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            BrowsedMediaPlayer mediaPlayer;
2361e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String bdaddrStr = new String(bdaddr);
236205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            if (connList.containsKey(bdaddrStr)) {
2363e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mediaPlayer = connList.get(bdaddrStr);
2364e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2365e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                mediaPlayer = new BrowsedMediaPlayer(bdaddr, mContext, mMediaInterface);
2366e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                connList.put(bdaddrStr, mediaPlayer);
2367e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2368e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return mediaPlayer;
2369e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2370e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2371e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        // clears the details pertaining to passed bdaddres
2372e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public boolean clearBrowsedMediaPlayer(byte[] bdaddr) {
2373e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String bdaddrStr = new String(bdaddr);
237405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            if (connList.containsKey(bdaddrStr)) {
2375e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                connList.remove(bdaddrStr);
2376e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                return true;
2377e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2378e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return false;
2379e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2380e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2381e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public Map<String, BrowsedMediaPlayer> getConnList() {
2382e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return connList;
2383e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2384e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2385e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        /* Helper function to convert colon separated bdaddr to byte string */
2386e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private byte[] hexStringToByteArray(String s) {
2387e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int len = s.length();
2388e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            byte[] data = new byte[len / 2];
2389e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            for (int i = 0; i < len; i += 2) {
2390e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
2391e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        + Character.digit(s.charAt(i+1), 16));
2392e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2393e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            return data;
2394e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2395e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2396e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2397e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /*
2398e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * private class which handles responses from AvrcpMediaManager. Maps responses to native
2399e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     * responses. This class implements the AvrcpMediaRspInterface interface.
2400e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah     */
2401e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private class AvrcpMediaRsp implements AvrcpMediaRspInterface {
2402e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        private static final String TAG = "AvrcpMediaRsp";
2403e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2404e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void setAddrPlayerRsp(byte[] address, int rspStatus) {
2405e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!setAddressedPlayerRspNative(address, rspStatus)) {
2406e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "setAddrPlayerRsp failed!");
2407e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2408e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2409e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2410e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void setBrowsedPlayerRsp(byte[] address, int rspStatus, byte depth, int numItems,
2411e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                String[] textArray) {
2412e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!setBrowsedPlayerRspNative(address, rspStatus, depth, numItems, textArray)) {
2413e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "setBrowsedPlayerRsp failed!");
2414e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2415e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2416e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2417e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void mediaPlayerListRsp(byte[] address, int rspStatus, MediaPlayerListRsp rspObj) {
2418e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) {
2419e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!mediaPlayerListRspNative(address, rspStatus, sUIDCounter, rspObj.itemType,
2420eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                            rspObj.mNumItems, rspObj.mPlayerIds, rspObj.mPlayerTypes,
2421eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                            rspObj.mPlayerSubTypes, rspObj.mPlayStatusValues,
2422eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                            rspObj.mFeatureBitMaskValues, rspObj.mPlayerNameList))
2423eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                    Log.e(TAG, "mediaPlayerListRsp failed!");
2424e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2425e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "mediaPlayerListRsp: rspObj is null");
2426eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                if (!mediaPlayerListRspNative(address, rspStatus, sUIDCounter, (byte) 0x00, 0, null,
2427eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                            null, null, null, null, null))
2428eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen                    Log.e(TAG, "mediaPlayerListRsp failed!");
2429e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2430e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2431e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2432e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void folderItemsRsp(byte[] address, int rspStatus, FolderItemsRsp rspObj) {
2433e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) {
2434e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!getFolderItemsRspNative(address, rspStatus, sUIDCounter, rspObj.mScope,
2435e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        rspObj.mNumItems, rspObj.mFolderTypes, rspObj.mPlayable, rspObj.mItemTypes,
2436e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        rspObj.mItemUid, rspObj.mDisplayNames, rspObj.mAttributesNum,
2437e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        rspObj.mAttrIds, rspObj.mAttrValues))
2438e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getFolderItemsRspNative failed!");
2439e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2440e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "folderItemsRsp: rspObj is null or rspStatus is error:" + rspStatus);
2441e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!getFolderItemsRspNative(address, rspStatus, sUIDCounter, (byte) 0x00, 0,
2442e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        null, null, null, null, null, null, null, null))
2443e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getFolderItemsRspNative failed!");
2444e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2445e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2446e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2447e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2448e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void changePathRsp(byte[] address, int rspStatus, int numItems) {
2449e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!changePathRspNative(address, rspStatus, numItems))
2450e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "changePathRspNative failed!");
2451e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2452e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2453e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void getItemAttrRsp(byte[] address, int rspStatus, ItemAttrRsp rspObj) {
2454e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (rspObj != null && rspStatus == AvrcpConstants.RSP_NO_ERROR) {
2455e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!getItemAttrRspNative(address, rspStatus, rspObj.mNumAttr,
2456e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                        rspObj.mAttributesIds, rspObj.mAttributesArray))
2457e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getItemAttrRspNative failed!");
2458e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            } else {
2459e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "getItemAttrRsp: rspObj is null or rspStatus is error:" + rspStatus);
2460e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                if (!getItemAttrRspNative(address, rspStatus, (byte) 0x00, null, null))
2461e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                    Log.e(TAG, "getItemAttrRspNative failed!");
2462e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2463e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2464e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2465e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void playItemRsp(byte[] address, int rspStatus) {
2466e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!playItemRspNative(address, rspStatus)) {
2467e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "playItemRspNative failed!");
2468e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2469e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2470e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2471e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void getTotalNumOfItemsRsp(byte[] address, int rspStatus, int uidCounter,
2472e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                int numItems) {
2473e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!getTotalNumOfItemsRspNative(address, rspStatus, sUIDCounter, numItems)) {
2474e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "getTotalNumOfItemsRspNative failed!");
2475e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2476e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2477e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
247805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        public void addrPlayerChangedRsp(int type, int playerId, int uidCounter) {
2479e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspAddrPlayerChangedNative(type, playerId, sUIDCounter)) {
2480e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspAddrPlayerChangedNative failed!");
2481e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2482e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2483e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2484e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void avalPlayerChangedRsp(byte[] address, int type) {
2485e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspAvalPlayerChangedNative(type)) {
2486e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspAvalPlayerChangedNative failed!");
2487e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2488e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2489e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2490e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void uidsChangedRsp(byte[] address, int type, int uidCounter) {
2491e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspUIDsChangedNative(type, sUIDCounter)) {
2492e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspUIDsChangedNative failed!");
2493e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2494e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2495e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2496e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void nowPlayingChangedRsp(int type) {
2497e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspNowPlayingChangedNative(type)) {
2498e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspNowPlayingChangedNative failed!");
2499e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2500e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2501e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2502e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        public void trackChangedRsp(int type, byte[] uid) {
2503e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            if (!registerNotificationRspTrackChangeNative(type, uid)) {
2504e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah                Log.e(TAG, "registerNotificationRspTrackChangeNative failed!");
2505e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            }
2506e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        }
2507e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2508e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2509e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    /* getters for some private variables */
2510e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    public AvrcpBrowseManager getAvrcpBrowseManager() {
2511e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        return mAvrcpBrowseManager;
2512e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    }
2513e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
251405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    /* PASSTHROUGH COMMAND MANAGEMENT */
251505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
251605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    void handlePassthroughCmd(int op, int state) {
251705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        int code = avrcpPassthroughToKeyCode(op);
251805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (code == KeyEvent.KEYCODE_UNKNOWN) {
251905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            Log.w(TAG, "Ignoring passthrough of unknown key " + op + " state " + state);
252005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            return;
252105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
252205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        int action = KeyEvent.ACTION_DOWN;
252305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (state == AvrcpConstants.KEY_STATE_RELEASE) action = KeyEvent.ACTION_UP;
252405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        KeyEvent event = new KeyEvent(action, code);
252505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        if (!KeyEvent.isMediaKey(code)) {
252605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            Log.w(TAG, "Passthrough non-media key " + op + " (code " + code + ") state " + state);
252705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
252805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        mMediaSessionManager.dispatchMediaKeyEvent(event);
252905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        addKeyPending(event);
253005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
253105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
253205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private int avrcpPassthroughToKeyCode(int operation) {
253305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        switch (operation) {
253405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_UP:
253505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_UP;
253605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_DOWN:
253705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_DOWN;
253805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_LEFT:
253905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_LEFT;
254005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT:
254105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_RIGHT;
254205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT_UP:
254305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_UP_RIGHT;
254405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RIGHT_DOWN:
254505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_DOWN_RIGHT;
254605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_LEFT_UP:
254705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_UP_LEFT;
254805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_LEFT_DOWN:
254905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_DPAD_DOWN_LEFT;
255005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_0:
255105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_0;
255205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_1:
255305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_1;
255405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_2:
255505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_2;
255605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_3:
255705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_3;
255805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_4:
255905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_4;
256005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_5:
256105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_5;
256205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_6:
256305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_6;
256405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_7:
256505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_7;
256605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_8:
256705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_8;
256805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_9:
256905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_9;
257005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_DOT:
257105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_DOT;
257205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_ENTER:
257305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_NUMPAD_ENTER;
257405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CLEAR:
257505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_CLEAR;
257605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CHAN_UP:
257705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_CHANNEL_UP;
257805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CHAN_DOWN:
257905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_CHANNEL_DOWN;
258005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_PREV_CHAN:
258105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_LAST_CHANNEL;
258205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_INPUT_SEL:
258305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_TV_INPUT;
258405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_DISP_INFO:
258505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_INFO;
258605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_HELP:
258705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_HELP;
258805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_PAGE_UP:
258905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_PAGE_UP;
259005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_PAGE_DOWN:
259105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_PAGE_DOWN;
259205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_POWER:
259305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_POWER;
259405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_VOL_UP:
259505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_VOLUME_UP;
259605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_VOL_DOWN:
259705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_VOLUME_DOWN;
259805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_MUTE:
259905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MUTE;
260005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_PLAY:
260105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_PLAY;
260205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_STOP:
260305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_STOP;
260405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_PAUSE:
260505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_PAUSE;
260605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_RECORD:
260705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_RECORD;
260805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_REWIND:
260905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_REWIND;
261005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR:
261105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
261205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_EJECT:
261305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_EJECT;
261405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_FORWARD:
261505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_NEXT;
261605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_BACKWARD:
261705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_MEDIA_PREVIOUS;
261805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F1:
261905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_F1;
262005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F2:
262105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_F2;
262205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F3:
262305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_F3;
262405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F4:
262505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_F4;
262605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_F5:
262705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_F5;
262805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            // Fallthrough for all unknown key mappings
262905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SELECT:
263005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_ROOT_MENU:
263105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SETUP_MENU:
263205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_CONT_MENU:
263305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_FAV_MENU:
263405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_EXIT:
263505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SOUND_SEL:
263605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_ANGLE:
263705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_SUBPICT:
263805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            case BluetoothAvrcp.PASSTHROUGH_ID_VENDOR:
263905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            default:
264005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                return KeyEvent.KEYCODE_UNKNOWN;
264105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
264205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
264305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
264405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private void addKeyPending(KeyEvent event) {
264578d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        mPassthroughPending.add(new MediaKeyLog(System.currentTimeMillis(), event));
264605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
264705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
264805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private void recordKeyDispatched(KeyEvent event, String packageName) {
264905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        long time = System.currentTimeMillis();
265005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        Log.v(TAG, "recordKeyDispatched: " + event + " dispatched to " + packageName);
265178d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen        setAddressedMediaSessionPackage(packageName);
265205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        synchronized (mPassthroughPending) {
265305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            Iterator<MediaKeyLog> pending = mPassthroughPending.iterator();
265405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            while (pending.hasNext()) {
265505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                MediaKeyLog log = pending.next();
265605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                if (log.addDispatch(time, event, packageName)) {
265705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    mPassthroughDispatched++;
265805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    mPassthroughLogs.add(log);
265905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    pending.remove();
266005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    return;
266105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                }
266205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            }
266378d53f7d7133cb5a32e1160e1c1a23f2e8174978Marie Janssen            Log.w(TAG, "recordKeyDispatch: can't find matching log!");
266405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen        }
266505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    }
266605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
266705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen    private final MediaSessionManager.Callback mButtonDispatchCallback =
266805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            new MediaSessionManager.Callback() {
266905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                @Override
267005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                public void onMediaKeyEventDispatched(KeyEvent event, MediaSession.Token token) {
267105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    // Get the package name
267205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    android.media.session.MediaController controller =
267305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                            new android.media.session.MediaController(mContext, token);
267405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    String targetPackage = controller.getPackageName();
267505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    recordKeyDispatched(event, targetPackage);
267605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                }
267705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
267805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                @Override
267905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                public void onMediaKeyEventDispatched(KeyEvent event, ComponentName receiver) {
268005df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    recordKeyDispatched(event, receiver.getPackageName());
268105df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                }
268205df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
268305df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                @Override
268405df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                public void onAddressedPlayerChanged(MediaSession.Token token) {
268505df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    setActiveMediaSession(token);
268605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                }
268705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
268805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                @Override
268905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                public void onAddressedPlayerChanged(ComponentName receiver) {
269041527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                    if (receiver == null) {
269141527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                        // No active sessions, and no session to revive, give up.
269241527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                        setAddressedMediaSessionPackage(null);
269341527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                        return;
269441527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                    }
269541527b2493a4ea59933c7cd4f8d1c761598509d8Marie Janssen                    // We can still get a passthrough which will revive this player.
269605df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                    setAddressedMediaSessionPackage(receiver.getPackageName());
269705df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen                }
269805df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen            };
269905df242b454cbe62dab2bfaa07ab2b236ed00f67Marie Janssen
2700e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // Do not modify without updating the HAL bt_rc.h files.
2701e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2702e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // match up with btrc_play_status_t enum of bt_rc.h
2703e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int PLAYSTATUS_STOPPED = 0;
2704e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int PLAYSTATUS_PLAYING = 1;
2705e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int PLAYSTATUS_PAUSED = 2;
2706e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int PLAYSTATUS_FWD_SEEK = 3;
2707e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int PLAYSTATUS_REV_SEEK = 4;
2708e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int PLAYSTATUS_ERROR = 255;
2709e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2710e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // match up with btrc_media_attr_t enum of bt_rc.h
2711e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_TITLE = 1;
2712e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_ARTIST = 2;
2713e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_ALBUM = 3;
2714e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_TRACK_NUM = 4;
2715e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_NUM_TRACKS = 5;
2716e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_GENRE = 6;
2717e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int MEDIA_ATTR_PLAYING_TIME = 7;
2718e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah
2719e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    // match up with btrc_event_id_t enum of bt_rc.h
2720e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_PLAY_STATUS_CHANGED = 1;
2721e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_TRACK_CHANGED = 2;
2722e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_TRACK_REACHED_END = 3;
2723e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_TRACK_REACHED_START = 4;
2724e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_PLAY_POS_CHANGED = 5;
2725e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_BATT_STATUS_CHANGED = 6;
2726e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_SYSTEM_STATUS_CHANGED = 7;
2727e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_APP_SETTINGS_CHANGED = 8;
2728e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVENT_NOW_PLAYING_CONTENT_CHANGED = 9;
2729e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_AVBL_PLAYERS_CHANGED = 0xa;
2730e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVT_ADDR_PLAYER_CHANGED = 0xb;
2731e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    final static int EVENT_UIDS_CHANGED = 0x0c;
2732c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
2733c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native static void classInitNative();
2734c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native void initNative();
2735c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native void cleanupNative();
2736e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getPlayStatusRspNative(byte[] address, int playStatus, int songLen,
2737e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int songPos);
2738e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getElementAttrRspNative(byte[] address, byte numAttr, int[] attrIds,
2739e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String[] textArray);
2740c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean registerNotificationRspPlayStatusNative(int type, int playStatus);
2741c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean registerNotificationRspTrackChangeNative(int type, byte[] track);
2742aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private native boolean registerNotificationRspPlayPosNative(int type, int playPos);
274317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private native boolean setVolumeNative(int volume);
27445c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta    private native boolean sendPassThroughCommandNative(int keyCode, int keyState);
2745e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean setAddressedPlayerRspNative(byte[] address, int rspStatus);
2746e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean setBrowsedPlayerRspNative(byte[] address, int rspStatus, byte depth,
2747e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int numItems, String[] textArray);
2748e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean mediaPlayerListRspNative(byte[] address, int rsStatus, int uidCounter,
2749eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            byte item_type, int numItems, int[] playerIds, byte[] playerTypes, int[] playerSubTypes,
2750eef486e7e3145cc7b302ee1b00bbd317481cdabdMarie Janssen            byte[] playStatusValues, short[] featureBitMaskValues, String[] textArray);
2751e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getFolderItemsRspNative(byte[] address, int rspStatus, short uidCounter,
2752e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            byte scope, int numItems, byte[] folderTypes, byte[] playable, byte[] itemTypes,
2753e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            byte[] itemUidArray, String[] textArray, int[] AttributesNum, int[] AttributesIds,
2754e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            String[] attributesArray);
2755e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean changePathRspNative(byte[] address, int rspStatus, int numItems);
2756e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getItemAttrRspNative(byte[] address, int rspStatus, byte numAttr,
2757e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int[] attrIds, String[] textArray);
2758e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean playItemRspNative(byte[] address, int rspStatus);
2759e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean getTotalNumOfItemsRspNative(byte[] address, int rspStatus,
2760e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int uidCounter, int numItems);
2761e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean searchRspNative(byte[] address, int rspStatus, int uidCounter,
2762e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah            int numItems);
2763e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean addToNowPlayingRspNative(byte[] address, int rspStatus);
2764e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean registerNotificationRspAddrPlayerChangedNative(int type,
2765e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah        int playerId, int uidCounter);
2766e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean registerNotificationRspAvalPlayerChangedNative(int type);
2767e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean registerNotificationRspUIDsChangedNative(int type, int uidCounter);
2768e90c830b72f97189935e99e9e4f5a0c4f216ba72Avish Shah    private native boolean registerNotificationRspNowPlayingChangedNative(int type);
27695c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta
2770c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
2771