Avrcp.java revision 838949d46a4cc054985a8cfd682004f8dd6d3bbb
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
22c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.app.PendingIntent;
23188f205b5f093850d4cc627917a21204be36c56aZhihai Xuimport android.bluetooth.BluetoothA2dp;
24066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.bluetooth.BluetoothAvrcp;
25c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.content.Context;
26aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport android.content.Intent;
27c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.graphics.Bitmap;
28c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.AudioManager;
29c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.IRemoteControlDisplay;
30c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.MediaMetadataRetriever;
31c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.RemoteControlClient;
326e29e12add362546784126119f26f04fc760f021RoboErikimport android.media.RemoteController;
336e29e12add362546784126119f26f04fc760f021RoboErikimport android.media.RemoteController.MetadataEditor;
34c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Bundle;
35c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Handler;
36c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.HandlerThread;
37c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Looper;
38c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Message;
39c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.ParcelUuid;
40c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.PowerManager;
41c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.PowerManager.WakeLock;
42c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.RemoteException;
43c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.ServiceManager;
44aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport android.os.SystemClock;
45c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.util.Log;
46881675b362bde18acbbcf69c513175addca4a8baZhenye Zhuimport android.view.KeyEvent;
476e29e12add362546784126119f26f04fc760f021RoboErik
48c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.bluetooth.btservice.AdapterService;
49c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.bluetooth.btservice.ProfileService;
50aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport com.android.bluetooth.Utils;
51c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.IState;
52c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.State;
53c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.StateMachine;
546e29e12add362546784126119f26f04fc760f021RoboErik
55c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.lang.ref.WeakReference;
56c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.ArrayList;
57c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.List;
58c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.Set;
59c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu/**
60c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * support Bluetooth AVRCP profile.
61c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * support metadata, play status and event notification
62c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu */
63066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodpublic final class Avrcp {
648e0d927632cce4ad53df85fb7627b915c5fbd64bRoboErik    private static final boolean DEBUG = false;
65c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private static final String TAG = "Avrcp";
66c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
67c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Context mContext;
68c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private final AudioManager mAudioManager;
69c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private AvrcpMessageHandler mHandler;
706e29e12add362546784126119f26f04fc760f021RoboErik    private RemoteController mRemoteController;
716e29e12add362546784126119f26f04fc760f021RoboErik    private RemoteControllerWeak mRemoteControllerCb;
72c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Metadata mMetadata;
73c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mTransportControlFlags;
74c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mCurrentPlayState;
75c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mPlayStatusChangedNT;
76c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int mTrackChangedNT;
77c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private long mTrackNumber;
78aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mCurrentPosMs;
79aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPlayStartTimeMs;
80aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mSongLengthMs;
81aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPlaybackIntervalMs;
82aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private int mPlayPosChangedNT;
83aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mNextPosMs;
84aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long mPrevPosMs;
85ace834feb02adabd61f628c4471147aea02d939cJohn Du    private long mSkipStartTime;
8617675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mFeatures;
8717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mAbsoluteVolume;
8817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mLastSetVolume;
8917675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mLastDirection;
902e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private final int mVolumeStep;
912e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private final int mAudioStreamMax;
9217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private boolean mVolCmdInProgress;
9317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int mAbsVolRetryTimes;
9419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu    private int mSkipAmount;
95ace834feb02adabd61f628c4471147aea02d939cJohn Du
9617675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* BTRC features */
9717675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_METADATA = 0x01;
9817675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02;
9917675906064bb72fdcca75baa56cdf8bb8968d01John Du    public static final int BTRC_FEAT_BROWSE = 0x04;
10017675906064bb72fdcca75baa56cdf8bb8968d01John Du
10117675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* AVRC response codes, from avrc_defs */
10217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_NOT_IMPL = 8;
10317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_ACCEPT = 9;
10417675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_REJ = 10;
10517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_IN_TRANS = 11;
10617675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_IMPL_STBL = 12;
10717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_CHANGED = 13;
10817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRC_RSP_INTERIM = 15;
10917675906064bb72fdcca75baa56cdf8bb8968d01John Du
11017675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_GET_RC_FEATURES = 1;
11117675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_GET_PLAY_STATUS = 2;
11217675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_GET_ELEM_ATTRS = 3;
11317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_REGISTER_NOTIFICATION = 4;
11417675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_PLAY_INTERVAL_TIMEOUT = 5;
11517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_VOLUME_CHANGED = 6;
11617675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_ADJUST_VOLUME = 7;
11717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_SET_ABSOLUTE_VOLUME = 8;
11817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_ABS_VOL_TIMEOUT = 9;
11917675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_FAST_FORWARD = 10;
12017675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MESSAGE_REWIND = 11;
12119e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu    private static final int MESSAGE_CHANGE_PLAY_POS = 12;
122188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    private static final int MESSAGE_SET_A2DP_AUDIO_STATE = 13;
123c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private static final int MSG_UPDATE_STATE = 100;
124c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private static final int MSG_SET_METADATA = 101;
125c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private static final int MSG_SET_TRANSPORT_CONTROLS = 102;
126c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private static final int MSG_SET_GENERATION_ID = 104;
127c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
128ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int BUTTON_TIMEOUT_TIME = 2000;
129ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int BASE_SKIP_AMOUNT = 2000;
130ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int KEY_STATE_PRESS = 1;
131ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int KEY_STATE_RELEASE = 0;
132ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int SKIP_PERIOD = 400;
133ace834feb02adabd61f628c4471147aea02d939cJohn Du    private static final int SKIP_DOUBLE_INTERVAL = 3000;
13419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu    private static final long MAX_MULTIPLIER_VALUE = 128L;
13517675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int CMD_TIMEOUT_DELAY = 2000;
13617675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int MAX_ERROR_RETRY_TIMES = 3;
13717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRCP_MAX_VOL = 127;
13817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private static final int AVRCP_BASE_VOLUME_STEP = 1;
139ace834feb02adabd61f628c4471147aea02d939cJohn Du
140c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    static {
141c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        classInitNative();
142c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
143c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
144c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private Avrcp(Context context) {
145c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mMetadata = new Metadata();
146c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback
147c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
148c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
14979d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu        mTrackNumber = -1L;
150f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        mCurrentPosMs = 0L;
151aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        mPlayStartTimeMs = -1L;
152aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        mSongLengthMs = 0L;
153aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        mPlaybackIntervalMs = 0L;
154aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
15517675906064bb72fdcca75baa56cdf8bb8968d01John Du        mFeatures = 0;
15617675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAbsoluteVolume = -1;
15717675906064bb72fdcca75baa56cdf8bb8968d01John Du        mLastSetVolume = -1;
15817675906064bb72fdcca75baa56cdf8bb8968d01John Du        mLastDirection = 0;
15917675906064bb72fdcca75baa56cdf8bb8968d01John Du        mVolCmdInProgress = false;
16017675906064bb72fdcca75baa56cdf8bb8968d01John Du        mAbsVolRetryTimes = 0;
161c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
162c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mContext = context;
163c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
164c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        initNative();
165c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
166c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
1672e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mAudioStreamMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
1682e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mVolumeStep = Math.max(AVRCP_BASE_VOLUME_STEP, AVRCP_MAX_VOL/mAudioStreamMax);
169c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
170c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
171c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void start() {
172c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler");
173c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        thread.start();
174c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Looper looper = thread.getLooper();
175c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler = new AvrcpMessageHandler(looper);
1766e29e12add362546784126119f26f04fc760f021RoboErik        mRemoteControllerCb = new RemoteControllerWeak(mHandler);
1776e29e12add362546784126119f26f04fc760f021RoboErik        mRemoteController = new RemoteController(mContext, mRemoteControllerCb);
1786e29e12add362546784126119f26f04fc760f021RoboErik        mAudioManager.registerRemoteController(mRemoteController);
1796e29e12add362546784126119f26f04fc760f021RoboErik        mRemoteController.setSynchronizationMode(RemoteController.POSITION_SYNCHRONIZATION_CHECK);
180c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
181c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
182066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood    public static Avrcp make(Context context) {
183c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (DEBUG) Log.v(TAG, "make");
184c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Avrcp ar = new Avrcp(context);
185c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ar.start();
186c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return ar;
187c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
188c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
189c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    public void doQuit() {
190c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.removeCallbacksAndMessages(null);
191c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Looper looper = mHandler.getLooper();
192c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (looper != null) {
193c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            looper.quit();
194c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
1956e29e12add362546784126119f26f04fc760f021RoboErik        mAudioManager.unregisterRemoteController(mRemoteController);
196c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
197c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
198c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    public void cleanup() {
199c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        cleanupNative();
200c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
201c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
2026e29e12add362546784126119f26f04fc760f021RoboErik    private static class RemoteControllerWeak implements RemoteController.OnClientUpdateListener {
2036e29e12add362546784126119f26f04fc760f021RoboErik        private final WeakReference<Handler> mLocalHandler;
2046e29e12add362546784126119f26f04fc760f021RoboErik
2056e29e12add362546784126119f26f04fc760f021RoboErik        public RemoteControllerWeak(Handler handler) {
206c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            mLocalHandler = new WeakReference<Handler>(handler);
207c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
208c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
209bc10e7d58aa55da25c18d8056a0254a2b736146aZhihai Xu        @Override
2106e29e12add362546784126119f26f04fc760f021RoboErik        public void onClientChange(boolean clearing) {
211c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            Handler handler = mLocalHandler.get();
212c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            if (handler != null) {
2136e29e12add362546784126119f26f04fc760f021RoboErik                handler.obtainMessage(MSG_SET_GENERATION_ID,
2146e29e12add362546784126119f26f04fc760f021RoboErik                        0, (clearing ? 1 : 0), null).sendToTarget();
215c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
216c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
217c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
218c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
2196e29e12add362546784126119f26f04fc760f021RoboErik        public void onClientPlaybackStateUpdate(int state) {
2206e29e12add362546784126119f26f04fc760f021RoboErik            // Should never be called with the existing code, but just in case
221c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            Handler handler = mLocalHandler.get();
222c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            if (handler != null) {
2236e29e12add362546784126119f26f04fc760f021RoboErik                handler.obtainMessage(MSG_UPDATE_STATE, 0, state,
2246e29e12add362546784126119f26f04fc760f021RoboErik                        new Long(RemoteControlClient.PLAYBACK_POSITION_INVALID)).sendToTarget();
225c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
226c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
227c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
228c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
2296e29e12add362546784126119f26f04fc760f021RoboErik        public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs,
2306e29e12add362546784126119f26f04fc760f021RoboErik                long currentPosMs, float speed) {
231c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            Handler handler = mLocalHandler.get();
232c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            if (handler != null) {
2336e29e12add362546784126119f26f04fc760f021RoboErik                handler.obtainMessage(MSG_UPDATE_STATE, 0, state,
2346e29e12add362546784126119f26f04fc760f021RoboErik                        new Long(currentPosMs)).sendToTarget();
235c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
236c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
237c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
238c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
2396e29e12add362546784126119f26f04fc760f021RoboErik        public void onClientTransportControlUpdate(int transportControlFlags) {
240c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            Handler handler = mLocalHandler.get();
241c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            if (handler != null) {
2426e29e12add362546784126119f26f04fc760f021RoboErik                handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, 0, transportControlFlags)
2436e29e12add362546784126119f26f04fc760f021RoboErik                        .sendToTarget();
244c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
245c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
246c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
247c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
2486e29e12add362546784126119f26f04fc760f021RoboErik        public void onClientMetadataUpdate(MetadataEditor metadataEditor) {
249c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            Handler handler = mLocalHandler.get();
250c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            if (handler != null) {
2516e29e12add362546784126119f26f04fc760f021RoboErik                handler.obtainMessage(MSG_SET_METADATA, 0, 0, metadataEditor).sendToTarget();
252c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
253c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
254c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
255c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
256c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    /** Handles Avrcp messages. */
257c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private final class AvrcpMessageHandler extends Handler {
258c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        private AvrcpMessageHandler(Looper looper) {
259c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            super(looper);
260c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
261c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
262c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        @Override
263c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public void handleMessage(Message msg) {
264c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            switch (msg.what) {
265c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MSG_UPDATE_STATE:
2666e29e12add362546784126119f26f04fc760f021RoboErik                    updatePlayPauseState(msg.arg2, ((Long) msg.obj).longValue());
267c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
268c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
269c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MSG_SET_METADATA:
2706e29e12add362546784126119f26f04fc760f021RoboErik                    updateMetadata((MetadataEditor) msg.obj);
271c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
272c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
273c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MSG_SET_TRANSPORT_CONTROLS:
2746e29e12add362546784126119f26f04fc760f021RoboErik                    updateTransportControls(msg.arg2);
275c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
276c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
277c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MSG_SET_GENERATION_ID:
278c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
279c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
280c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
28117675906064bb72fdcca75baa56cdf8bb8968d01John Du            case MESSAGE_GET_RC_FEATURES:
28217675906064bb72fdcca75baa56cdf8bb8968d01John Du                String address = (String) msg.obj;
28317675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (DEBUG) Log.v(TAG, "MESSAGE_GET_RC_FEATURES: address="+address+
28417675906064bb72fdcca75baa56cdf8bb8968d01John Du                                                             ", features="+msg.arg1);
28517675906064bb72fdcca75baa56cdf8bb8968d01John Du                mFeatures = msg.arg1;
28617675906064bb72fdcca75baa56cdf8bb8968d01John Du                mAudioManager.avrcpSupportsAbsoluteVolume(address, isAbsoluteVolumeSupported());
28717675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
28817675906064bb72fdcca75baa56cdf8bb8968d01John Du
289c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MESSAGE_GET_PLAY_STATUS:
290c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                if (DEBUG) Log.v(TAG, "MESSAGE_GET_PLAY_STATUS");
291aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                getPlayStatusRspNative(convertPlayStateToPlayStatus(mCurrentPlayState),
292aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                                       (int)mSongLengthMs, (int)getPlayPosition());
293c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
294c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
295c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MESSAGE_GET_ELEM_ATTRS:
296c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            {
297c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                String[] textArray;
298c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                int[] attrIds;
299c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                byte numAttr = (byte) msg.arg1;
300c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                ArrayList<Integer> attrList = (ArrayList<Integer>) msg.obj;
301c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                if (DEBUG) Log.v(TAG, "MESSAGE_GET_ELEM_ATTRS:numAttr=" + numAttr);
302c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                attrIds = new int[numAttr];
303c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                textArray = new String[numAttr];
304c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                for (int i = 0; i < numAttr; ++i) {
305c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                    attrIds[i] = attrList.get(i).intValue();
306c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                    textArray[i] = getAttributeString(attrIds[i]);
307c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                }
308c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                getElementAttrRspNative(numAttr, attrIds, textArray);
309c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
310c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
311c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MESSAGE_REGISTER_NOTIFICATION:
312c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                if (DEBUG) Log.v(TAG, "MESSAGE_REGISTER_NOTIFICATION:event=" + msg.arg1 +
313c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                      " param=" + msg.arg2);
314c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                processRegisterNotification(msg.arg1, msg.arg2);
315c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
316c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
317aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            case MESSAGE_PLAY_INTERVAL_TIMEOUT:
318aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                if (DEBUG) Log.v(TAG, "MESSAGE_PLAY_INTERVAL_TIMEOUT");
319aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
320aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)getPlayPosition());
321aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                break;
322aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
32317675906064bb72fdcca75baa56cdf8bb8968d01John Du            case MESSAGE_VOLUME_CHANGED:
3245c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                if (DEBUG) Log.v(TAG, "MESSAGE_VOLUME_CHANGED: volume=" + ((byte)msg.arg1 & 0x7f)
3255c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                                                        + " ctype=" + msg.arg2);
32617675906064bb72fdcca75baa56cdf8bb8968d01John Du
32717675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (msg.arg2 == AVRC_RSP_ACCEPT || msg.arg2 == AVRC_RSP_REJ) {
32817675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (mVolCmdInProgress == false) {
32917675906064bb72fdcca75baa56cdf8bb8968d01John Du                        Log.e(TAG, "Unsolicited response, ignored");
33017675906064bb72fdcca75baa56cdf8bb8968d01John Du                        break;
33117675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
33217675906064bb72fdcca75baa56cdf8bb8968d01John Du                    removeMessages(MESSAGE_ABS_VOL_TIMEOUT);
33317675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mVolCmdInProgress = false;
33417675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes = 0;
33517675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
3362e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie                if (mAbsoluteVolume != msg.arg1 && (msg.arg2 == AVRC_RSP_ACCEPT ||
3372e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie                                                    msg.arg2 == AVRC_RSP_CHANGED ||
3382e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie                                                    msg.arg2 == AVRC_RSP_INTERIM)) {
3395c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                    byte absVol = (byte)((byte)msg.arg1 & 0x7f); // discard MSB as it is RFD
3406e29e12add362546784126119f26f04fc760f021RoboErik                    notifyVolumeChanged(absVol);
3415c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                    mAbsoluteVolume = absVol;
3425c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                    long pecentVolChanged = ((long)absVol * 100) / 0x7f;
3435c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta                    Log.e(TAG, "percent volume changed: " + pecentVolChanged + "%");
34417675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else if (msg.arg2 == AVRC_RSP_REJ) {
34517675906064bb72fdcca75baa56cdf8bb8968d01John Du                    Log.e(TAG, "setAbsoluteVolume call rejected");
34617675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
34717675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
34817675906064bb72fdcca75baa56cdf8bb8968d01John Du
34917675906064bb72fdcca75baa56cdf8bb8968d01John Du            case MESSAGE_ADJUST_VOLUME:
35017675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (DEBUG) Log.d(TAG, "MESSAGE_ADJUST_VOLUME: direction=" + msg.arg1);
35117675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (mVolCmdInProgress) {
35217675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
35317675906064bb72fdcca75baa56cdf8bb8968d01John Du                    break;
35417675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
35517675906064bb72fdcca75baa56cdf8bb8968d01John Du                // Wait on verification on volume from device, before changing the volume.
35617675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (mAbsoluteVolume != -1 && (msg.arg1 == -1 || msg.arg1 == 1)) {
35717675906064bb72fdcca75baa56cdf8bb8968d01John Du                    int setVol = Math.min(AVRCP_MAX_VOL,
35817675906064bb72fdcca75baa56cdf8bb8968d01John Du                                 Math.max(0, mAbsoluteVolume + msg.arg1*mVolumeStep));
35917675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (setVolumeNative(setVol)) {
36017675906064bb72fdcca75baa56cdf8bb8968d01John Du                        sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT),
36117675906064bb72fdcca75baa56cdf8bb8968d01John Du                                           CMD_TIMEOUT_DELAY);
36217675906064bb72fdcca75baa56cdf8bb8968d01John Du                        mVolCmdInProgress = true;
36317675906064bb72fdcca75baa56cdf8bb8968d01John Du                        mLastDirection = msg.arg1;
36417675906064bb72fdcca75baa56cdf8bb8968d01John Du                        mLastSetVolume = setVol;
36517675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
36617675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else {
36717675906064bb72fdcca75baa56cdf8bb8968d01John Du                    Log.e(TAG, "Unknown direction in MESSAGE_ADJUST_VOLUME");
36817675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
36917675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
37017675906064bb72fdcca75baa56cdf8bb8968d01John Du
37117675906064bb72fdcca75baa56cdf8bb8968d01John Du            case MESSAGE_SET_ABSOLUTE_VOLUME:
37217675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (DEBUG) Log.v(TAG, "MESSAGE_SET_ABSOLUTE_VOLUME");
37317675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (mVolCmdInProgress) {
37417675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
37517675906064bb72fdcca75baa56cdf8bb8968d01John Du                    break;
37617675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
37717675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (setVolumeNative(msg.arg1)) {
37817675906064bb72fdcca75baa56cdf8bb8968d01John Du                    sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
37917675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mVolCmdInProgress = true;
38017675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mLastSetVolume = msg.arg1;
38117675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
38217675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
38317675906064bb72fdcca75baa56cdf8bb8968d01John Du
38417675906064bb72fdcca75baa56cdf8bb8968d01John Du            case MESSAGE_ABS_VOL_TIMEOUT:
38517675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (DEBUG) Log.v(TAG, "MESSAGE_ABS_VOL_TIMEOUT: Volume change cmd timed out.");
38617675906064bb72fdcca75baa56cdf8bb8968d01John Du                mVolCmdInProgress = false;
38717675906064bb72fdcca75baa56cdf8bb8968d01John Du                if (mAbsVolRetryTimes >= MAX_ERROR_RETRY_TIMES) {
38817675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes = 0;
38917675906064bb72fdcca75baa56cdf8bb8968d01John Du                } else {
39017675906064bb72fdcca75baa56cdf8bb8968d01John Du                    mAbsVolRetryTimes += 1;
39117675906064bb72fdcca75baa56cdf8bb8968d01John Du                    if (setVolumeNative(mLastSetVolume)) {
39217675906064bb72fdcca75baa56cdf8bb8968d01John Du                        sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT),
39317675906064bb72fdcca75baa56cdf8bb8968d01John Du                                           CMD_TIMEOUT_DELAY);
39417675906064bb72fdcca75baa56cdf8bb8968d01John Du                        mVolCmdInProgress = true;
39517675906064bb72fdcca75baa56cdf8bb8968d01John Du                    }
39617675906064bb72fdcca75baa56cdf8bb8968d01John Du                }
39717675906064bb72fdcca75baa56cdf8bb8968d01John Du                break;
39817675906064bb72fdcca75baa56cdf8bb8968d01John Du
399ace834feb02adabd61f628c4471147aea02d939cJohn Du            case MESSAGE_FAST_FORWARD:
400ace834feb02adabd61f628c4471147aea02d939cJohn Du            case MESSAGE_REWIND:
401881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                if(msg.what == MESSAGE_FAST_FORWARD) {
402881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    if((mTransportControlFlags &
403881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                        RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD) != 0) {
404881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    int keyState = msg.arg1 == KEY_STATE_PRESS ?
405881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                        KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
406881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    KeyEvent keyEvent =
407881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                        new KeyEvent(keyState, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
408881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    mRemoteController.sendMediaKeyEvent(keyEvent);
409881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    break;
410881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    }
411881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                } else if((mTransportControlFlags &
412881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                        RemoteControlClient.FLAG_KEY_MEDIA_REWIND) != 0) {
413881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    int keyState = msg.arg1 == KEY_STATE_PRESS ?
414881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                        KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
415881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    KeyEvent keyEvent =
416881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                        new KeyEvent(keyState, KeyEvent.KEYCODE_MEDIA_REWIND);
417881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    mRemoteController.sendMediaKeyEvent(keyEvent);
418881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    break;
419881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                }
420881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu
42119e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                int skipAmount;
422ace834feb02adabd61f628c4471147aea02d939cJohn Du                if (msg.what == MESSAGE_FAST_FORWARD) {
423ace834feb02adabd61f628c4471147aea02d939cJohn Du                    if (DEBUG) Log.v(TAG, "MESSAGE_FAST_FORWARD");
424881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    removeMessages(MESSAGE_FAST_FORWARD);
425ace834feb02adabd61f628c4471147aea02d939cJohn Du                    skipAmount = BASE_SKIP_AMOUNT;
426ace834feb02adabd61f628c4471147aea02d939cJohn Du                } else {
427ace834feb02adabd61f628c4471147aea02d939cJohn Du                    if (DEBUG) Log.v(TAG, "MESSAGE_REWIND");
428881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu                    removeMessages(MESSAGE_REWIND);
429ace834feb02adabd61f628c4471147aea02d939cJohn Du                    skipAmount = -BASE_SKIP_AMOUNT;
430ace834feb02adabd61f628c4471147aea02d939cJohn Du                }
431ace834feb02adabd61f628c4471147aea02d939cJohn Du
43219e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                if (hasMessages(MESSAGE_CHANGE_PLAY_POS) &&
43319e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                        (skipAmount != mSkipAmount)) {
43419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    Log.w(TAG, "missing release button event:" + mSkipAmount);
43519e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                }
43619e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu
43719e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                if ((!hasMessages(MESSAGE_CHANGE_PLAY_POS)) ||
43819e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                        (skipAmount != mSkipAmount)) {
43919e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    mSkipStartTime = SystemClock.elapsedRealtime();
44019e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                }
44119e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu
44219e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                removeMessages(MESSAGE_CHANGE_PLAY_POS);
443ace834feb02adabd61f628c4471147aea02d939cJohn Du                if (msg.arg1 == KEY_STATE_PRESS) {
44419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    mSkipAmount = skipAmount;
44519e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    changePositionBy(mSkipAmount * getSkipMultiplier());
44619e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS);
44719e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    posMsg.arg1 = 1;
44819e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    sendMessageDelayed(posMsg, SKIP_PERIOD);
449ace834feb02adabd61f628c4471147aea02d939cJohn Du                }
450881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu
451ace834feb02adabd61f628c4471147aea02d939cJohn Du                break;
452ace834feb02adabd61f628c4471147aea02d939cJohn Du
45319e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu            case MESSAGE_CHANGE_PLAY_POS:
45419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                if (DEBUG) Log.v(TAG, "MESSAGE_CHANGE_PLAY_POS:" + msg.arg1);
45519e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                changePositionBy(mSkipAmount * getSkipMultiplier());
45619e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                if (msg.arg1 * SKIP_PERIOD < BUTTON_TIMEOUT_TIME) {
45719e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS);
45819e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    posMsg.arg1 = msg.arg1 + 1;
45919e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu                    sendMessageDelayed(posMsg, SKIP_PERIOD);
460ace834feb02adabd61f628c4471147aea02d939cJohn Du                }
461ace834feb02adabd61f628c4471147aea02d939cJohn Du                break;
462188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
463188f205b5f093850d4cc627917a21204be36c56aZhihai Xu            case MESSAGE_SET_A2DP_AUDIO_STATE:
464188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                if (DEBUG) Log.v(TAG, "MESSAGE_SET_A2DP_AUDIO_STATE:" + msg.arg1);
465188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                updateA2dpAudioState(msg.arg1);
466188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                break;
467c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
468c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
469c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
470c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
471188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    private void updateA2dpAudioState(int state) {
472188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        boolean isPlaying = (state == BluetoothA2dp.STATE_PLAYING);
473188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        if (isPlaying != isPlayingState(mCurrentPlayState)) {
47422bad7047263a6924423d12718738fdcc7b0352cRavi Nagarajan            /* if a2dp is streaming, check to make sure music is active */
47522bad7047263a6924423d12718738fdcc7b0352cRavi Nagarajan            if ( (isPlaying) && !mAudioManager.isMusicActive())
47622bad7047263a6924423d12718738fdcc7b0352cRavi Nagarajan                return;
477188f205b5f093850d4cc627917a21204be36c56aZhihai Xu            updatePlayPauseState(isPlaying ? RemoteControlClient.PLAYSTATE_PLAYING :
478188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                                 RemoteControlClient.PLAYSTATE_PAUSED,
479188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                                 RemoteControlClient.PLAYBACK_POSITION_INVALID);
480188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        }
481188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
482188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
483aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private void updatePlayPauseState(int state, long currentPosMs) {
484c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (DEBUG) Log.v(TAG,
485aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                "updatePlayPauseState, old=" + mCurrentPlayState + ", state=" + state);
486f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        boolean oldPosValid = (mCurrentPosMs !=
487f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu                               RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN);
488c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState);
489c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        int newPlayStatus = convertPlayStateToPlayStatus(state);
490f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu
491f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        if ((mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) &&
492f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu            (mCurrentPlayState != state) && oldPosValid) {
493f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu            mCurrentPosMs = getPlayPosition();
494f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        }
495f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu
496f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        if (currentPosMs != RemoteControlClient.PLAYBACK_POSITION_INVALID) {
497f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu            mCurrentPosMs = currentPosMs;
498f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        }
499aa6c1cb7f08a5d1fe2c878b587c62cf4dbb6ee8fZhihai Xu        if ((state == RemoteControlClient.PLAYSTATE_PLAYING) &&
500aa6c1cb7f08a5d1fe2c878b587c62cf4dbb6ee8fZhihai Xu            ((currentPosMs != RemoteControlClient.PLAYBACK_POSITION_INVALID) ||
501aa6c1cb7f08a5d1fe2c878b587c62cf4dbb6ee8fZhihai Xu            (mCurrentPlayState != RemoteControlClient.PLAYSTATE_PLAYING))) {
502aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            mPlayStartTimeMs = SystemClock.elapsedRealtime();
503aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        }
504aa6c1cb7f08a5d1fe2c878b587c62cf4dbb6ee8fZhihai Xu        mCurrentPlayState = state;
505aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
506f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        boolean newPosValid = (mCurrentPosMs !=
507f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu                               RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN);
508f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        long playPosition = getPlayPosition();
509aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
510aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        /* need send play position changed notification when play status is changed */
511aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) &&
512aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            ((oldPlayStatus != newPlayStatus) || (oldPosValid != newPosValid) ||
513f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu             (newPosValid && ((playPosition >= mNextPosMs) || (playPosition <= mPrevPosMs))))) {
514aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
515f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu            registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)playPosition);
516aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        }
517aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) && newPosValid &&
518aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            (state == RemoteControlClient.PLAYSTATE_PLAYING)) {
519aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
520f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu            mHandler.sendMessageDelayed(msg, mNextPosMs - playPosition);
521aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        }
522aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
523c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if ((mPlayStatusChangedNT == NOTIFICATION_TYPE_INTERIM) && (oldPlayStatus != newPlayStatus)) {
524c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
525c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, newPlayStatus);
526c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
527c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
528c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
529c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void updateTransportControls(int transportControlFlags) {
530c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mTransportControlFlags = transportControlFlags;
531c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
532c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
533c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    class Metadata {
534c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        private String artist;
535c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        private String trackTitle;
536c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        private String albumTitle;
537c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
538c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public Metadata() {
539c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            artist = null;
540c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            trackTitle = null;
541c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            albumTitle = null;
542c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
543c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
544c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        public String toString() {
545c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + " albumTitle=" +
546c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                   albumTitle + "]";
547c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
548c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
549c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
5506e29e12add362546784126119f26f04fc760f021RoboErik    private void updateMetadata(MetadataEditor data) {
551c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        String oldMetadata = mMetadata.toString();
5526e29e12add362546784126119f26f04fc760f021RoboErik        mMetadata.artist = data.getString(MediaMetadataRetriever.METADATA_KEY_ARTIST, null);
5536e29e12add362546784126119f26f04fc760f021RoboErik        mMetadata.trackTitle = data.getString(MediaMetadataRetriever.METADATA_KEY_TITLE, null);
5546e29e12add362546784126119f26f04fc760f021RoboErik        mMetadata.albumTitle = data.getString(MediaMetadataRetriever.METADATA_KEY_ALBUM, null);
555c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (!oldMetadata.equals(mMetadata.toString())) {
556c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            mTrackNumber++;
557c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            if (mTrackChangedNT == NOTIFICATION_TYPE_INTERIM) {
558c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
559c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                sendTrackChangedRsp();
560c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            }
561aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
562f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu            if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
563aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                mCurrentPosMs = 0L;
564aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
565aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                    mPlayStartTimeMs = SystemClock.elapsedRealtime();
566aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                }
567aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            }
568aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            /* need send play position changed notification when track is changed */
569aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            if (mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) {
570aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
571aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                registerNotificationRspPlayPosNative(mPlayPosChangedNT,
572aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                                                     (int)getPlayPosition());
573aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
574aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            }
575c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
576c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (DEBUG) Log.v(TAG, "mMetadata=" + mMetadata.toString());
577aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
5786e29e12add362546784126119f26f04fc760f021RoboErik        mSongLengthMs = data.getLong(MediaMetadataRetriever.METADATA_KEY_DURATION,
5796e29e12add362546784126119f26f04fc760f021RoboErik                RemoteControlClient.PLAYBACK_POSITION_INVALID);
580aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        if (DEBUG) Log.v(TAG, "duration=" + mSongLengthMs);
581c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
582c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
58317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private void getRcFeatures(byte[] address, int features) {
58417675906064bb72fdcca75baa56cdf8bb8968d01John Du        Message msg = mHandler.obtainMessage(MESSAGE_GET_RC_FEATURES, features, 0,
58517675906064bb72fdcca75baa56cdf8bb8968d01John Du                                             Utils.getAddressStringFromByte(address));
58617675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
58717675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
58817675906064bb72fdcca75baa56cdf8bb8968d01John Du
589c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void getPlayStatus() {
590c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Message msg = mHandler.obtainMessage(MESSAGE_GET_PLAY_STATUS);
591c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
592c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
593c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
594c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void getElementAttr(byte numAttr, int[] attrs) {
595c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        int i;
596c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ArrayList<Integer> attrList = new ArrayList<Integer>();
597c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        for (i = 0; i < numAttr; ++i) {
598c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            attrList.add(attrs[i]);
599c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
6006e29e12add362546784126119f26f04fc760f021RoboErik        Message msg = mHandler.obtainMessage(MESSAGE_GET_ELEM_ATTRS, numAttr, 0, attrList);
601c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
602c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
603c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
604c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void registerNotification(int eventId, int param) {
605c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_NOTIFICATION, eventId, param);
606c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mHandler.sendMessage(msg);
607c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
608c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
609c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void processRegisterNotification(int eventId, int param) {
610c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        switch (eventId) {
611c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case EVT_PLAY_STATUS_CHANGED:
612c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                mPlayStatusChangedNT = NOTIFICATION_TYPE_INTERIM;
613c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                registerNotificationRspPlayStatusNative(mPlayStatusChangedNT,
614c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                       convertPlayStateToPlayStatus(mCurrentPlayState));
615c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
616c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
617c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case EVT_TRACK_CHANGED:
618c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                mTrackChangedNT = NOTIFICATION_TYPE_INTERIM;
619c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                sendTrackChangedRsp();
620c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
621c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
622aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            case EVT_PLAY_POS_CHANGED:
623aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                long songPosition = getPlayPosition();
624aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                mPlayPosChangedNT = NOTIFICATION_TYPE_INTERIM;
625aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                mPlaybackIntervalMs = (long)param * 1000L;
626f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu                if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
627aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                    mNextPosMs = songPosition + mPlaybackIntervalMs;
628aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                    mPrevPosMs = songPosition - mPlaybackIntervalMs;
629aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                    if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
630aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                        Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
631aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                        mHandler.sendMessageDelayed(msg, mPlaybackIntervalMs);
632aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                    }
633aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                }
634aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)songPosition);
635aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                break;
636aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
637c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
638c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
639c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
640ace834feb02adabd61f628c4471147aea02d939cJohn Du    private void handlePassthroughCmd(int id, int keyState) {
641ace834feb02adabd61f628c4471147aea02d939cJohn Du        switch (id) {
642066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            case BluetoothAvrcp.PASSTHROUGH_ID_REWIND:
643ace834feb02adabd61f628c4471147aea02d939cJohn Du                rewind(keyState);
644ace834feb02adabd61f628c4471147aea02d939cJohn Du                break;
645066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood            case BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR:
646ace834feb02adabd61f628c4471147aea02d939cJohn Du                fastForward(keyState);
647ace834feb02adabd61f628c4471147aea02d939cJohn Du                break;
648ace834feb02adabd61f628c4471147aea02d939cJohn Du        }
649ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
650ace834feb02adabd61f628c4471147aea02d939cJohn Du
651ace834feb02adabd61f628c4471147aea02d939cJohn Du    private void fastForward(int keyState) {
652ace834feb02adabd61f628c4471147aea02d939cJohn Du        Message msg = mHandler.obtainMessage(MESSAGE_FAST_FORWARD, keyState, 0);
653ace834feb02adabd61f628c4471147aea02d939cJohn Du        mHandler.sendMessage(msg);
654ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
655ace834feb02adabd61f628c4471147aea02d939cJohn Du
656ace834feb02adabd61f628c4471147aea02d939cJohn Du    private void rewind(int keyState) {
657ace834feb02adabd61f628c4471147aea02d939cJohn Du        Message msg = mHandler.obtainMessage(MESSAGE_REWIND, keyState, 0);
658ace834feb02adabd61f628c4471147aea02d939cJohn Du        mHandler.sendMessage(msg);
659ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
660ace834feb02adabd61f628c4471147aea02d939cJohn Du
661ace834feb02adabd61f628c4471147aea02d939cJohn Du    private void changePositionBy(long amount) {
662ace834feb02adabd61f628c4471147aea02d939cJohn Du        long currentPosMs = getPlayPosition();
663ace834feb02adabd61f628c4471147aea02d939cJohn Du        if (currentPosMs == -1L) return;
664ace834feb02adabd61f628c4471147aea02d939cJohn Du        long newPosMs = Math.max(0L, currentPosMs + amount);
6656e29e12add362546784126119f26f04fc760f021RoboErik        mRemoteController.seekTo(newPosMs);
666ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
667ace834feb02adabd61f628c4471147aea02d939cJohn Du
668ace834feb02adabd61f628c4471147aea02d939cJohn Du    private int getSkipMultiplier() {
669ace834feb02adabd61f628c4471147aea02d939cJohn Du        long currentTime = SystemClock.elapsedRealtime();
67019e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu        long multi = (long) Math.pow(2, (currentTime - mSkipStartTime)/SKIP_DOUBLE_INTERVAL);
67119e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu        return (int) Math.min(MAX_MULTIPLIER_VALUE, multi);
672ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
673ace834feb02adabd61f628c4471147aea02d939cJohn Du
674c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private void sendTrackChangedRsp() {
675c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        byte[] track = new byte[TRACK_ID_SIZE];
67679d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu        /* track is stored in big endian format */
677c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        for (int i = 0; i < TRACK_ID_SIZE; ++i) {
67879d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu            track[i] = (byte) (mTrackNumber >> (56 - 8 * i));
679c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
680c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        registerNotificationRspTrackChangeNative(mTrackChangedNT, track);
681c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
682c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
683aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private long getPlayPosition() {
684aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        long songPosition = -1L;
685f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu        if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
686aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
687aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                songPosition = SystemClock.elapsedRealtime() -
688aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                               mPlayStartTimeMs + mCurrentPosMs;
689aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            } else {
690aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                songPosition = mCurrentPosMs;
691aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            }
692aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        }
693aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        if (DEBUG) Log.v(TAG, "position=" + songPosition);
694aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        return songPosition;
695aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    }
696aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
697c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private String getAttributeString(int attrId) {
698c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        String attrStr = null;
699c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        switch (attrId) {
700c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MEDIA_ATTR_TITLE:
701c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                attrStr = mMetadata.trackTitle;
702c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
703c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
704c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MEDIA_ATTR_ARTIST:
705c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                attrStr = mMetadata.artist;
706c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
707c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
708c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case MEDIA_ATTR_ALBUM:
709c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                attrStr = mMetadata.albumTitle;
710c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
711c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
712aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu            case MEDIA_ATTR_PLAYING_TIME:
713aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                if (mSongLengthMs != 0L) {
714aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                    attrStr = Long.toString(mSongLengthMs);
715aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                }
716aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                break;
717aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
718c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
719c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (attrStr == null) {
720c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            attrStr = new String();
721c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
722c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (DEBUG) Log.v(TAG, "getAttributeString:attrId=" + attrId + " str=" + attrStr);
723c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return attrStr;
724c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
725c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
726c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private int convertPlayStateToPlayStatus(int playState) {
727c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        int playStatus = PLAYSTATUS_ERROR;
728c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        switch (playState) {
729c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case RemoteControlClient.PLAYSTATE_PLAYING:
730c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case RemoteControlClient.PLAYSTATE_BUFFERING:
731c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_PLAYING;
732c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
733c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
734c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case RemoteControlClient.PLAYSTATE_STOPPED:
73579d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu            case RemoteControlClient.PLAYSTATE_NONE:
736c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_STOPPED;
737c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
738c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
739c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case RemoteControlClient.PLAYSTATE_PAUSED:
740c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_PAUSED;
741c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
742c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
743c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
744c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
745c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_FWD_SEEK;
746c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
747c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
748c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case RemoteControlClient.PLAYSTATE_REWINDING:
749c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
750c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_REV_SEEK;
751c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
752c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
753c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            case RemoteControlClient.PLAYSTATE_ERROR:
754c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                playStatus = PLAYSTATUS_ERROR;
755c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                break;
756c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
757c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
758c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return playStatus;
759c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
760c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
761188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    private boolean isPlayingState(int playState) {
762188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        boolean isPlaying = false;
763188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        switch (playState) {
764188f205b5f093850d4cc627917a21204be36c56aZhihai Xu            case RemoteControlClient.PLAYSTATE_PLAYING:
765188f205b5f093850d4cc627917a21204be36c56aZhihai Xu            case RemoteControlClient.PLAYSTATE_BUFFERING:
766188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                isPlaying = true;
767188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                break;
768188f205b5f093850d4cc627917a21204be36c56aZhihai Xu            default:
769188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                isPlaying = false;
770188f205b5f093850d4cc627917a21204be36c56aZhihai Xu                break;
771188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        }
772188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        return isPlaying;
773188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
774188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
77517675906064bb72fdcca75baa56cdf8bb8968d01John Du    /**
77617675906064bb72fdcca75baa56cdf8bb8968d01John Du     * This is called from AudioService. It will return whether this device supports abs volume.
77717675906064bb72fdcca75baa56cdf8bb8968d01John Du     * NOT USED AT THE MOMENT.
77817675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
77917675906064bb72fdcca75baa56cdf8bb8968d01John Du    public boolean isAbsoluteVolumeSupported() {
78017675906064bb72fdcca75baa56cdf8bb8968d01John Du        return ((mFeatures & BTRC_FEAT_ABSOLUTE_VOLUME) != 0);
78117675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
78217675906064bb72fdcca75baa56cdf8bb8968d01John Du
78317675906064bb72fdcca75baa56cdf8bb8968d01John Du    /**
78417675906064bb72fdcca75baa56cdf8bb8968d01John Du     * We get this call from AudioService. This will send a message to our handler object,
78517675906064bb72fdcca75baa56cdf8bb8968d01John Du     * requesting our handler to call setVolumeNative()
78617675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
78717675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void adjustVolume(int direction) {
78817675906064bb72fdcca75baa56cdf8bb8968d01John Du        Message msg = mHandler.obtainMessage(MESSAGE_ADJUST_VOLUME, direction, 0);
78917675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
79017675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
79117675906064bb72fdcca75baa56cdf8bb8968d01John Du
79217675906064bb72fdcca75baa56cdf8bb8968d01John Du    public void setAbsoluteVolume(int volume) {
79317675906064bb72fdcca75baa56cdf8bb8968d01John Du        int avrcpVolume = convertToAvrcpVolume(volume);
79417675906064bb72fdcca75baa56cdf8bb8968d01John Du        avrcpVolume = Math.min(AVRCP_MAX_VOL, Math.max(0, avrcpVolume));
79517675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.removeMessages(MESSAGE_ADJUST_VOLUME);
79617675906064bb72fdcca75baa56cdf8bb8968d01John Du        Message msg = mHandler.obtainMessage(MESSAGE_SET_ABSOLUTE_VOLUME, avrcpVolume, 0);
79717675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
7985c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta    }
7995c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta
80017675906064bb72fdcca75baa56cdf8bb8968d01John Du    /* Called in the native layer as a btrc_callback to return the volume set on the carkit in the
80117675906064bb72fdcca75baa56cdf8bb8968d01John Du     * case when the volume is change locally on the carkit. This notification is not called when
80217675906064bb72fdcca75baa56cdf8bb8968d01John Du     * the volume is changed from the phone.
80317675906064bb72fdcca75baa56cdf8bb8968d01John Du     *
80417675906064bb72fdcca75baa56cdf8bb8968d01John Du     * This method will send a message to our handler to change the local stored volume and notify
80517675906064bb72fdcca75baa56cdf8bb8968d01John Du     * AudioService to update the UI
80617675906064bb72fdcca75baa56cdf8bb8968d01John Du     */
80717675906064bb72fdcca75baa56cdf8bb8968d01John Du    private void volumeChangeCallback(int volume, int ctype) {
80817675906064bb72fdcca75baa56cdf8bb8968d01John Du        Message msg = mHandler.obtainMessage(MESSAGE_VOLUME_CHANGED, volume, ctype);
80917675906064bb72fdcca75baa56cdf8bb8968d01John Du        mHandler.sendMessage(msg);
81017675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
81117675906064bb72fdcca75baa56cdf8bb8968d01John Du
8122e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie    private void notifyVolumeChanged(int volume) {
81317675906064bb72fdcca75baa56cdf8bb8968d01John Du        volume = convertToAudioStreamVolume(volume);
8142e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume,
8152e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie                      AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
81617675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
81717675906064bb72fdcca75baa56cdf8bb8968d01John Du
81817675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int convertToAudioStreamVolume(int volume) {
81917675906064bb72fdcca75baa56cdf8bb8968d01John Du        // Rescale volume to match AudioSystem's volume
820e296684eab2bf622ff27cb1b3cd3008e919dfe30Christian Hanner        return (int) Math.round((double) volume*mAudioStreamMax/AVRCP_MAX_VOL);
82117675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
82217675906064bb72fdcca75baa56cdf8bb8968d01John Du
82317675906064bb72fdcca75baa56cdf8bb8968d01John Du    private int convertToAvrcpVolume(int volume) {
8242e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie        return (int) Math.ceil((double) volume*AVRCP_MAX_VOL/mAudioStreamMax);
82517675906064bb72fdcca75baa56cdf8bb8968d01John Du    }
82617675906064bb72fdcca75baa56cdf8bb8968d01John Du
827188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    /**
828188f205b5f093850d4cc627917a21204be36c56aZhihai Xu     * This is called from A2dpStateMachine to set A2dp audio state.
829188f205b5f093850d4cc627917a21204be36c56aZhihai Xu     */
830188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    public void setA2dpAudioState(int state) {
831188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        Message msg = mHandler.obtainMessage(MESSAGE_SET_A2DP_AUDIO_STATE, state, 0);
832188f205b5f093850d4cc627917a21204be36c56aZhihai Xu        mHandler.sendMessage(msg);
833188f205b5f093850d4cc627917a21204be36c56aZhihai Xu    }
834188f205b5f093850d4cc627917a21204be36c56aZhihai Xu
835838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    public void dump(StringBuilder sb) {
836838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        sb.append("AVRCP:\n");
837838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mMetadata: " + mMetadata);
838838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags);
839838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState);
840838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT);
841838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT);
842838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mTrackNumber: " + mTrackNumber);
843838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mCurrentPosMs: " + mCurrentPosMs);
844838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mPlayStartTimeMs: " + mPlayStartTimeMs);
845838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mSongLengthMs: " + mSongLengthMs);
846838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs);
847838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT);
848838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mNextPosMs: " + mNextPosMs);
849838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mPrevPosMs: " + mPrevPosMs);
850838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mSkipStartTime: " + mSkipStartTime);
851838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mFeatures: " + mFeatures);
852838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mAbsoluteVolume: " + mAbsoluteVolume);
853838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mLastSetVolume: " + mLastSetVolume);
854838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mLastDirection: " + mLastDirection);
855838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mVolumeStep: " + mVolumeStep);
856838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mAudioStreamMax: " + mAudioStreamMax);
857838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mVolCmdInProgress: " + mVolCmdInProgress);
858838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mAbsVolRetryTimes: " + mAbsVolRetryTimes);
859838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood        ProfileService.println(sb, "mSkipAmount: " + mSkipAmount);
860838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood    }
861838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood
862c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // Do not modify without updating the HAL bt_rc.h files.
863c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
864c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // match up with btrc_play_status_t enum of bt_rc.h
865c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_STOPPED = 0;
866c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_PLAYING = 1;
867c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_PAUSED = 2;
868c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_FWD_SEEK = 3;
869c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_REV_SEEK = 4;
870c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int PLAYSTATUS_ERROR = 255;
871c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
872c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // match up with btrc_media_attr_t enum of bt_rc.h
873c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_TITLE = 1;
874c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_ARTIST = 2;
875c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_ALBUM = 3;
876c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_TRACK_NUM = 4;
877c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_NUM_TRACKS = 5;
878c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_GENRE = 6;
879c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int MEDIA_ATTR_PLAYING_TIME = 7;
880c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
881c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // match up with btrc_event_id_t enum of bt_rc.h
882c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_PLAY_STATUS_CHANGED = 1;
883c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_TRACK_CHANGED = 2;
884c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_TRACK_REACHED_END = 3;
885c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_TRACK_REACHED_START = 4;
886c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_PLAY_POS_CHANGED = 5;
887c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_BATT_STATUS_CHANGED = 6;
888c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_SYSTEM_STATUS_CHANGED = 7;
889c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int EVT_APP_SETTINGS_CHANGED = 8;
890c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
891c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // match up with btrc_notification_type_t enum of bt_rc.h
892c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int NOTIFICATION_TYPE_INTERIM = 0;
893c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int NOTIFICATION_TYPE_CHANGED = 1;
894c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
895c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // match up with BTRC_UID_SIZE of bt_rc.h
896c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    final static int TRACK_ID_SIZE = 8;
897c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
898c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native static void classInitNative();
899c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native void initNative();
900c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native void cleanupNative();
901c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean getPlayStatusRspNative(int playStatus, int songLen, int songPos);
902c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean getElementAttrRspNative(byte numAttr, int[] attrIds, String[] textArray);
903c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean registerNotificationRspPlayStatusNative(int type, int playStatus);
904c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    private native boolean registerNotificationRspTrackChangeNative(int type, byte[] track);
905aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    private native boolean registerNotificationRspPlayPosNative(int type, int playPos);
90617675906064bb72fdcca75baa56cdf8bb8968d01John Du    private native boolean setVolumeNative(int volume);
9075c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta    private native boolean sendPassThroughCommandNative(int keyCode, int keyState);
9085c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta
909c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
910