Avrcp.java revision 2fc493d0ea2b504df25d783a488dfadfe301329e
1c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu/*
2c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * Copyright (C) 2012 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
19ace834feb02adabd61f628c4471147aea02d939cJohn Duimport java.util.Timer;
20ace834feb02adabd61f628c4471147aea02d939cJohn Duimport java.util.TimerTask;
21ace834feb02adabd61f628c4471147aea02d939cJohn Du
22188f205b5f093850d4cc627917a21204be36c56aZhihai Xuimport android.bluetooth.BluetoothA2dp;
23066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.bluetooth.BluetoothAvrcp;
24c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.content.Context;
25aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport android.content.Intent;
2611798b011c962b602217b479130d413f3b30f19aLiejun Taoimport android.content.res.Resources;
2711798b011c962b602217b479130d413f3b30f19aLiejun Taoimport android.content.SharedPreferences;
28c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.graphics.Bitmap;
29c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.AudioManager;
30c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.MediaMetadataRetriever;
312fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssenimport android.media.MediaMetadata;
322fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssenimport android.media.session.MediaController;
332fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssenimport android.media.session.MediaSessionManager;
342fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssenimport android.media.session.PlaybackState;
35c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Bundle;
36c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Handler;
37c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.HandlerThread;
38c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Looper;
39c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Message;
40c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.ParcelUuid;
41c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.PowerManager;
42c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.PowerManager.WakeLock;
43c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.RemoteException;
44c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.ServiceManager;
45aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport android.os.SystemClock;
46c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.util.Log;
47881675b362bde18acbbcf69c513175addca4a8baZhenye Zhuimport android.view.KeyEvent;
486e29e12add362546784126119f26f04fc760f021RoboErik
4911798b011c962b602217b479130d413f3b30f19aLiejun Taoimport com.android.bluetooth.R;
50c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.bluetooth.btservice.AdapterService;
51c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.bluetooth.btservice.ProfileService;
52aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport com.android.bluetooth.Utils;
53c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.IState;
54c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.State;
55c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.StateMachine;
566e29e12add362546784126119f26f04fc760f021RoboErik
57c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.lang.ref.WeakReference;
58c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.ArrayList;
5911798b011c962b602217b479130d413f3b30f19aLiejun Taoimport java.util.HashMap;
60c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.List;
61c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.Set;
62c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu/**
63c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * support Bluetooth AVRCP profile.
64c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * support metadata, play status and event notification
65c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu */
66066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodpublic final class Avrcp {
678e0d927632cce4ad53df85fb7627b915c5fbd64bRoboErik    private static final boolean DEBUG = false;
68c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private static final String TAG = "Avrcp";
6911798b011c962b602217b479130d413f3b30f19aLiejun Tao    private static final String ABSOLUTE_VOLUME_BLACKLIST = "absolute_volume_blacklist";
70c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
71c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Context mContext;
72c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private final AudioManager mAudioManager;
73c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private AvrcpMessageHandler mHandler;
742fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private MediaSessionManager mMediaSessionManager;
752fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private MediaSessionChangeListener mSessionChangeListener;
762fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private MediaController mMediaController;
772fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private MediaControllerListener mMediaControllerCb;
78c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Metadata mMetadata;
79c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mTransportControlFlags;
802fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private PlaybackState mCurrentPlayState;
81c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mPlayStatusChangedNT;
82c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mTrackChangedNT;
83c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private long mTrackNumber;
84aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mCurrentPosMs;
85aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPlayStartTimeMs;
86aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mSongLengthMs;
87aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPlaybackIntervalMs;
88aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private int mPlayPosChangedNT;
89aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mNextPosMs;
90aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPrevPosMs;
91ace834feb02adabd61f628c4471147aea02d939cJohn Du    private long mSkipStartTime;
9217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mFeatures;
9311798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mRemoteVolume;
9411798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLastRemoteVolume;
9511798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mInitialRemoteVolume;
9611798b011c962b602217b479130d413f3b30f19aLiejun Tao
9711798b011c962b602217b479130d413f3b30f19aLiejun Tao    /* Local volume in audio index 0-15 */
9811798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLocalVolume;
9911798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mLastLocalVolume;
10011798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int mAbsVolThreshold;
10111798b011c962b602217b479130d413f3b30f19aLiejun Tao
10211798b011c962b602217b479130d413f3b30f19aLiejun Tao    private String mAddress;
10311798b011c962b602217b479130d413f3b30f19aLiejun Tao    private HashMap<Integer, Integer> mVolumeMapping;
10411798b011c962b602217b479130d413f3b30f19aLiejun Tao
10517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mLastDirection;
1062e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private final int mVolumeStep;
1072e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private final int mAudioStreamMax;
10811798b011c962b602217b479130d413f3b30f19aLiejun Tao    private boolean mVolCmdAdjustInProgress;
10911798b011c962b602217b479130d413f3b30f19aLiejun Tao    private boolean mVolCmdSetInProgress;
11017675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mAbsVolRetryTimes;
11119e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu    private int mSkipAmount;
112ace834feb02adabd61f628c4471147aea02d939cJohn Du
11317675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* BTRC features */
11417675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_METADATA = 0x01;
11517675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02;
11617675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_BROWSE = 0x04;
11717675906064bb72fdcca75baa56cdf8bb8968d01John Du
11817675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* AVRC response codes, from avrc_defs */
11917675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_NOT_IMPL = 8;
12017675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_ACCEPT = 9;
12117675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_REJ = 10;
12217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_IN_TRANS = 11;
12317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_IMPL_STBL = 12;
12417675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_CHANGED = 13;
12517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_INTERIM = 15;
12617675906064bb72fdcca75baa56cdf8bb8968d01John Du
12717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_GET_RC_FEATURES = 1;
12817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_GET_PLAY_STATUS = 2;
12917675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_GET_ELEM_ATTRS = 3;
13017675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_REGISTER_NOTIFICATION = 4;
13117675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_PLAY_INTERVAL_TIMEOUT = 5;
13217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_VOLUME_CHANGED = 6;
13317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_ADJUST_VOLUME = 7;
13417675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_SET_ABSOLUTE_VOLUME = 8;
13517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_ABS_VOL_TIMEOUT = 9;
13617675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_FAST_FORWARD = 10;
13717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_REWIND = 11;
13819e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu    private static final int MESSAGE_CHANGE_PLAY_POS = 12;
139188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    private static final int MESSAGE_SET_A2DP_AUDIO_STATE = 13;
140c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
141ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int BUTTON_TIMEOUT_TIME = 2000;
142ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int BASE_SKIP_AMOUNT = 2000;
143ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int KEY_STATE_PRESS = 1;
144ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int KEY_STATE_RELEASE = 0;
145ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int SKIP_PERIOD = 400;
146ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int SKIP_DOUBLE_INTERVAL = 3000;
14719e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu    private static final long MAX_MULTIPLIER_VALUE = 128L;
14817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int CMD_TIMEOUT_DELAY = 2000;
14917675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MAX_ERROR_RETRY_TIMES = 3;
15017675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRCP_MAX_VOL = 127;
15117675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRCP_BASE_VOLUME_STEP = 1;
152ace834feb02adabd61f628c4471147aea02d939cJohn Du
153c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    static {
154c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        classInitNative();
155c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
156c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
157c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Avrcp(Context context) {
158c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mMetadata = new Metadata();
1592fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        mCurrentPlayState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build();
160c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
161c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
16279d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu        mTrackNumber = -1L;
1632fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        mCurrentPosMs = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
164aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        mPlayStartTimeMs = -1L;
165aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        mSongLengthMs = 0L;
166aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        mPlaybackIntervalMs = 0L;
167aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
16817675906064bb72fdcca75baa56cdf8bb8968d01John Du        mFeatures = 0;
16911798b011c962b602217b479130d413f3b30f19aLiejun Tao        mRemoteVolume = -1;
17011798b011c962b602217b479130d413f3b30f19aLiejun Tao        mInitialRemoteVolume = -1;
17111798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLastRemoteVolume = -1;
17217675906064bb72fdcca75baa56cdf8bb8968d01John Du        mLastDirection = 0;
17311798b011c962b602217b479130d413f3b30f19aLiejun Tao        mVolCmdAdjustInProgress = false;
17411798b011c962b602217b479130d413f3b30f19aLiejun Tao        mVolCmdSetInProgress = false;
17517675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAbsVolRetryTimes = 0;
17611798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLocalVolume = -1;
17711798b011c962b602217b479130d413f3b30f19aLiejun Tao        mLastLocalVolume = -1;
17811798b011c962b602217b479130d413f3b30f19aLiejun Tao        mAbsVolThreshold = 0;
17911798b011c962b602217b479130d413f3b30f19aLiejun Tao        mVolumeMapping = new HashMap<Integer, Integer>();
180c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
181c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mContext = context;
182c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
183c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        initNative();
184c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1852fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        mMediaSessionManager = (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
186c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
1872e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mAudioStreamMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
1882e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mVolumeStep = Math.max(AVRCP_BASE_VOLUME_STEP, AVRCP_MAX_VOL/mAudioStreamMax);
18911798b011c962b602217b479130d413f3b30f19aLiejun Tao        Resources resources = context.getResources();
19011798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (resources != null) {
19111798b011c962b602217b479130d413f3b30f19aLiejun Tao            mAbsVolThreshold = resources.getInteger(R.integer.a2dp_absolute_volume_initial_threshold);
19211798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
193c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
194c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
195c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void start() {
196c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler");
197c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        thread.start();
198c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Looper looper = thread.getLooper();
199c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler = new AvrcpMessageHandler(looper);
2002fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen
2012fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        mSessionChangeListener = new MediaSessionChangeListener();
2022fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        mMediaSessionManager.addOnActiveSessionsChangedListener(mSessionChangeListener, null, mHandler);
2032fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        List<MediaController> sessions = mMediaSessionManager.getActiveSessions(null);
2042fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        mMediaControllerCb = new MediaControllerListener();
2052fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        if (sessions.size() > 0) {
2062fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            updateCurrentMediaController(sessions.get(0));
2072fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        }
208c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
209c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
210066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    public static Avrcp make(Context context) {
211c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (DEBUG) Log.v(TAG, "make");
212c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Avrcp ar = new Avrcp(context);
213c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ar.start();
214c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return ar;
215c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
216c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
217c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    public void doQuit() {
218c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.removeCallbacksAndMessages(null);
219c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Looper looper = mHandler.getLooper();
220c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (looper != null) {
221c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            looper.quit();
222c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
2232fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        mMediaSessionManager.removeOnActiveSessionsChangedListener(mSessionChangeListener);
224c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
225c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
226c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    public void cleanup() {
227c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        cleanupNative();
22811798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (mVolumeMapping != null)
22911798b011c962b602217b479130d413f3b30f19aLiejun Tao            mVolumeMapping.clear();
230c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
231c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
2322fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private class MediaControllerListener extends MediaController.Callback {
2332fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        @Override
2342fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        public void onMetadataChanged(MediaMetadata metadata) {
2352fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            Log.v(TAG, "MediaController metadata changed");
2362fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            updateMetadata(metadata);
237c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
238c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
239bc10e7d58aa55da25c18d8056a0254a2b736146aZhihai Xu        @Override
2402fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        public void onPlaybackStateChanged(PlaybackState state) {
2412fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            Log.v(TAG, "MediaController playback changed: " + state.toString());
2422fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            updatePlayPauseState(state);
243c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
244c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
245c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
2462fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        public void onSessionDestroyed() {
2472fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            Log.v(TAG, "MediaController session destroyed");
248c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
2492fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    }
250c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
2512fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private class MediaSessionChangeListener implements MediaSessionManager.OnActiveSessionsChangedListener {
2522fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        public MediaSessionChangeListener() {
253c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
254c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
255c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
2562fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        public void onActiveSessionsChanged(List<MediaController> controllers) {
2572fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            Log.v(TAG, "Active sessions changed, " + controllers.size() + " sessions");
2582fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            if (controllers.size() > 0) {
2592fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                updateCurrentMediaController(controllers.get(0));
260c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
261c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
2622fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    }
263c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
2642fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private void updateCurrentMediaController(MediaController controller) {
2652fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        Log.v(TAG, "Updating media controller to " + controller);
2662fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        if (mMediaController != null) {
2672fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            mMediaController.unregisterCallback(mMediaControllerCb);
2682fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        }
2692fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        mMediaController = controller;
2702fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        if (mMediaController == null) {
2712fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            updateMetadata(null);
2722fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            updatePlayPauseState(null);
2732fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            return;
274c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
2752fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        mMediaController.registerCallback(mMediaControllerCb, mHandler);
2762fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        updateMetadata(mMediaController.getMetadata());
2772fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        updatePlayPauseState(mMediaController.getPlaybackState());
278c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
279c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
280c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    /** Handles Avrcp messages. */
281c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private final class AvrcpMessageHandler extends Handler {
282c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        private AvrcpMessageHandler(Looper looper) {
283c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            super(looper);
284c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
285c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
286c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
287c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public void handleMessage(Message msg) {
288c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            switch (msg.what) {
28917675906064bb72fdcca75baa56cdf8bb8968d01John Du            case MESSAGE_GET_RC_FEATURES:
29017675906064bb72fdcca75baa56cdf8bb8968d01John Du                String address = (String) msg.obj;
29117675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (DEBUG) Log.v(TAG, "MESSAGE_GET_RC_FEATURES: address="+address+
29217675906064bb72fdcca75baa56cdf8bb8968d01John Du                                                             ", features="+msg.arg1);
29317675906064bb72fdcca75baa56cdf8bb8968d01John Du                mFeatures = msg.arg1;
29411798b011c962b602217b479130d413f3b30f19aLiejun Tao                mFeatures = modifyRcFeatureFromBlacklist(mFeatures, address);
29517675906064bb72fdcca75baa56cdf8bb8968d01John Du                mAudioManager.avrcpSupportsAbsoluteVolume(address, isAbsoluteVolumeSupported());
29611798b011c962b602217b479130d413f3b30f19aLiejun Tao                mLastLocalVolume = -1;
29711798b011c962b602217b479130d413f3b30f19aLiejun Tao                mRemoteVolume = -1;
29811798b011c962b602217b479130d413f3b30f19aLiejun Tao                mLocalVolume = -1;
29911798b011c962b602217b479130d413f3b30f19aLiejun Tao                mInitialRemoteVolume = -1;
30011798b011c962b602217b479130d413f3b30f19aLiejun Tao                mAddress = address;
30111798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mVolumeMapping != null)
30211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolumeMapping.clear();
30317675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
30417675906064bb72fdcca75baa56cdf8bb8968d01John Du
305c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MESSAGE_GET_PLAY_STATUS:
306c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                if (DEBUG) Log.v(TAG, "MESSAGE_GET_PLAY_STATUS");
307aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                getPlayStatusRspNative(convertPlayStateToPlayStatus(mCurrentPlayState),
308aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                                       (int)mSongLengthMs, (int)getPlayPosition());
309c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
310c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
311c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MESSAGE_GET_ELEM_ATTRS:
312c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                String[] textArray;
313c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                int[] attrIds;
314c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                byte numAttr = (byte) msg.arg1;
315c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                ArrayList<Integer> attrList = (ArrayList<Integer>) msg.obj;
31665e7943d098113c5aa56e9822b68f0c51c6dbe36Marie Janssen                Log.v(TAG, "MESSAGE_GET_ELEM_ATTRS:numAttr=" + numAttr);
317c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                attrIds = new int[numAttr];
318c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                textArray = new String[numAttr];
319c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                for (int i = 0; i < numAttr; ++i) {
320c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                    attrIds[i] = attrList.get(i).intValue();
321c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                    textArray[i] = getAttributeString(attrIds[i]);
322c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                }
323c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                getElementAttrRspNative(numAttr, attrIds, textArray);
324c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
32565e7943d098113c5aa56e9822b68f0c51c6dbe36Marie Janssen
326c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MESSAGE_REGISTER_NOTIFICATION:
327c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                if (DEBUG) Log.v(TAG, "MESSAGE_REGISTER_NOTIFICATION:event=" + msg.arg1 +
328c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                      " param=" + msg.arg2);
329c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                processRegisterNotification(msg.arg1, msg.arg2);
330c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
331c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
332aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            case MESSAGE_PLAY_INTERVAL_TIMEOUT:
333aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                if (DEBUG) Log.v(TAG, "MESSAGE_PLAY_INTERVAL_TIMEOUT");
334aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
335aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)getPlayPosition());
336aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                break;
337aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
33817675906064bb72fdcca75baa56cdf8bb8968d01John Du            case MESSAGE_VOLUME_CHANGED:
33911798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (!isAbsoluteVolumeSupported()) {
34011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.v(TAG, "ignore MESSAGE_VOLUME_CHANGED");
34111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
34211798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
34311798b011c962b602217b479130d413f3b30f19aLiejun Tao
3445c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                if (DEBUG) Log.v(TAG, "MESSAGE_VOLUME_CHANGED: volume=" + ((byte)msg.arg1 & 0x7f)
3455c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                                                        + " ctype=" + msg.arg2);
34617675906064bb72fdcca75baa56cdf8bb8968d01John Du
34711798b011c962b602217b479130d413f3b30f19aLiejun Tao
34811798b011c962b602217b479130d413f3b30f19aLiejun Tao                boolean volAdj = false;
34917675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (msg.arg2 == AVRC_RSP_ACCEPT || msg.arg2 == AVRC_RSP_REJ) {
35011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mVolCmdAdjustInProgress == false && mVolCmdSetInProgress == false) {
35117675906064bb72fdcca75baa56cdf8bb8968d01John Du                        Log.e(TAG, "Unsolicited response, ignored");
35217675906064bb72fdcca75baa56cdf8bb8968d01John Du                        break;
35317675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
35417675906064bb72fdcca75baa56cdf8bb8968d01John Du                    removeMessages(MESSAGE_ABS_VOL_TIMEOUT);
35511798b011c962b602217b479130d413f3b30f19aLiejun Tao
35611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    volAdj = mVolCmdAdjustInProgress;
35711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolCmdAdjustInProgress = false;
35811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolCmdSetInProgress = false;
35917675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes = 0;
36017675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
36111798b011c962b602217b479130d413f3b30f19aLiejun Tao
36211798b011c962b602217b479130d413f3b30f19aLiejun Tao                byte absVol = (byte)((byte)msg.arg1 & 0x7f); // discard MSB as it is RFD
36311798b011c962b602217b479130d413f3b30f19aLiejun Tao                // convert remote volume to local volume
36411798b011c962b602217b479130d413f3b30f19aLiejun Tao                int volIndex = convertToAudioStreamVolume(absVol);
36511798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mInitialRemoteVolume == -1) {
36611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mInitialRemoteVolume = absVol;
36711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mAbsVolThreshold > 0 && mAbsVolThreshold < mAudioStreamMax && volIndex > mAbsVolThreshold) {
36811798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.v(TAG, "remote inital volume too high " + volIndex + ">" + mAbsVolThreshold);
36911798b011c962b602217b479130d413f3b30f19aLiejun Tao                        Message msg1 = mHandler.obtainMessage(MESSAGE_SET_ABSOLUTE_VOLUME, mAbsVolThreshold , 0);
37011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mHandler.sendMessage(msg1);
37111798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mRemoteVolume = absVol;
37211798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLocalVolume = volIndex;
37311798b011c962b602217b479130d413f3b30f19aLiejun Tao                        break;
37411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
37511798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
37611798b011c962b602217b479130d413f3b30f19aLiejun Tao
3772fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                if (mLocalVolume != volIndex && (msg.arg2 == AVRC_RSP_ACCEPT ||
3782fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                                                 msg.arg2 == AVRC_RSP_CHANGED ||
3792fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                                                 msg.arg2 == AVRC_RSP_INTERIM)) {
38011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    /* If the volume has successfully changed */
38111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mLocalVolume = volIndex;
38211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mLastLocalVolume != -1 && msg.arg2 == AVRC_RSP_ACCEPT) {
38311798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (mLastLocalVolume != volIndex) {
38411798b011c962b602217b479130d413f3b30f19aLiejun Tao                            /* remote volume changed more than requested due to
38511798b011c962b602217b479130d413f3b30f19aLiejun Tao                             * local and remote has different volume steps */
38611798b011c962b602217b479130d413f3b30f19aLiejun Tao                            if (DEBUG) Log.d(TAG, "Remote returned volume does not match desired volume "
38711798b011c962b602217b479130d413f3b30f19aLiejun Tao                                + mLastLocalVolume + " vs "
38811798b011c962b602217b479130d413f3b30f19aLiejun Tao                                + volIndex);
38911798b011c962b602217b479130d413f3b30f19aLiejun Tao                            mLastLocalVolume = mLocalVolume;
39011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        }
39111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
39211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    // remember the remote volume value, as it's the one supported by remote
39311798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (volAdj) {
39411798b011c962b602217b479130d413f3b30f19aLiejun Tao                        synchronized (mVolumeMapping) {
39511798b011c962b602217b479130d413f3b30f19aLiejun Tao                            mVolumeMapping.put(volIndex, (int)absVol);
39611798b011c962b602217b479130d413f3b30f19aLiejun Tao                            if (DEBUG) Log.v(TAG, "remember volume mapping " +volIndex+ "-"+absVol);
39711798b011c962b602217b479130d413f3b30f19aLiejun Tao                        }
39811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
39911798b011c962b602217b479130d413f3b30f19aLiejun Tao
40011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    notifyVolumeChanged(mLocalVolume);
40111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mRemoteVolume = absVol;
4025c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                    long pecentVolChanged = ((long)absVol * 100) / 0x7f;
4035c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                    Log.e(TAG, "percent volume changed: " + pecentVolChanged + "%");
40417675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else if (msg.arg2 == AVRC_RSP_REJ) {
40517675906064bb72fdcca75baa56cdf8bb8968d01John Du                    Log.e(TAG, "setAbsoluteVolume call rejected");
40611798b011c962b602217b479130d413f3b30f19aLiejun Tao                } else if (volAdj && mLastRemoteVolume > 0 && mLastRemoteVolume < AVRCP_MAX_VOL &&
4072fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                        mLocalVolume == volIndex &&
4082fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                        (msg.arg2 == AVRC_RSP_ACCEPT )) {
40911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    /* oops, the volume is still same, remote does not like the value
41011798b011c962b602217b479130d413f3b30f19aLiejun Tao                     * retry a volume one step up/down */
41111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.d(TAG, "Remote device didn't tune volume, let's try one more step.");
41211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    int retry_volume = Math.min(AVRCP_MAX_VOL,
41311798b011c962b602217b479130d413f3b30f19aLiejun Tao                            Math.max(0, mLastRemoteVolume + mLastDirection));
41411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (setVolumeNative(retry_volume)) {
41511798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLastRemoteVolume = retry_volume;
41611798b011c962b602217b479130d413f3b30f19aLiejun Tao                        sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT),
41711798b011c962b602217b479130d413f3b30f19aLiejun Tao                                           CMD_TIMEOUT_DELAY);
41811798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mVolCmdAdjustInProgress = true;
41911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
42017675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
42117675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
42217675906064bb72fdcca75baa56cdf8bb8968d01John Du
42317675906064bb72fdcca75baa56cdf8bb8968d01John Du            case MESSAGE_ADJUST_VOLUME:
42411798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (!isAbsoluteVolumeSupported()) {
42511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.v(TAG, "ignore MESSAGE_ADJUST_VOLUME");
42611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
42711798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
42811798b011c962b602217b479130d413f3b30f19aLiejun Tao
42917675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (DEBUG) Log.d(TAG, "MESSAGE_ADJUST_VOLUME: direction=" + msg.arg1);
43011798b011c962b602217b479130d413f3b30f19aLiejun Tao
43111798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mVolCmdAdjustInProgress || mVolCmdSetInProgress) {
43217675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
43317675906064bb72fdcca75baa56cdf8bb8968d01John Du                    break;
43417675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
43511798b011c962b602217b479130d413f3b30f19aLiejun Tao
43611798b011c962b602217b479130d413f3b30f19aLiejun Tao                // Remote device didn't set initial volume. Let's black list it
43711798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mInitialRemoteVolume == -1) {
43811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    Log.d(TAG, "remote " + mAddress + " never tell us initial volume, black list it.");
43911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    blackListCurrentDevice();
44011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
44111798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
44211798b011c962b602217b479130d413f3b30f19aLiejun Tao
44317675906064bb72fdcca75baa56cdf8bb8968d01John Du                // Wait on verification on volume from device, before changing the volume.
44411798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mRemoteVolume != -1 && (msg.arg1 == -1 || msg.arg1 == 1)) {
44511798b011c962b602217b479130d413f3b30f19aLiejun Tao                    int setVol = -1;
44611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    int targetVolIndex = -1;
44711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mLocalVolume == 0 && msg.arg1 == -1) {
44811798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.w(TAG, "No need to Vol down from 0.");
44911798b011c962b602217b479130d413f3b30f19aLiejun Tao                        break;
45011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
45111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (mLocalVolume == mAudioStreamMax && msg.arg1 == 1) {
45211798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.w(TAG, "No need to Vol up from max.");
45311798b011c962b602217b479130d413f3b30f19aLiejun Tao                        break;
45411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
45511798b011c962b602217b479130d413f3b30f19aLiejun Tao
45611798b011c962b602217b479130d413f3b30f19aLiejun Tao                    targetVolIndex = mLocalVolume + msg.arg1;
45711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.d(TAG, "Adjusting volume to  " + targetVolIndex);
45811798b011c962b602217b479130d413f3b30f19aLiejun Tao
45911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    Integer i;
46011798b011c962b602217b479130d413f3b30f19aLiejun Tao                    synchronized (mVolumeMapping) {
46111798b011c962b602217b479130d413f3b30f19aLiejun Tao                        i = mVolumeMapping.get(targetVolIndex);
46211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
46311798b011c962b602217b479130d413f3b30f19aLiejun Tao
46411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (i != null) {
46511798b011c962b602217b479130d413f3b30f19aLiejun Tao                        /* if we already know this volume mapping, use it */
46611798b011c962b602217b479130d413f3b30f19aLiejun Tao                        setVol = i.byteValue();
46711798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (setVol == mRemoteVolume) {
46811798b011c962b602217b479130d413f3b30f19aLiejun Tao                            if (DEBUG) Log.d(TAG, "got same volume from mapping for " + targetVolIndex + ", ignore.");
46911798b011c962b602217b479130d413f3b30f19aLiejun Tao                            setVol = -1;
47011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        }
47111798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.d(TAG, "set volume from mapping " + targetVolIndex + "-" + setVol);
47211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
47311798b011c962b602217b479130d413f3b30f19aLiejun Tao
47411798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (setVol == -1) {
47511798b011c962b602217b479130d413f3b30f19aLiejun Tao                        /* otherwise use phone steps */
47611798b011c962b602217b479130d413f3b30f19aLiejun Tao                        setVol = Math.min(AVRCP_MAX_VOL,
47711798b011c962b602217b479130d413f3b30f19aLiejun Tao                                 convertToAvrcpVolume(Math.max(0, targetVolIndex)));
47811798b011c962b602217b479130d413f3b30f19aLiejun Tao                        if (DEBUG) Log.d(TAG, "set volume from local volume "+ targetVolIndex+"-"+ setVol);
47911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    }
48011798b011c962b602217b479130d413f3b30f19aLiejun Tao
48117675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (setVolumeNative(setVol)) {
48217675906064bb72fdcca75baa56cdf8bb8968d01John Du                        sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT),
48317675906064bb72fdcca75baa56cdf8bb8968d01John Du                                           CMD_TIMEOUT_DELAY);
48411798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mVolCmdAdjustInProgress = true;
48517675906064bb72fdcca75baa56cdf8bb8968d01John Du                        mLastDirection = msg.arg1;
48611798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLastRemoteVolume = setVol;
48711798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mLastLocalVolume = targetVolIndex;
48811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    } else {
48911798b011c962b602217b479130d413f3b30f19aLiejun Tao                         if (DEBUG) Log.d(TAG, "setVolumeNative failed");
49017675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
49117675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else {
49217675906064bb72fdcca75baa56cdf8bb8968d01John Du                    Log.e(TAG, "Unknown direction in MESSAGE_ADJUST_VOLUME");
49317675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
49417675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
49517675906064bb72fdcca75baa56cdf8bb8968d01John Du
49617675906064bb72fdcca75baa56cdf8bb8968d01John Du            case MESSAGE_SET_ABSOLUTE_VOLUME:
49711798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (!isAbsoluteVolumeSupported()) {
49811798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.v(TAG, "ignore MESSAGE_SET_ABSOLUTE_VOLUME");
49911798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
50011798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
50111798b011c962b602217b479130d413f3b30f19aLiejun Tao
50217675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (DEBUG) Log.v(TAG, "MESSAGE_SET_ABSOLUTE_VOLUME");
50311798b011c962b602217b479130d413f3b30f19aLiejun Tao
50411798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mVolCmdSetInProgress || mVolCmdAdjustInProgress) {
50517675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
50617675906064bb72fdcca75baa56cdf8bb8968d01John Du                    break;
50717675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
50811798b011c962b602217b479130d413f3b30f19aLiejun Tao
50911798b011c962b602217b479130d413f3b30f19aLiejun Tao                // Remote device didn't set initial volume. Let's black list it
51011798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (mInitialRemoteVolume == -1) {
51111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (DEBUG) Log.d(TAG, "remote " + mAddress + " never tell us initial volume, black list it.");
51211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    blackListCurrentDevice();
51311798b011c962b602217b479130d413f3b30f19aLiejun Tao                    break;
51411798b011c962b602217b479130d413f3b30f19aLiejun Tao                }
51511798b011c962b602217b479130d413f3b30f19aLiejun Tao
51611798b011c962b602217b479130d413f3b30f19aLiejun Tao                int avrcpVolume = convertToAvrcpVolume(msg.arg1);
51711798b011c962b602217b479130d413f3b30f19aLiejun Tao                avrcpVolume = Math.min(AVRCP_MAX_VOL, Math.max(0, avrcpVolume));
51811798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (DEBUG) Log.d(TAG, "Setting volume to " + msg.arg1+"-"+avrcpVolume);
51911798b011c962b602217b479130d413f3b30f19aLiejun Tao                if (setVolumeNative(avrcpVolume)) {
52017675906064bb72fdcca75baa56cdf8bb8968d01John Du                    sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
52111798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mVolCmdSetInProgress = true;
52211798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mLastRemoteVolume = avrcpVolume;
52311798b011c962b602217b479130d413f3b30f19aLiejun Tao                    mLastLocalVolume = msg.arg1;
52411798b011c962b602217b479130d413f3b30f19aLiejun Tao                } else {
52511798b011c962b602217b479130d413f3b30f19aLiejun Tao                     if (DEBUG) Log.d(TAG, "setVolumeNative failed");
52617675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
52717675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
52817675906064bb72fdcca75baa56cdf8bb8968d01John Du
52917675906064bb72fdcca75baa56cdf8bb8968d01John Du            case MESSAGE_ABS_VOL_TIMEOUT:
53017675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (DEBUG) Log.v(TAG, "MESSAGE_ABS_VOL_TIMEOUT: Volume change cmd timed out.");
53111798b011c962b602217b479130d413f3b30f19aLiejun Tao                mVolCmdAdjustInProgress = false;
53211798b011c962b602217b479130d413f3b30f19aLiejun Tao                mVolCmdSetInProgress = false;
53317675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (mAbsVolRetryTimes >= MAX_ERROR_RETRY_TIMES) {
53417675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes = 0;
53517675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else {
53617675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes += 1;
53711798b011c962b602217b479130d413f3b30f19aLiejun Tao                    if (setVolumeNative(mLastRemoteVolume)) {
53817675906064bb72fdcca75baa56cdf8bb8968d01John Du                        sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT),
53917675906064bb72fdcca75baa56cdf8bb8968d01John Du                                           CMD_TIMEOUT_DELAY);
54011798b011c962b602217b479130d413f3b30f19aLiejun Tao                        mVolCmdSetInProgress = true;
54117675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
54217675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
54317675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
54417675906064bb72fdcca75baa56cdf8bb8968d01John Du
545ace834feb02adabd61f628c4471147aea02d939cJohn Du            case MESSAGE_FAST_FORWARD:
546ace834feb02adabd61f628c4471147aea02d939cJohn Du            case MESSAGE_REWIND:
5472fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                if (msg.what == MESSAGE_FAST_FORWARD) {
5482fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                    if ((mCurrentPlayState.getActions() &
5492fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                                PlaybackState.ACTION_FAST_FORWARD) != 0) {
5502fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                        int keyState = msg.arg1 == KEY_STATE_PRESS ?
5512fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                                KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
5522fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                        KeyEvent keyEvent =
5532fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                                new KeyEvent(keyState, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
5542fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                        mMediaController.dispatchMediaButtonEvent(keyEvent);
5552fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                        break;
556881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    }
5572fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                } else if ((mCurrentPlayState.getActions() &
5582fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                            PlaybackState.ACTION_REWIND) != 0) {
559881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    int keyState = msg.arg1 == KEY_STATE_PRESS ?
5602fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                            KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
561881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    KeyEvent keyEvent =
5622fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                            new KeyEvent(keyState, KeyEvent.KEYCODE_MEDIA_REWIND);
5632fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                    mMediaController.dispatchMediaButtonEvent(keyEvent);
564881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    break;
565881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                }
566881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu
56719e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                int skipAmount;
568ace834feb02adabd61f628c4471147aea02d939cJohn Du                if (msg.what == MESSAGE_FAST_FORWARD) {
569ace834feb02adabd61f628c4471147aea02d939cJohn Du                    if (DEBUG) Log.v(TAG, "MESSAGE_FAST_FORWARD");
570881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    removeMessages(MESSAGE_FAST_FORWARD);
571ace834feb02adabd61f628c4471147aea02d939cJohn Du                    skipAmount = BASE_SKIP_AMOUNT;
572ace834feb02adabd61f628c4471147aea02d939cJohn Du                } else {
573ace834feb02adabd61f628c4471147aea02d939cJohn Du                    if (DEBUG) Log.v(TAG, "MESSAGE_REWIND");
574881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    removeMessages(MESSAGE_REWIND);
575ace834feb02adabd61f628c4471147aea02d939cJohn Du                    skipAmount = -BASE_SKIP_AMOUNT;
576ace834feb02adabd61f628c4471147aea02d939cJohn Du                }
577ace834feb02adabd61f628c4471147aea02d939cJohn Du
57819e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                if (hasMessages(MESSAGE_CHANGE_PLAY_POS) &&
57919e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                        (skipAmount != mSkipAmount)) {
58019e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    Log.w(TAG, "missing release button event:" + mSkipAmount);
58119e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                }
58219e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu
58319e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                if ((!hasMessages(MESSAGE_CHANGE_PLAY_POS)) ||
58419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                        (skipAmount != mSkipAmount)) {
58519e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    mSkipStartTime = SystemClock.elapsedRealtime();
58619e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                }
58719e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu
58819e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                removeMessages(MESSAGE_CHANGE_PLAY_POS);
589ace834feb02adabd61f628c4471147aea02d939cJohn Du                if (msg.arg1 == KEY_STATE_PRESS) {
59019e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    mSkipAmount = skipAmount;
59119e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    changePositionBy(mSkipAmount * getSkipMultiplier());
59219e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS);
59319e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    posMsg.arg1 = 1;
59419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    sendMessageDelayed(posMsg, SKIP_PERIOD);
595ace834feb02adabd61f628c4471147aea02d939cJohn Du                }
596881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu
597ace834feb02adabd61f628c4471147aea02d939cJohn Du                break;
598ace834feb02adabd61f628c4471147aea02d939cJohn Du
59919e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu            case MESSAGE_CHANGE_PLAY_POS:
60019e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                if (DEBUG) Log.v(TAG, "MESSAGE_CHANGE_PLAY_POS:" + msg.arg1);
60119e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                changePositionBy(mSkipAmount * getSkipMultiplier());
60219e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                if (msg.arg1 * SKIP_PERIOD < BUTTON_TIMEOUT_TIME) {
60319e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS);
60419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    posMsg.arg1 = msg.arg1 + 1;
60519e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    sendMessageDelayed(posMsg, SKIP_PERIOD);
606ace834feb02adabd61f628c4471147aea02d939cJohn Du                }
607ace834feb02adabd61f628c4471147aea02d939cJohn Du                break;
608188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
609188f205b5f093850d4cc627917a21204be36c56aZhihai Xu            case MESSAGE_SET_A2DP_AUDIO_STATE:
610188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                if (DEBUG) Log.v(TAG, "MESSAGE_SET_A2DP_AUDIO_STATE:" + msg.arg1);
611188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                updateA2dpAudioState(msg.arg1);
612188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                break;
613c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
614c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
615c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
616c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
617188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    private void updateA2dpAudioState(int state) {
618188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        boolean isPlaying = (state == BluetoothA2dp.STATE_PLAYING);
619188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        if (isPlaying != isPlayingState(mCurrentPlayState)) {
62022bad7047263a6924423d12718738fdcc7b0352cRavi Nagarajan            /* if a2dp is streaming, check to make sure music is active */
6212fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            if (isPlaying && !mAudioManager.isMusicActive())
62222bad7047263a6924423d12718738fdcc7b0352cRavi Nagarajan                return;
6232fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            PlaybackState.Builder builder = new PlaybackState.Builder();
6242fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            if (isPlaying) {
6252fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                builder.setState(PlaybackState.STATE_PLAYING,
6262fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                                 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f);
6272fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            } else {
6282fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                builder.setState(PlaybackState.STATE_PAUSED,
6292fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                                 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f);
6302fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            }
6312fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            updatePlayPauseState(builder.build());
632188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        }
633188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
634188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
6352fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private void updatePlayPauseState(PlaybackState state) {
636c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (DEBUG) Log.v(TAG,
6372fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                "updatePlayPauseState: old=" + mCurrentPlayState + ", state=" + state);
6382fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        if (state == null) {
6392fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen          state = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE,
6402fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                         PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build();
6412fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        }
6422fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        boolean oldPosValid = (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN);
643c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState);
644c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        int newPlayStatus = convertPlayStateToPlayStatus(state);
645f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu
6462fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        if ((mCurrentPlayState.getState() == PlaybackState.STATE_PLAYING) &&
6472fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                (mCurrentPlayState != state) && oldPosValid) {
648f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu            mCurrentPosMs = getPlayPosition();
649f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        }
650f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu
6512fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        if (state.getState() == PlaybackState.STATE_NONE ||
6522fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                state.getState() == PlaybackState.STATE_ERROR) {
6532fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            mCurrentPosMs = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
6542fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        } else {
6552fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            mCurrentPosMs = state.getPosition();
656f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        }
6572fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen
6582fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        if ((state.getState() == PlaybackState.STATE_PLAYING) &&
6592fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                (mCurrentPlayState.getState() != PlaybackState.STATE_PLAYING)) {
660aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            mPlayStartTimeMs = SystemClock.elapsedRealtime();
661aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        }
6622fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen
663aa6c1cb7f08a5d1fe2c878b587c62cf4dbb6ee8fZhihai Xu        mCurrentPlayState = state;
664aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
6652fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        boolean newPosValid = mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN;
666f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        long playPosition = getPlayPosition();
6672fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen
668aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
669aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        /* need send play position changed notification when play status is changed */
670aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) &&
6712fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                ((oldPlayStatus != newPlayStatus) || (oldPosValid != newPosValid) ||
6722fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                 (newPosValid && ((playPosition >= mNextPosMs) || (playPosition <= mPrevPosMs))))) {
673aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
674f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu            registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)playPosition);
675aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        }
676aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) && newPosValid &&
6772fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                (state.getState() == PlaybackState.STATE_PLAYING)) {
678aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
679f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu            mHandler.sendMessageDelayed(msg, mNextPosMs - playPosition);
680aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        }
681aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
682c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if ((mPlayStatusChangedNT == NOTIFICATION_TYPE_INTERIM) && (oldPlayStatus != newPlayStatus)) {
683c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
684c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, newPlayStatus);
685c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
686c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
687c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
688c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void updateTransportControls(int transportControlFlags) {
689c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mTransportControlFlags = transportControlFlags;
690c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
691c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
692c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    class Metadata {
693c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        private String artist;
694c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        private String trackTitle;
695c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        private String albumTitle;
696c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
697c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public Metadata() {
698c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            artist = null;
699c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            trackTitle = null;
700c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            albumTitle = null;
701c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
702c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
703c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public String toString() {
704c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + " albumTitle=" +
7052fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                    albumTitle + "]";
706c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
707c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
708c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
7092fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private void updateMetadata(MediaMetadata data) {
710c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        String oldMetadata = mMetadata.toString();
7112fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        if (data == null) {
7122fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            mMetadata = new Metadata();
7132fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            mSongLengthMs = 0L;
7142fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        } else {
7152fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            mMetadata.artist = data.getString(MediaMetadata.METADATA_KEY_ARTIST);
7162fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            mMetadata.trackTitle = data.getString(MediaMetadata.METADATA_KEY_TITLE);
7172fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            mMetadata.albumTitle = data.getString(MediaMetadata.METADATA_KEY_ALBUM);
7182fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            mSongLengthMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION);
7192fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        }
720c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (!oldMetadata.equals(mMetadata.toString())) {
72165e7943d098113c5aa56e9822b68f0c51c6dbe36Marie Janssen            Log.v(TAG, "Metadata Changed to " + mMetadata.toString());
722c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            mTrackNumber++;
723c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            if (mTrackChangedNT == NOTIFICATION_TYPE_INTERIM) {
724c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
725c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                sendTrackChangedRsp();
726c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
727aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
7282fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            if (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN &&
7292fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                isPlayingState(mCurrentPlayState)) {
7302fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                mPlayStartTimeMs = SystemClock.elapsedRealtime();
731aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            }
732aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            /* need send play position changed notification when track is changed */
733aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            if (mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) {
734aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
735aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                registerNotificationRspPlayPosNative(mPlayPosChangedNT,
7362fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                        (int)getPlayPosition());
737aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
738aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            }
73965e7943d098113c5aa56e9822b68f0c51c6dbe36Marie Janssen        } else {
7402fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            Log.v(TAG, "Metadata updated but no change!");
741c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
742aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
743c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
744c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
74517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private void getRcFeatures(byte[] address, int features) {
74617675906064bb72fdcca75baa56cdf8bb8968d01John Du        Message msg = mHandler.obtainMessage(MESSAGE_GET_RC_FEATURES, features, 0,
74717675906064bb72fdcca75baa56cdf8bb8968d01John Du                                             Utils.getAddressStringFromByte(address));
74817675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
74917675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
75017675906064bb72fdcca75baa56cdf8bb8968d01John Du
751c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void getPlayStatus() {
752c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Message msg = mHandler.obtainMessage(MESSAGE_GET_PLAY_STATUS);
753c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
754c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
755c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
756c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void getElementAttr(byte numAttr, int[] attrs) {
757c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        int i;
758c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ArrayList<Integer> attrList = new ArrayList<Integer>();
759c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        for (i = 0; i < numAttr; ++i) {
760c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            attrList.add(attrs[i]);
761c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
7626e29e12add362546784126119f26f04fc760f021RoboErik        Message msg = mHandler.obtainMessage(MESSAGE_GET_ELEM_ATTRS, numAttr, 0, attrList);
763c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
764c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
765c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
766c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void registerNotification(int eventId, int param) {
767c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_NOTIFICATION, eventId, param);
768c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
769c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
770c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
771c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void processRegisterNotification(int eventId, int param) {
772c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        switch (eventId) {
773c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case EVT_PLAY_STATUS_CHANGED:
774c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                mPlayStatusChangedNT = NOTIFICATION_TYPE_INTERIM;
775c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                registerNotificationRspPlayStatusNative(mPlayStatusChangedNT,
7762fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                        convertPlayStateToPlayStatus(mCurrentPlayState));
777c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
778c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
779c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case EVT_TRACK_CHANGED:
780c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                mTrackChangedNT = NOTIFICATION_TYPE_INTERIM;
781c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                sendTrackChangedRsp();
782c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
783c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
784aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            case EVT_PLAY_POS_CHANGED:
785aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                long songPosition = getPlayPosition();
786aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                mPlayPosChangedNT = NOTIFICATION_TYPE_INTERIM;
787aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                mPlaybackIntervalMs = (long)param * 1000L;
7882fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                if (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
789aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                    mNextPosMs = songPosition + mPlaybackIntervalMs;
790aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                    mPrevPosMs = songPosition - mPlaybackIntervalMs;
7912fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                    if (isPlayingState(mCurrentPlayState)) {
792aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                        Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
793aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                        mHandler.sendMessageDelayed(msg, mPlaybackIntervalMs);
794aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                    }
795aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                }
796aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)songPosition);
797aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                break;
798aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
799c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
800c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
801c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
802ace834feb02adabd61f628c4471147aea02d939cJohn Du    private void handlePassthroughCmd(int id, int keyState) {
803ace834feb02adabd61f628c4471147aea02d939cJohn Du        switch (id) {
804066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            case BluetoothAvrcp.PASSTHROUGH_ID_REWIND:
805ace834feb02adabd61f628c4471147aea02d939cJohn Du                rewind(keyState);
806ace834feb02adabd61f628c4471147aea02d939cJohn Du                break;
807066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            case BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR:
808ace834feb02adabd61f628c4471147aea02d939cJohn Du                fastForward(keyState);
809ace834feb02adabd61f628c4471147aea02d939cJohn Du                break;
810ace834feb02adabd61f628c4471147aea02d939cJohn Du        }
811ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
812ace834feb02adabd61f628c4471147aea02d939cJohn Du
813ace834feb02adabd61f628c4471147aea02d939cJohn Du    private void fastForward(int keyState) {
814ace834feb02adabd61f628c4471147aea02d939cJohn Du        Message msg = mHandler.obtainMessage(MESSAGE_FAST_FORWARD, keyState, 0);
815ace834feb02adabd61f628c4471147aea02d939cJohn Du        mHandler.sendMessage(msg);
816ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
817ace834feb02adabd61f628c4471147aea02d939cJohn Du
818ace834feb02adabd61f628c4471147aea02d939cJohn Du    private void rewind(int keyState) {
819ace834feb02adabd61f628c4471147aea02d939cJohn Du        Message msg = mHandler.obtainMessage(MESSAGE_REWIND, keyState, 0);
820ace834feb02adabd61f628c4471147aea02d939cJohn Du        mHandler.sendMessage(msg);
821ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
822ace834feb02adabd61f628c4471147aea02d939cJohn Du
823ace834feb02adabd61f628c4471147aea02d939cJohn Du    private void changePositionBy(long amount) {
824ace834feb02adabd61f628c4471147aea02d939cJohn Du        long currentPosMs = getPlayPosition();
825ace834feb02adabd61f628c4471147aea02d939cJohn Du        if (currentPosMs == -1L) return;
826ace834feb02adabd61f628c4471147aea02d939cJohn Du        long newPosMs = Math.max(0L, currentPosMs + amount);
8272fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        mMediaController.getTransportControls().seekTo(newPosMs);
828ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
829ace834feb02adabd61f628c4471147aea02d939cJohn Du
830ace834feb02adabd61f628c4471147aea02d939cJohn Du    private int getSkipMultiplier() {
831ace834feb02adabd61f628c4471147aea02d939cJohn Du        long currentTime = SystemClock.elapsedRealtime();
83219e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu        long multi = (long) Math.pow(2, (currentTime - mSkipStartTime)/SKIP_DOUBLE_INTERVAL);
83319e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu        return (int) Math.min(MAX_MULTIPLIER_VALUE, multi);
834ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
835ace834feb02adabd61f628c4471147aea02d939cJohn Du
836c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void sendTrackChangedRsp() {
837c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        byte[] track = new byte[TRACK_ID_SIZE];
838e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou
839e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou        /* If no track is currently selected, then return
840e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou           0xFFFFFFFFFFFFFFFF in the interim response */
841e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou        long trackNumberRsp = -1L;
842e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou
8432fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        if (isPlayingState(mCurrentPlayState)) {
844e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou            trackNumberRsp = mTrackNumber;
845e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou        }
846e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou
84779d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu        /* track is stored in big endian format */
848c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        for (int i = 0; i < TRACK_ID_SIZE; ++i) {
849e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou            track[i] = (byte) (trackNumberRsp >> (56 - 8 * i));
850c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
851c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        registerNotificationRspTrackChangeNative(mTrackChangedNT, track);
852c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
853c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
854aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long getPlayPosition() {
855aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        long songPosition = -1L;
8562fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        if (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
8572fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            if (mCurrentPlayState.getState() == PlaybackState.STATE_PLAYING) {
858aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                songPosition = SystemClock.elapsedRealtime() -
8592fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                        mPlayStartTimeMs + mCurrentPosMs;
860aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            } else {
861aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                songPosition = mCurrentPosMs;
862aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            }
863aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        }
864aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        if (DEBUG) Log.v(TAG, "position=" + songPosition);
865aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        return songPosition;
866aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    }
867aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
868c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private String getAttributeString(int attrId) {
869c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        String attrStr = null;
870c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        switch (attrId) {
871c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MEDIA_ATTR_TITLE:
872c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                attrStr = mMetadata.trackTitle;
873c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
874c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
875c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MEDIA_ATTR_ARTIST:
876c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                attrStr = mMetadata.artist;
877c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
878c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
879c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MEDIA_ATTR_ALBUM:
880c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                attrStr = mMetadata.albumTitle;
881c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
882c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
883aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            case MEDIA_ATTR_PLAYING_TIME:
884aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                if (mSongLengthMs != 0L) {
885aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                    attrStr = Long.toString(mSongLengthMs);
886aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                }
887aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                break;
888aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
889c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
890c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (attrStr == null) {
891c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            attrStr = new String();
892c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
89365e7943d098113c5aa56e9822b68f0c51c6dbe36Marie Janssen        Log.v(TAG, "getAttributeString:attrId=" + attrId + " str=" + attrStr);
894c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return attrStr;
895c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
896c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
8972fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private int convertPlayStateToPlayStatus(PlaybackState state) {
898c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        int playStatus = PLAYSTATUS_ERROR;
8992fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        switch (state.getState()) {
9002fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            case PlaybackState.STATE_PLAYING:
9012fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            case PlaybackState.STATE_BUFFERING:
902c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_PLAYING;
903c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
904c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
9052fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            case PlaybackState.STATE_STOPPED:
9062fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            case PlaybackState.STATE_NONE:
907c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_STOPPED;
908c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
909c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
9102fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            case PlaybackState.STATE_PAUSED:
911c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_PAUSED;
912c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
913c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
9142fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            case PlaybackState.STATE_FAST_FORWARDING:
9152fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            case PlaybackState.STATE_SKIPPING_TO_NEXT:
9162fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM:
917c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_FWD_SEEK;
918c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
919c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
9202fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            case PlaybackState.STATE_REWINDING:
9212fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
922c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_REV_SEEK;
923c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
924c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
9252fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen            case PlaybackState.STATE_ERROR:
926c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_ERROR;
927c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
928c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
929c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
930c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return playStatus;
931c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
932c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
9332fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen    private boolean isPlayingState(PlaybackState state) {
9342fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen        return (state.getState() == PlaybackState.STATE_PLAYING) ||
9352fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen                (state.getState() == PlaybackState.STATE_BUFFERING);
936188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
937188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
93817675906064bb72fdcca75baa56cdf8bb8968d01John Du    /**
93917675906064bb72fdcca75baa56cdf8bb8968d01John Du     * This is called from AudioService. It will return whether this device supports abs volume.
94017675906064bb72fdcca75baa56cdf8bb8968d01John Du     * NOT USED AT THE MOMENT.
94117675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
94217675906064bb72fdcca75baa56cdf8bb8968d01John Du    public boolean isAbsoluteVolumeSupported() {
94317675906064bb72fdcca75baa56cdf8bb8968d01John Du        return ((mFeatures & BTRC_FEAT_ABSOLUTE_VOLUME) != 0);
94417675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
94517675906064bb72fdcca75baa56cdf8bb8968d01John Du
94617675906064bb72fdcca75baa56cdf8bb8968d01John Du    /**
94717675906064bb72fdcca75baa56cdf8bb8968d01John Du     * We get this call from AudioService. This will send a message to our handler object,
94817675906064bb72fdcca75baa56cdf8bb8968d01John Du     * requesting our handler to call setVolumeNative()
94917675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
95017675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void adjustVolume(int direction) {
95117675906064bb72fdcca75baa56cdf8bb8968d01John Du        Message msg = mHandler.obtainMessage(MESSAGE_ADJUST_VOLUME, direction, 0);
95217675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
95317675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
95417675906064bb72fdcca75baa56cdf8bb8968d01John Du
95517675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void setAbsoluteVolume(int volume) {
95611798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (volume == mLocalVolume) {
95711798b011c962b602217b479130d413f3b30f19aLiejun Tao            if (DEBUG) Log.v(TAG, "setAbsoluteVolume is setting same index, ignore "+volume);
95811798b011c962b602217b479130d413f3b30f19aLiejun Tao            return;
95911798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
96011798b011c962b602217b479130d413f3b30f19aLiejun Tao
96117675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.removeMessages(MESSAGE_ADJUST_VOLUME);
96211798b011c962b602217b479130d413f3b30f19aLiejun Tao        Message msg = mHandler.obtainMessage(MESSAGE_SET_ABSOLUTE_VOLUME, volume, 0);
96317675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
9645c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta    }
9655c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta
96617675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* Called in the native layer as a btrc_callback to return the volume set on the carkit in the
96717675906064bb72fdcca75baa56cdf8bb8968d01John Du     * case when the volume is change locally on the carkit. This notification is not called when
96817675906064bb72fdcca75baa56cdf8bb8968d01John Du     * the volume is changed from the phone.
96917675906064bb72fdcca75baa56cdf8bb8968d01John Du     *
97017675906064bb72fdcca75baa56cdf8bb8968d01John Du     * This method will send a message to our handler to change the local stored volume and notify
97117675906064bb72fdcca75baa56cdf8bb8968d01John Du     * AudioService to update the UI
97217675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
97317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private void volumeChangeCallback(int volume, int ctype) {
97417675906064bb72fdcca75baa56cdf8bb8968d01John Du        Message msg = mHandler.obtainMessage(MESSAGE_VOLUME_CHANGED, volume, ctype);
97517675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
97617675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
97717675906064bb72fdcca75baa56cdf8bb8968d01John Du
9782e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private void notifyVolumeChanged(int volume) {
9792e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume,
9802e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie                      AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
98117675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
98217675906064bb72fdcca75baa56cdf8bb8968d01John Du
98317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int convertToAudioStreamVolume(int volume) {
98417675906064bb72fdcca75baa56cdf8bb8968d01John Du        // Rescale volume to match AudioSystem's volume
98511798b011c962b602217b479130d413f3b30f19aLiejun Tao        return (int) Math.floor((double) volume*mAudioStreamMax/AVRCP_MAX_VOL);
98617675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
98717675906064bb72fdcca75baa56cdf8bb8968d01John Du
98817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int convertToAvrcpVolume(int volume) {
9892e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        return (int) Math.ceil((double) volume*AVRCP_MAX_VOL/mAudioStreamMax);
99017675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
99117675906064bb72fdcca75baa56cdf8bb8968d01John Du
99211798b011c962b602217b479130d413f3b30f19aLiejun Tao    private void blackListCurrentDevice() {
99311798b011c962b602217b479130d413f3b30f19aLiejun Tao        mFeatures &= ~BTRC_FEAT_ABSOLUTE_VOLUME;
99411798b011c962b602217b479130d413f3b30f19aLiejun Tao        mAudioManager.avrcpSupportsAbsoluteVolume(mAddress, isAbsoluteVolumeSupported());
99511798b011c962b602217b479130d413f3b30f19aLiejun Tao
99611798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST,
99711798b011c962b602217b479130d413f3b30f19aLiejun Tao                Context.MODE_PRIVATE);
99811798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences.Editor editor = pref.edit();
99911798b011c962b602217b479130d413f3b30f19aLiejun Tao        editor.putBoolean(mAddress, true);
100011798b011c962b602217b479130d413f3b30f19aLiejun Tao        editor.commit();
100111798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
100211798b011c962b602217b479130d413f3b30f19aLiejun Tao
100311798b011c962b602217b479130d413f3b30f19aLiejun Tao    private int modifyRcFeatureFromBlacklist(int feature, String address) {
100411798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST,
100511798b011c962b602217b479130d413f3b30f19aLiejun Tao                Context.MODE_PRIVATE);
100611798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (!pref.contains(address)) {
100711798b011c962b602217b479130d413f3b30f19aLiejun Tao            return feature;
100811798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
100911798b011c962b602217b479130d413f3b30f19aLiejun Tao        if (pref.getBoolean(address, false)) {
101011798b011c962b602217b479130d413f3b30f19aLiejun Tao            feature &= ~BTRC_FEAT_ABSOLUTE_VOLUME;
101111798b011c962b602217b479130d413f3b30f19aLiejun Tao        }
101211798b011c962b602217b479130d413f3b30f19aLiejun Tao        return feature;
101311798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
101411798b011c962b602217b479130d413f3b30f19aLiejun Tao
101511798b011c962b602217b479130d413f3b30f19aLiejun Tao    public void resetBlackList(String address) {
101611798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST,
101711798b011c962b602217b479130d413f3b30f19aLiejun Tao                Context.MODE_PRIVATE);
101811798b011c962b602217b479130d413f3b30f19aLiejun Tao        SharedPreferences.Editor editor = pref.edit();
101911798b011c962b602217b479130d413f3b30f19aLiejun Tao        editor.remove(address);
102011798b011c962b602217b479130d413f3b30f19aLiejun Tao        editor.commit();
102111798b011c962b602217b479130d413f3b30f19aLiejun Tao    }
102211798b011c962b602217b479130d413f3b30f19aLiejun Tao
1023188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    /**
1024188f205b5f093850d4cc627917a21204be36c56aZhihai Xu     * This is called from A2dpStateMachine to set A2dp audio state.
1025188f205b5f093850d4cc627917a21204be36c56aZhihai Xu     */
1026188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    public void setA2dpAudioState(int state) {
1027188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        Message msg = mHandler.obtainMessage(MESSAGE_SET_A2DP_AUDIO_STATE, state, 0);
1028188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        mHandler.sendMessage(msg);
1029188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
1030188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
1031838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    public void dump(StringBuilder sb) {
1032838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        sb.append("AVRCP:\n");
1033838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mMetadata: " + mMetadata);
1034838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags);
1035838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState);
1036838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT);
1037838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT);
1038838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mTrackNumber: " + mTrackNumber);
1039838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mCurrentPosMs: " + mCurrentPosMs);
1040838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mPlayStartTimeMs: " + mPlayStartTimeMs);
1041838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mSongLengthMs: " + mSongLengthMs);
1042838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs);
1043838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT);
1044838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mNextPosMs: " + mNextPosMs);
1045838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mPrevPosMs: " + mPrevPosMs);
1046838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mSkipStartTime: " + mSkipStartTime);
1047838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mFeatures: " + mFeatures);
104811798b011c962b602217b479130d413f3b30f19aLiejun Tao        ProfileService.println(sb, "mRemoteVolume: " + mRemoteVolume);
104911798b011c962b602217b479130d413f3b30f19aLiejun Tao        ProfileService.println(sb, "mLastRemoteVolume: " + mLastRemoteVolume);
1050838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mLastDirection: " + mLastDirection);
1051838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mVolumeStep: " + mVolumeStep);
1052838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mAudioStreamMax: " + mAudioStreamMax);
105311798b011c962b602217b479130d413f3b30f19aLiejun Tao        ProfileService.println(sb, "mVolCmdAdjustInProgress: " + mVolCmdAdjustInProgress);
105411798b011c962b602217b479130d413f3b30f19aLiejun Tao        ProfileService.println(sb, "mVolCmdSetInProgress: " + mVolCmdSetInProgress);
1055838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mAbsVolRetryTimes: " + mAbsVolRetryTimes);
1056838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mSkipAmount: " + mSkipAmount);
105711798b011c962b602217b479130d413f3b30f19aLiejun Tao        ProfileService.println(sb, "mVolumeMapping: " + mVolumeMapping.toString());
1058838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    }
1059838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood
1060c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // Do not modify without updating the HAL bt_rc.h files.
1061c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1062c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // match up with btrc_play_status_t enum of bt_rc.h
1063c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_STOPPED = 0;
1064c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_PLAYING = 1;
1065c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_PAUSED = 2;
1066c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_FWD_SEEK = 3;
1067c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_REV_SEEK = 4;
1068c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_ERROR = 255;
1069c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1070c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // match up with btrc_media_attr_t enum of bt_rc.h
1071c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_TITLE = 1;
1072c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_ARTIST = 2;
1073c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_ALBUM = 3;
1074c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_TRACK_NUM = 4;
1075c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_NUM_TRACKS = 5;
1076c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_GENRE = 6;
1077c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_PLAYING_TIME = 7;
1078c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1079c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // match up with btrc_event_id_t enum of bt_rc.h
1080c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_PLAY_STATUS_CHANGED = 1;
1081c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_TRACK_CHANGED = 2;
1082c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_TRACK_REACHED_END = 3;
1083c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_TRACK_REACHED_START = 4;
1084c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_PLAY_POS_CHANGED = 5;
1085c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_BATT_STATUS_CHANGED = 6;
1086c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_SYSTEM_STATUS_CHANGED = 7;
1087c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_APP_SETTINGS_CHANGED = 8;
1088c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1089c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // match up with btrc_notification_type_t enum of bt_rc.h
1090c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int NOTIFICATION_TYPE_INTERIM = 0;
1091c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int NOTIFICATION_TYPE_CHANGED = 1;
1092c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1093c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // match up with BTRC_UID_SIZE of bt_rc.h
1094c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int TRACK_ID_SIZE = 8;
1095c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
1096c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native static void classInitNative();
1097c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native void initNative();
1098c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native void cleanupNative();
1099c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean getPlayStatusRspNative(int playStatus, int songLen, int songPos);
1100c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean getElementAttrRspNative(byte numAttr, int[] attrIds, String[] textArray);
1101c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean registerNotificationRspPlayStatusNative(int type, int playStatus);
1102c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean registerNotificationRspTrackChangeNative(int type, byte[] track);
1103aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private native boolean registerNotificationRspPlayPosNative(int type, int playPos);
110417675906064bb72fdcca75baa56cdf8bb8968d01John Du    private native boolean setVolumeNative(int volume);
11055c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta    private native boolean sendPassThroughCommandNative(int keyCode, int keyState);
11065c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta
1107c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
1108