Avrcp.java revision 17675906064bb72fdcca75baa56cdf8bb8968d01
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 17c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xupackage com.android.bluetooth.a2dp; 18c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 19ace834feb02adabd61f628c4471147aea02d939cJohn Duimport java.util.Timer; 20ace834feb02adabd61f628c4471147aea02d939cJohn Duimport java.util.TimerTask; 21ace834feb02adabd61f628c4471147aea02d939cJohn Du 22c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.app.PendingIntent; 23c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.content.Context; 24aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport android.content.Intent; 25c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.graphics.Bitmap; 26c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.AudioManager; 27c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.IRemoteControlDisplay; 28c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.MediaMetadataRetriever; 29c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.RemoteControlClient; 30c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Bundle; 31c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Handler; 32c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.HandlerThread; 33c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Looper; 34c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Message; 35c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.ParcelUuid; 36c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.PowerManager; 37c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.PowerManager.WakeLock; 38c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.RemoteException; 39c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.ServiceManager; 40aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport android.os.SystemClock; 41c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.util.Log; 42c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.bluetooth.btservice.AdapterService; 43c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.bluetooth.btservice.ProfileService; 44aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport com.android.bluetooth.Utils; 45c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.IState; 46c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.State; 47c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.StateMachine; 48c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.lang.ref.WeakReference; 49c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.ArrayList; 50c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.List; 51c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.Set; 52c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 53c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu/** 54c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * support Bluetooth AVRCP profile. 55c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * support metadata, play status and event notification 56c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu */ 57c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xufinal class Avrcp { 5817675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final boolean DEBUG = true; 59c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private static final String TAG = "Avrcp"; 60c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 61c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private Context mContext; 62c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private final AudioManager mAudioManager; 63c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private AvrcpMessageHandler mHandler; 64c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private IRemoteControlDisplayWeak mRemoteControlDisplay; 65c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private int mClientGeneration; 66c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private Metadata mMetadata; 67c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private int mTransportControlFlags; 68c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private int mCurrentPlayState; 69c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private int mPlayStatusChangedNT; 70c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private int mTrackChangedNT; 71c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private long mTrackNumber; 72aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long mCurrentPosMs; 73aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long mPlayStartTimeMs; 74aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long mSongLengthMs; 75aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long mPlaybackIntervalMs; 76aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private int mPlayPosChangedNT; 77aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long mNextPosMs; 78aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long mPrevPosMs; 79ace834feb02adabd61f628c4471147aea02d939cJohn Du private long mSkipStartTime; 80ace834feb02adabd61f628c4471147aea02d939cJohn Du private Timer mTimer; 8117675906064bb72fdcca75baa56cdf8bb8968d01John Du private int mFeatures; 8217675906064bb72fdcca75baa56cdf8bb8968d01John Du private int mAbsoluteVolume; 8317675906064bb72fdcca75baa56cdf8bb8968d01John Du private int mLastSetVolume; 8417675906064bb72fdcca75baa56cdf8bb8968d01John Du private int mLastDirection; 8517675906064bb72fdcca75baa56cdf8bb8968d01John Du private int mVolumeStep; 8617675906064bb72fdcca75baa56cdf8bb8968d01John Du private boolean mVolCmdInProgress; 8717675906064bb72fdcca75baa56cdf8bb8968d01John Du private int mAbsVolRetryTimes; 88ace834feb02adabd61f628c4471147aea02d939cJohn Du 89ace834feb02adabd61f628c4471147aea02d939cJohn Du /* AVRC IDs from avrc_defs.h */ 90ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int AVRC_ID_REWIND = 0x48; 91ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int AVRC_ID_FAST_FOR = 0x49; 92aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 9317675906064bb72fdcca75baa56cdf8bb8968d01John Du /* BTRC features */ 9417675906064bb72fdcca75baa56cdf8bb8968d01John Du public static final int BTRC_FEAT_METADATA = 0x01; 9517675906064bb72fdcca75baa56cdf8bb8968d01John Du public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02; 9617675906064bb72fdcca75baa56cdf8bb8968d01John Du public static final int BTRC_FEAT_BROWSE = 0x04; 9717675906064bb72fdcca75baa56cdf8bb8968d01John Du 9817675906064bb72fdcca75baa56cdf8bb8968d01John Du /* AVRC response codes, from avrc_defs */ 9917675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_NOT_IMPL = 8; 10017675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_ACCEPT = 9; 10117675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_REJ = 10; 10217675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_IN_TRANS = 11; 10317675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_IMPL_STBL = 12; 10417675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_CHANGED = 13; 10517675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_INTERIM = 15; 10617675906064bb72fdcca75baa56cdf8bb8968d01John Du 10717675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_GET_RC_FEATURES = 1; 10817675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_GET_PLAY_STATUS = 2; 10917675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_GET_ELEM_ATTRS = 3; 11017675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_REGISTER_NOTIFICATION = 4; 11117675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_PLAY_INTERVAL_TIMEOUT = 5; 11217675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_VOLUME_CHANGED = 6; 11317675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_ADJUST_VOLUME = 7; 11417675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_SET_ABSOLUTE_VOLUME = 8; 11517675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_ABS_VOL_TIMEOUT = 9; 11617675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_FAST_FORWARD = 10; 11717675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_REWIND = 11; 11817675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_FF_REW_TIMEOUT = 12; 119c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private static final int MSG_UPDATE_STATE = 100; 120c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private static final int MSG_SET_METADATA = 101; 121c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private static final int MSG_SET_TRANSPORT_CONTROLS = 102; 122c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private static final int MSG_SET_ARTWORK = 103; 123c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private static final int MSG_SET_GENERATION_ID = 104; 124c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 125ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int BUTTON_TIMEOUT_TIME = 2000; 126ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int BASE_SKIP_AMOUNT = 2000; 127ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int KEY_STATE_PRESS = 1; 128ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int KEY_STATE_RELEASE = 0; 129ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int SKIP_PERIOD = 400; 130ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int SKIP_DOUBLE_INTERVAL = 3000; 13117675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int CMD_TIMEOUT_DELAY = 2000; 13217675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MAX_ERROR_RETRY_TIMES = 3; 13317675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AUDIO_STREAM_MAX_VOL = 150; 13417675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRCP_MAX_VOL = 127; 13517675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRCP_BASE_VOLUME_STEP = 1; 136ace834feb02adabd61f628c4471147aea02d939cJohn Du 137c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu static { 138c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu classInitNative(); 139c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 140c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 141c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private Avrcp(Context context) { 142c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mMetadata = new Metadata(); 143c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback 144c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED; 145c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mTrackChangedNT = NOTIFICATION_TYPE_CHANGED; 14679d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu mTrackNumber = -1L; 147f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu mCurrentPosMs = 0L; 148aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlayStartTimeMs = -1L; 149aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mSongLengthMs = 0L; 150aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlaybackIntervalMs = 0L; 151aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED; 152ace834feb02adabd61f628c4471147aea02d939cJohn Du mTimer = null; 15317675906064bb72fdcca75baa56cdf8bb8968d01John Du mFeatures = 0; 15417675906064bb72fdcca75baa56cdf8bb8968d01John Du mAbsoluteVolume = -1; 15517675906064bb72fdcca75baa56cdf8bb8968d01John Du mLastSetVolume = -1; 15617675906064bb72fdcca75baa56cdf8bb8968d01John Du mLastDirection = 0; 15717675906064bb72fdcca75baa56cdf8bb8968d01John Du mVolumeStep = AVRCP_BASE_VOLUME_STEP; 15817675906064bb72fdcca75baa56cdf8bb8968d01John Du mVolCmdInProgress = false; 15917675906064bb72fdcca75baa56cdf8bb8968d01John Du mAbsVolRetryTimes = 0; 160c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 161c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mContext = context; 162c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 163c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu initNative(); 164c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 165c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 166c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 167c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 168c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void start() { 169c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler"); 170c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu thread.start(); 171c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Looper looper = thread.getLooper(); 172c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mHandler = new AvrcpMessageHandler(looper); 173c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mRemoteControlDisplay = new IRemoteControlDisplayWeak(mHandler); 174c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mAudioManager.registerRemoteControlDisplay(mRemoteControlDisplay); 175db367aa803836ca5b80da6b07ea2ef8a4b0ca1d2Zhihai Xu mAudioManager.remoteControlDisplayWantsPlaybackPositionSync( 176db367aa803836ca5b80da6b07ea2ef8a4b0ca1d2Zhihai Xu mRemoteControlDisplay, true); 177c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 178c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 179c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu static Avrcp make(Context context) { 180c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (DEBUG) Log.v(TAG, "make"); 181c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Avrcp ar = new Avrcp(context); 182c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu ar.start(); 183c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu return ar; 184c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 185c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 186c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public void doQuit() { 187c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mHandler.removeCallbacksAndMessages(null); 188c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Looper looper = mHandler.getLooper(); 189c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (looper != null) { 190c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu looper.quit(); 191c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 192c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mAudioManager.unregisterRemoteControlDisplay(mRemoteControlDisplay); 193c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 194c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 195c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public void cleanup() { 196c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu cleanupNative(); 197c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 198c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 199c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private static class IRemoteControlDisplayWeak extends IRemoteControlDisplay.Stub { 200c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private WeakReference<Handler> mLocalHandler; 201c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu IRemoteControlDisplayWeak(Handler handler) { 202c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mLocalHandler = new WeakReference<Handler>(handler); 203c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 204c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 205bc10e7d58aa55da25c18d8056a0254a2b736146aZhihai Xu @Override 206eb8907e19ad3fa8208d7a65c8aae1bf758838705Jean-Michel Trivi public void setPlaybackState(int generationId, int state, long stateChangeTimeMs, 207eb8907e19ad3fa8208d7a65c8aae1bf758838705Jean-Michel Trivi long currentPosMs, float speed) { 208c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Handler handler = mLocalHandler.get(); 209c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (handler != null) { 210aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu handler.obtainMessage(MSG_UPDATE_STATE, generationId, state, 211aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu new Long(currentPosMs)).sendToTarget(); 212c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 213c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 214c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 215c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu @Override 216c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public void setMetadata(int generationId, Bundle metadata) { 217c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Handler handler = mLocalHandler.get(); 218c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (handler != null) { 219c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget(); 220c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 221c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 222c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 223c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu @Override 22493627064c68acfaef2da5deb2c9c9e73c7aa13afJean-Michel Trivi public void setTransportControlInfo(int generationId, int flags, int posCapabilities) { 225c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Handler handler = mLocalHandler.get(); 226c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (handler != null) { 227c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags) 228c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu .sendToTarget(); 229c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 230c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 231c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 232c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu @Override 233c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public void setArtwork(int generationId, Bitmap bitmap) { 234c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 235c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 236c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu @Override 237c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) { 238c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Handler handler = mLocalHandler.get(); 239c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (handler != null) { 240c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu handler.obtainMessage(MSG_SET_METADATA, generationId, 0, metadata).sendToTarget(); 241c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu handler.obtainMessage(MSG_SET_ARTWORK, generationId, 0, bitmap).sendToTarget(); 242c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 243c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 244c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 245c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu @Override 246c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent, 247c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu boolean clearing) throws RemoteException { 248c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Handler handler = mLocalHandler.get(); 249c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (handler != null) { 250c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu handler.obtainMessage(MSG_SET_GENERATION_ID, 251c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu clientGeneration, (clearing ? 1 : 0), mediaIntent).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: 266aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if (mClientGeneration == msg.arg1) { 267aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu updatePlayPauseState(msg.arg2, ((Long)msg.obj).longValue()); 268aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 269c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 270c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 271c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MSG_SET_METADATA: 272c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (mClientGeneration == msg.arg1) updateMetadata((Bundle) msg.obj); 273c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 274c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 275c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MSG_SET_TRANSPORT_CONTROLS: 276c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (mClientGeneration == msg.arg1) updateTransportControls(msg.arg2); 277c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 278c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 279c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MSG_SET_ARTWORK: 280c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (mClientGeneration == msg.arg1) { 281c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 282c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 283c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 284c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MSG_SET_GENERATION_ID: 285c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2); 286c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mClientGeneration = msg.arg1; 287c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 288c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 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; 29417675906064bb72fdcca75baa56cdf8bb8968d01John Du mAudioManager.avrcpSupportsAbsoluteVolume(address, isAbsoluteVolumeSupported()); 29517675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 29617675906064bb72fdcca75baa56cdf8bb8968d01John Du 297c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MESSAGE_GET_PLAY_STATUS: 298c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (DEBUG) Log.v(TAG, "MESSAGE_GET_PLAY_STATUS"); 299aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu getPlayStatusRspNative(convertPlayStateToPlayStatus(mCurrentPlayState), 300aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu (int)mSongLengthMs, (int)getPlayPosition()); 301c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 302c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 303c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MESSAGE_GET_ELEM_ATTRS: 304c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu { 305c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu String[] textArray; 306c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu int[] attrIds; 307c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu byte numAttr = (byte) msg.arg1; 308c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu ArrayList<Integer> attrList = (ArrayList<Integer>) msg.obj; 309c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (DEBUG) Log.v(TAG, "MESSAGE_GET_ELEM_ATTRS:numAttr=" + numAttr); 310c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu attrIds = new int[numAttr]; 311c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu textArray = new String[numAttr]; 312c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu for (int i = 0; i < numAttr; ++i) { 313c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu attrIds[i] = attrList.get(i).intValue(); 314c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu textArray[i] = getAttributeString(attrIds[i]); 315c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 316c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu getElementAttrRspNative(numAttr, attrIds, textArray); 317c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 318c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 319c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MESSAGE_REGISTER_NOTIFICATION: 320c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (DEBUG) Log.v(TAG, "MESSAGE_REGISTER_NOTIFICATION:event=" + msg.arg1 + 321c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu " param=" + msg.arg2); 322c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu processRegisterNotification(msg.arg1, msg.arg2); 323c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 324c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 325aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu case MESSAGE_PLAY_INTERVAL_TIMEOUT: 326aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if (DEBUG) Log.v(TAG, "MESSAGE_PLAY_INTERVAL_TIMEOUT"); 327aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED; 328aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)getPlayPosition()); 329aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu break; 330aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 33117675906064bb72fdcca75baa56cdf8bb8968d01John Du case MESSAGE_VOLUME_CHANGED: 33217675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.v(TAG, "MESSAGE_VOLUME_CHANGED: volume=" + msg.arg1 + 33317675906064bb72fdcca75baa56cdf8bb8968d01John Du " ctype=" + msg.arg2); 33417675906064bb72fdcca75baa56cdf8bb8968d01John Du 33517675906064bb72fdcca75baa56cdf8bb8968d01John Du if (msg.arg2 == AVRC_RSP_ACCEPT || msg.arg2 == AVRC_RSP_REJ) { 33617675906064bb72fdcca75baa56cdf8bb8968d01John Du if (mVolCmdInProgress == false) { 33717675906064bb72fdcca75baa56cdf8bb8968d01John Du Log.e(TAG, "Unsolicited response, ignored"); 33817675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 33917675906064bb72fdcca75baa56cdf8bb8968d01John Du } 34017675906064bb72fdcca75baa56cdf8bb8968d01John Du removeMessages(MESSAGE_ABS_VOL_TIMEOUT); 34117675906064bb72fdcca75baa56cdf8bb8968d01John Du mVolCmdInProgress = false; 34217675906064bb72fdcca75baa56cdf8bb8968d01John Du mAbsVolRetryTimes = 0; 34317675906064bb72fdcca75baa56cdf8bb8968d01John Du } 34417675906064bb72fdcca75baa56cdf8bb8968d01John Du // to deal with granularity in the TG 34517675906064bb72fdcca75baa56cdf8bb8968d01John Du if (msg.arg2 == AVRC_RSP_ACCEPT && mAbsoluteVolume == msg.arg1) { 34617675906064bb72fdcca75baa56cdf8bb8968d01John Du if ((mAbsoluteVolume == AVRCP_MAX_VOL && mLastDirection == -1) 34717675906064bb72fdcca75baa56cdf8bb8968d01John Du || (mAbsoluteVolume == 0 && mLastDirection == 1) 34817675906064bb72fdcca75baa56cdf8bb8968d01John Du || (mAbsoluteVolume != AVRCP_MAX_VOL && mAbsoluteVolume != 0)) { 34917675906064bb72fdcca75baa56cdf8bb8968d01John Du mVolumeStep += 1; 35017675906064bb72fdcca75baa56cdf8bb8968d01John Du adjustVolumeImmediate(mLastDirection); 35117675906064bb72fdcca75baa56cdf8bb8968d01John Du } 35217675906064bb72fdcca75baa56cdf8bb8968d01John Du } else if (mAbsoluteVolume != msg.arg1 && (msg.arg2 == AVRC_RSP_ACCEPT || 35317675906064bb72fdcca75baa56cdf8bb8968d01John Du msg.arg2 == AVRC_RSP_CHANGED || 35417675906064bb72fdcca75baa56cdf8bb8968d01John Du msg.arg2 == AVRC_RSP_INTERIM)) { 35517675906064bb72fdcca75baa56cdf8bb8968d01John Du notifyVolumeChanged(mAbsoluteVolume, msg.arg1); 35617675906064bb72fdcca75baa56cdf8bb8968d01John Du mAbsoluteVolume = msg.arg1; 35717675906064bb72fdcca75baa56cdf8bb8968d01John Du } else if (msg.arg2 == AVRC_RSP_REJ) { 35817675906064bb72fdcca75baa56cdf8bb8968d01John Du Log.e(TAG, "setAbsoluteVolume call rejected"); 35917675906064bb72fdcca75baa56cdf8bb8968d01John Du } 36017675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 36117675906064bb72fdcca75baa56cdf8bb8968d01John Du 36217675906064bb72fdcca75baa56cdf8bb8968d01John Du case MESSAGE_ADJUST_VOLUME: 36317675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.d(TAG, "MESSAGE_ADJUST_VOLUME: direction=" + msg.arg1); 36417675906064bb72fdcca75baa56cdf8bb8968d01John Du if (mVolCmdInProgress) { 36517675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.w(TAG, "There is already a volume command in progress."); 36617675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 36717675906064bb72fdcca75baa56cdf8bb8968d01John Du } 36817675906064bb72fdcca75baa56cdf8bb8968d01John Du // Wait on verification on volume from device, before changing the volume. 36917675906064bb72fdcca75baa56cdf8bb8968d01John Du if (mAbsoluteVolume != -1 && (msg.arg1 == -1 || msg.arg1 == 1)) { 37017675906064bb72fdcca75baa56cdf8bb8968d01John Du int setVol = Math.min(AVRCP_MAX_VOL, 37117675906064bb72fdcca75baa56cdf8bb8968d01John Du Math.max(0, mAbsoluteVolume + msg.arg1*mVolumeStep)); 37217675906064bb72fdcca75baa56cdf8bb8968d01John Du if (setVolumeNative(setVol)) { 37317675906064bb72fdcca75baa56cdf8bb8968d01John Du sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT), 37417675906064bb72fdcca75baa56cdf8bb8968d01John Du CMD_TIMEOUT_DELAY); 37517675906064bb72fdcca75baa56cdf8bb8968d01John Du mVolCmdInProgress = true; 37617675906064bb72fdcca75baa56cdf8bb8968d01John Du mLastDirection = msg.arg1; 37717675906064bb72fdcca75baa56cdf8bb8968d01John Du mLastSetVolume = setVol; 37817675906064bb72fdcca75baa56cdf8bb8968d01John Du } 37917675906064bb72fdcca75baa56cdf8bb8968d01John Du } else { 38017675906064bb72fdcca75baa56cdf8bb8968d01John Du Log.e(TAG, "Unknown direction in MESSAGE_ADJUST_VOLUME"); 38117675906064bb72fdcca75baa56cdf8bb8968d01John Du } 38217675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 38317675906064bb72fdcca75baa56cdf8bb8968d01John Du 38417675906064bb72fdcca75baa56cdf8bb8968d01John Du case MESSAGE_SET_ABSOLUTE_VOLUME: 38517675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.v(TAG, "MESSAGE_SET_ABSOLUTE_VOLUME"); 38617675906064bb72fdcca75baa56cdf8bb8968d01John Du if (mVolCmdInProgress) { 38717675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.w(TAG, "There is already a volume command in progress."); 38817675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 38917675906064bb72fdcca75baa56cdf8bb8968d01John Du } 39017675906064bb72fdcca75baa56cdf8bb8968d01John Du if (setVolumeNative(msg.arg1)) { 39117675906064bb72fdcca75baa56cdf8bb8968d01John Du sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY); 39217675906064bb72fdcca75baa56cdf8bb8968d01John Du mVolCmdInProgress = true; 39317675906064bb72fdcca75baa56cdf8bb8968d01John Du mLastSetVolume = msg.arg1; 39417675906064bb72fdcca75baa56cdf8bb8968d01John Du } 39517675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 39617675906064bb72fdcca75baa56cdf8bb8968d01John Du 39717675906064bb72fdcca75baa56cdf8bb8968d01John Du case MESSAGE_ABS_VOL_TIMEOUT: 39817675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.v(TAG, "MESSAGE_ABS_VOL_TIMEOUT: Volume change cmd timed out."); 39917675906064bb72fdcca75baa56cdf8bb8968d01John Du mVolCmdInProgress = false; 40017675906064bb72fdcca75baa56cdf8bb8968d01John Du if (mAbsVolRetryTimes >= MAX_ERROR_RETRY_TIMES) { 40117675906064bb72fdcca75baa56cdf8bb8968d01John Du mAbsVolRetryTimes = 0; 40217675906064bb72fdcca75baa56cdf8bb8968d01John Du } else { 40317675906064bb72fdcca75baa56cdf8bb8968d01John Du mAbsVolRetryTimes += 1; 40417675906064bb72fdcca75baa56cdf8bb8968d01John Du if (setVolumeNative(mLastSetVolume)) { 40517675906064bb72fdcca75baa56cdf8bb8968d01John Du sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT), 40617675906064bb72fdcca75baa56cdf8bb8968d01John Du CMD_TIMEOUT_DELAY); 40717675906064bb72fdcca75baa56cdf8bb8968d01John Du mVolCmdInProgress = true; 40817675906064bb72fdcca75baa56cdf8bb8968d01John Du } 40917675906064bb72fdcca75baa56cdf8bb8968d01John Du } 41017675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 41117675906064bb72fdcca75baa56cdf8bb8968d01John Du 412ace834feb02adabd61f628c4471147aea02d939cJohn Du case MESSAGE_FAST_FORWARD: 413ace834feb02adabd61f628c4471147aea02d939cJohn Du case MESSAGE_REWIND: 414ace834feb02adabd61f628c4471147aea02d939cJohn Du final int skipAmount; 415ace834feb02adabd61f628c4471147aea02d939cJohn Du if (msg.what == MESSAGE_FAST_FORWARD) { 416ace834feb02adabd61f628c4471147aea02d939cJohn Du if (DEBUG) Log.v(TAG, "MESSAGE_FAST_FORWARD"); 417ace834feb02adabd61f628c4471147aea02d939cJohn Du skipAmount = BASE_SKIP_AMOUNT; 418ace834feb02adabd61f628c4471147aea02d939cJohn Du } else { 419ace834feb02adabd61f628c4471147aea02d939cJohn Du if (DEBUG) Log.v(TAG, "MESSAGE_REWIND"); 420ace834feb02adabd61f628c4471147aea02d939cJohn Du skipAmount = -BASE_SKIP_AMOUNT; 421ace834feb02adabd61f628c4471147aea02d939cJohn Du } 422ace834feb02adabd61f628c4471147aea02d939cJohn Du 423ace834feb02adabd61f628c4471147aea02d939cJohn Du removeMessages(MESSAGE_FF_REW_TIMEOUT); 424ace834feb02adabd61f628c4471147aea02d939cJohn Du if (msg.arg1 == KEY_STATE_PRESS) { 425ace834feb02adabd61f628c4471147aea02d939cJohn Du if (mTimer == null) { 426ace834feb02adabd61f628c4471147aea02d939cJohn Du /** Begin fast forwarding */ 427ace834feb02adabd61f628c4471147aea02d939cJohn Du mSkipStartTime = SystemClock.elapsedRealtime(); 428ace834feb02adabd61f628c4471147aea02d939cJohn Du TimerTask task = new TimerTask() { 429ace834feb02adabd61f628c4471147aea02d939cJohn Du @Override 430ace834feb02adabd61f628c4471147aea02d939cJohn Du public void run() { 431ace834feb02adabd61f628c4471147aea02d939cJohn Du changePositionBy(skipAmount*getSkipMultiplier()); 432ace834feb02adabd61f628c4471147aea02d939cJohn Du } 433ace834feb02adabd61f628c4471147aea02d939cJohn Du }; 434ace834feb02adabd61f628c4471147aea02d939cJohn Du mTimer = new Timer(); 435ace834feb02adabd61f628c4471147aea02d939cJohn Du mTimer.schedule(task, 0, SKIP_PERIOD); 436ace834feb02adabd61f628c4471147aea02d939cJohn Du } 437ace834feb02adabd61f628c4471147aea02d939cJohn Du sendMessageDelayed(obtainMessage(MESSAGE_FF_REW_TIMEOUT), BUTTON_TIMEOUT_TIME); 438ace834feb02adabd61f628c4471147aea02d939cJohn Du } else if (msg.arg1 == KEY_STATE_RELEASE && mTimer != null) { 439ace834feb02adabd61f628c4471147aea02d939cJohn Du mTimer.cancel(); 440ace834feb02adabd61f628c4471147aea02d939cJohn Du mTimer = null; 441ace834feb02adabd61f628c4471147aea02d939cJohn Du } 442ace834feb02adabd61f628c4471147aea02d939cJohn Du break; 443ace834feb02adabd61f628c4471147aea02d939cJohn Du 444ace834feb02adabd61f628c4471147aea02d939cJohn Du case MESSAGE_FF_REW_TIMEOUT: 445ace834feb02adabd61f628c4471147aea02d939cJohn Du if (DEBUG) Log.v(TAG, "MESSAGE_FF_REW_TIMEOUT: FF/REW response timed out"); 446ace834feb02adabd61f628c4471147aea02d939cJohn Du if (mTimer != null) { 447ace834feb02adabd61f628c4471147aea02d939cJohn Du mTimer.cancel(); 448ace834feb02adabd61f628c4471147aea02d939cJohn Du mTimer = null; 449ace834feb02adabd61f628c4471147aea02d939cJohn Du } 450ace834feb02adabd61f628c4471147aea02d939cJohn Du break; 451c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 452c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 453c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 454c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 455aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private void updatePlayPauseState(int state, long currentPosMs) { 456c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (DEBUG) Log.v(TAG, 457aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu "updatePlayPauseState, old=" + mCurrentPlayState + ", state=" + state); 458f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu boolean oldPosValid = (mCurrentPosMs != 459f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN); 460c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState); 461c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu int newPlayStatus = convertPlayStateToPlayStatus(state); 462f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu 463f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu if ((mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) && 464f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu (mCurrentPlayState != state) && oldPosValid) { 465f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu mCurrentPosMs = getPlayPosition(); 466f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu } 467f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu 468c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mCurrentPlayState = state; 469f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu if (currentPosMs != RemoteControlClient.PLAYBACK_POSITION_INVALID) { 470f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu mCurrentPosMs = currentPosMs; 471f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu } 472aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if (state == RemoteControlClient.PLAYSTATE_PLAYING) { 473aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlayStartTimeMs = SystemClock.elapsedRealtime(); 474aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 475aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 476f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu boolean newPosValid = (mCurrentPosMs != 477f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN); 478f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu long playPosition = getPlayPosition(); 479aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT); 480aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu /* need send play position changed notification when play status is changed */ 481aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) && 482aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu ((oldPlayStatus != newPlayStatus) || (oldPosValid != newPosValid) || 483f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu (newPosValid && ((playPosition >= mNextPosMs) || (playPosition <= mPrevPosMs))))) { 484aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED; 485f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)playPosition); 486aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 487aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) && newPosValid && 488aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu (state == RemoteControlClient.PLAYSTATE_PLAYING)) { 489aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT); 490f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu mHandler.sendMessageDelayed(msg, mNextPosMs - playPosition); 491aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 492aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 493c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if ((mPlayStatusChangedNT == NOTIFICATION_TYPE_INTERIM) && (oldPlayStatus != newPlayStatus)) { 494c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED; 495c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, newPlayStatus); 496c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 497c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 498c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 499c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void updateTransportControls(int transportControlFlags) { 500c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mTransportControlFlags = transportControlFlags; 501c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 502c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 503c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu class Metadata { 504c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private String artist; 505c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private String trackTitle; 506c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private String albumTitle; 507c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 508c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public Metadata() { 509c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu artist = null; 510c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu trackTitle = null; 511c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu albumTitle = null; 512c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 513c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 514c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public String toString() { 515c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu return "Metadata[artist=" + artist + " trackTitle=" + trackTitle + " albumTitle=" + 516c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu albumTitle + "]"; 517c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 518c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 519c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 520c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private String getMdString(Bundle data, int id) { 521c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu return data.getString(Integer.toString(id)); 522c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 523c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 524aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long getMdLong(Bundle data, int id) { 525aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu return data.getLong(Integer.toString(id)); 526aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 527aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 528c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void updateMetadata(Bundle data) { 529c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu String oldMetadata = mMetadata.toString(); 530c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mMetadata.artist = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST); 531c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mMetadata.trackTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_TITLE); 532c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mMetadata.albumTitle = getMdString(data, MediaMetadataRetriever.METADATA_KEY_ALBUM); 533c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (!oldMetadata.equals(mMetadata.toString())) { 534c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mTrackNumber++; 535c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (mTrackChangedNT == NOTIFICATION_TYPE_INTERIM) { 536c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mTrackChangedNT = NOTIFICATION_TYPE_CHANGED; 537c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu sendTrackChangedRsp(); 538c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 539aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 540f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) { 541aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mCurrentPosMs = 0L; 542aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) { 543aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlayStartTimeMs = SystemClock.elapsedRealtime(); 544aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 545aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 546aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu /* need send play position changed notification when track is changed */ 547aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if (mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) { 548aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED; 549aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu registerNotificationRspPlayPosNative(mPlayPosChangedNT, 550aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu (int)getPlayPosition()); 551aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT); 552aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 553c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 554c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (DEBUG) Log.v(TAG, "mMetadata=" + mMetadata.toString()); 555aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 556aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mSongLengthMs = getMdLong(data, MediaMetadataRetriever.METADATA_KEY_DURATION); 557aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if (DEBUG) Log.v(TAG, "duration=" + mSongLengthMs); 558c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 559c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 56017675906064bb72fdcca75baa56cdf8bb8968d01John Du private void getRcFeatures(byte[] address, int features) { 56117675906064bb72fdcca75baa56cdf8bb8968d01John Du Message msg = mHandler.obtainMessage(MESSAGE_GET_RC_FEATURES, features, 0, 56217675906064bb72fdcca75baa56cdf8bb8968d01John Du Utils.getAddressStringFromByte(address)); 56317675906064bb72fdcca75baa56cdf8bb8968d01John Du mHandler.sendMessage(msg); 56417675906064bb72fdcca75baa56cdf8bb8968d01John Du } 56517675906064bb72fdcca75baa56cdf8bb8968d01John Du 566c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void getPlayStatus() { 567c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Message msg = mHandler.obtainMessage(MESSAGE_GET_PLAY_STATUS); 568c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mHandler.sendMessage(msg); 569c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 570c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 571c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void getElementAttr(byte numAttr, int[] attrs) { 572c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu int i; 573c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu ArrayList<Integer> attrList = new ArrayList<Integer>(); 574c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu for (i = 0; i < numAttr; ++i) { 575c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu attrList.add(attrs[i]); 576c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 577c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Message msg = mHandler.obtainMessage(MESSAGE_GET_ELEM_ATTRS, (int)numAttr, 0, attrList); 578c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mHandler.sendMessage(msg); 579c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 580c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 581c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void registerNotification(int eventId, int param) { 582c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_NOTIFICATION, eventId, param); 583c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mHandler.sendMessage(msg); 584c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 585c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 586c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void processRegisterNotification(int eventId, int param) { 587c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu switch (eventId) { 588c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case EVT_PLAY_STATUS_CHANGED: 589c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mPlayStatusChangedNT = NOTIFICATION_TYPE_INTERIM; 590c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, 591c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu convertPlayStateToPlayStatus(mCurrentPlayState)); 592c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 593c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 594c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case EVT_TRACK_CHANGED: 595c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mTrackChangedNT = NOTIFICATION_TYPE_INTERIM; 596c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu sendTrackChangedRsp(); 597c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 598c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 599aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu case EVT_PLAY_POS_CHANGED: 600aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu long songPosition = getPlayPosition(); 601aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlayPosChangedNT = NOTIFICATION_TYPE_INTERIM; 602aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlaybackIntervalMs = (long)param * 1000L; 603f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) { 604aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mNextPosMs = songPosition + mPlaybackIntervalMs; 605aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPrevPosMs = songPosition - mPlaybackIntervalMs; 606aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) { 607aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT); 608aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mHandler.sendMessageDelayed(msg, mPlaybackIntervalMs); 609aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 610aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 611aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)songPosition); 612aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu break; 613aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 614c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 615c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 616c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 617ace834feb02adabd61f628c4471147aea02d939cJohn Du private void handlePassthroughCmd(int id, int keyState) { 618ace834feb02adabd61f628c4471147aea02d939cJohn Du switch (id) { 619ace834feb02adabd61f628c4471147aea02d939cJohn Du case AVRC_ID_REWIND: 620ace834feb02adabd61f628c4471147aea02d939cJohn Du rewind(keyState); 621ace834feb02adabd61f628c4471147aea02d939cJohn Du break; 622ace834feb02adabd61f628c4471147aea02d939cJohn Du case AVRC_ID_FAST_FOR: 623ace834feb02adabd61f628c4471147aea02d939cJohn Du fastForward(keyState); 624ace834feb02adabd61f628c4471147aea02d939cJohn Du break; 625ace834feb02adabd61f628c4471147aea02d939cJohn Du } 626ace834feb02adabd61f628c4471147aea02d939cJohn Du } 627ace834feb02adabd61f628c4471147aea02d939cJohn Du 628ace834feb02adabd61f628c4471147aea02d939cJohn Du private void fastForward(int keyState) { 629ace834feb02adabd61f628c4471147aea02d939cJohn Du Message msg = mHandler.obtainMessage(MESSAGE_FAST_FORWARD, keyState, 0); 630ace834feb02adabd61f628c4471147aea02d939cJohn Du mHandler.sendMessage(msg); 631ace834feb02adabd61f628c4471147aea02d939cJohn Du } 632ace834feb02adabd61f628c4471147aea02d939cJohn Du 633ace834feb02adabd61f628c4471147aea02d939cJohn Du private void rewind(int keyState) { 634ace834feb02adabd61f628c4471147aea02d939cJohn Du Message msg = mHandler.obtainMessage(MESSAGE_REWIND, keyState, 0); 635ace834feb02adabd61f628c4471147aea02d939cJohn Du mHandler.sendMessage(msg); 636ace834feb02adabd61f628c4471147aea02d939cJohn Du } 637ace834feb02adabd61f628c4471147aea02d939cJohn Du 638ace834feb02adabd61f628c4471147aea02d939cJohn Du private void changePositionBy(long amount) { 639ace834feb02adabd61f628c4471147aea02d939cJohn Du long currentPosMs = getPlayPosition(); 640ace834feb02adabd61f628c4471147aea02d939cJohn Du if (currentPosMs == -1L) return; 641ace834feb02adabd61f628c4471147aea02d939cJohn Du long newPosMs = Math.max(0L, currentPosMs + amount); 642ace834feb02adabd61f628c4471147aea02d939cJohn Du mAudioManager.setRemoteControlClientPlaybackPosition(mClientGeneration, 643ace834feb02adabd61f628c4471147aea02d939cJohn Du newPosMs); 644ace834feb02adabd61f628c4471147aea02d939cJohn Du } 645ace834feb02adabd61f628c4471147aea02d939cJohn Du 646ace834feb02adabd61f628c4471147aea02d939cJohn Du private int getSkipMultiplier() { 647ace834feb02adabd61f628c4471147aea02d939cJohn Du long currentTime = SystemClock.elapsedRealtime(); 648ace834feb02adabd61f628c4471147aea02d939cJohn Du return (int) Math.pow(2, (currentTime - mSkipStartTime)/SKIP_DOUBLE_INTERVAL); 649ace834feb02adabd61f628c4471147aea02d939cJohn Du } 650ace834feb02adabd61f628c4471147aea02d939cJohn Du 651c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void sendTrackChangedRsp() { 652c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu byte[] track = new byte[TRACK_ID_SIZE]; 65379d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu /* track is stored in big endian format */ 654c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu for (int i = 0; i < TRACK_ID_SIZE; ++i) { 65579d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu track[i] = (byte) (mTrackNumber >> (56 - 8 * i)); 656c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 657c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu registerNotificationRspTrackChangeNative(mTrackChangedNT, track); 658c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 659c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 660aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long getPlayPosition() { 661aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu long songPosition = -1L; 662f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) { 663aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) { 664aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu songPosition = SystemClock.elapsedRealtime() - 665aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlayStartTimeMs + mCurrentPosMs; 666aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } else { 667aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu songPosition = mCurrentPosMs; 668aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 669aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 670aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if (DEBUG) Log.v(TAG, "position=" + songPosition); 671aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu return songPosition; 672aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 673aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 674c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private String getAttributeString(int attrId) { 675c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu String attrStr = null; 676c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu switch (attrId) { 677c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MEDIA_ATTR_TITLE: 678c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu attrStr = mMetadata.trackTitle; 679c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 680c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 681c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MEDIA_ATTR_ARTIST: 682c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu attrStr = mMetadata.artist; 683c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 684c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 685c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MEDIA_ATTR_ALBUM: 686c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu attrStr = mMetadata.albumTitle; 687c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 688c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 689aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu case MEDIA_ATTR_PLAYING_TIME: 690aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if (mSongLengthMs != 0L) { 691aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu attrStr = Long.toString(mSongLengthMs); 692aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 693aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu break; 694aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 695c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 696c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (attrStr == null) { 697c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu attrStr = new String(); 698c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 699c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (DEBUG) Log.v(TAG, "getAttributeString:attrId=" + attrId + " str=" + attrStr); 700c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu return attrStr; 701c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 702c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 703c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private int convertPlayStateToPlayStatus(int playState) { 704c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu int playStatus = PLAYSTATUS_ERROR; 705c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu switch (playState) { 706c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case RemoteControlClient.PLAYSTATE_PLAYING: 707c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case RemoteControlClient.PLAYSTATE_BUFFERING: 708c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_PLAYING; 709c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 710c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 711c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case RemoteControlClient.PLAYSTATE_STOPPED: 71279d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu case RemoteControlClient.PLAYSTATE_NONE: 713c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_STOPPED; 714c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 715c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 716c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case RemoteControlClient.PLAYSTATE_PAUSED: 717c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_PAUSED; 718c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 719c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 720c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: 721c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: 722c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_FWD_SEEK; 723c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 724c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 725c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case RemoteControlClient.PLAYSTATE_REWINDING: 726c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: 727c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_REV_SEEK; 728c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 729c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 730c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case RemoteControlClient.PLAYSTATE_ERROR: 731c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_ERROR; 732c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 733c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 734c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 735c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu return playStatus; 736c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 737c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 73817675906064bb72fdcca75baa56cdf8bb8968d01John Du /** 73917675906064bb72fdcca75baa56cdf8bb8968d01John Du * This is called from AudioService. It will return whether this device supports abs volume. 74017675906064bb72fdcca75baa56cdf8bb8968d01John Du * NOT USED AT THE MOMENT. 74117675906064bb72fdcca75baa56cdf8bb8968d01John Du */ 74217675906064bb72fdcca75baa56cdf8bb8968d01John Du public boolean isAbsoluteVolumeSupported() { 74317675906064bb72fdcca75baa56cdf8bb8968d01John Du return ((mFeatures & BTRC_FEAT_ABSOLUTE_VOLUME) != 0); 74417675906064bb72fdcca75baa56cdf8bb8968d01John Du } 74517675906064bb72fdcca75baa56cdf8bb8968d01John Du 74617675906064bb72fdcca75baa56cdf8bb8968d01John Du /** 74717675906064bb72fdcca75baa56cdf8bb8968d01John Du * We get this call from AudioService. This will send a message to our handler object, 74817675906064bb72fdcca75baa56cdf8bb8968d01John Du * requesting our handler to call setVolumeNative() 74917675906064bb72fdcca75baa56cdf8bb8968d01John Du */ 75017675906064bb72fdcca75baa56cdf8bb8968d01John Du public void adjustVolume(int direction) { 75117675906064bb72fdcca75baa56cdf8bb8968d01John Du Message msg = mHandler.obtainMessage(MESSAGE_ADJUST_VOLUME, direction, 0); 75217675906064bb72fdcca75baa56cdf8bb8968d01John Du mHandler.sendMessage(msg); 75317675906064bb72fdcca75baa56cdf8bb8968d01John Du } 75417675906064bb72fdcca75baa56cdf8bb8968d01John Du 75517675906064bb72fdcca75baa56cdf8bb8968d01John Du private void adjustVolumeImmediate(int direction) { 75617675906064bb72fdcca75baa56cdf8bb8968d01John Du Message msg = mHandler.obtainMessage(MESSAGE_ADJUST_VOLUME, direction, 0); 75717675906064bb72fdcca75baa56cdf8bb8968d01John Du mHandler.sendMessageAtFrontOfQueue(msg); 75817675906064bb72fdcca75baa56cdf8bb8968d01John Du } 75917675906064bb72fdcca75baa56cdf8bb8968d01John Du 76017675906064bb72fdcca75baa56cdf8bb8968d01John Du public void setAbsoluteVolume(int volume) { 76117675906064bb72fdcca75baa56cdf8bb8968d01John Du int avrcpVolume = convertToAvrcpVolume(volume); 76217675906064bb72fdcca75baa56cdf8bb8968d01John Du avrcpVolume = Math.min(AVRCP_MAX_VOL, Math.max(0, avrcpVolume)); 76317675906064bb72fdcca75baa56cdf8bb8968d01John Du mHandler.removeMessages(MESSAGE_ADJUST_VOLUME); 76417675906064bb72fdcca75baa56cdf8bb8968d01John Du Message msg = mHandler.obtainMessage(MESSAGE_SET_ABSOLUTE_VOLUME, avrcpVolume, 0); 76517675906064bb72fdcca75baa56cdf8bb8968d01John Du mHandler.sendMessage(msg); 76617675906064bb72fdcca75baa56cdf8bb8968d01John Du 76717675906064bb72fdcca75baa56cdf8bb8968d01John Du } 76817675906064bb72fdcca75baa56cdf8bb8968d01John Du 76917675906064bb72fdcca75baa56cdf8bb8968d01John Du /* Called in the native layer as a btrc_callback to return the volume set on the carkit in the 77017675906064bb72fdcca75baa56cdf8bb8968d01John Du * case when the volume is change locally on the carkit. This notification is not called when 77117675906064bb72fdcca75baa56cdf8bb8968d01John Du * the volume is changed from the phone. 77217675906064bb72fdcca75baa56cdf8bb8968d01John Du * 77317675906064bb72fdcca75baa56cdf8bb8968d01John Du * This method will send a message to our handler to change the local stored volume and notify 77417675906064bb72fdcca75baa56cdf8bb8968d01John Du * AudioService to update the UI 77517675906064bb72fdcca75baa56cdf8bb8968d01John Du */ 77617675906064bb72fdcca75baa56cdf8bb8968d01John Du private void volumeChangeCallback(int volume, int ctype) { 77717675906064bb72fdcca75baa56cdf8bb8968d01John Du Message msg = mHandler.obtainMessage(MESSAGE_VOLUME_CHANGED, volume, ctype); 77817675906064bb72fdcca75baa56cdf8bb8968d01John Du mHandler.sendMessage(msg); 77917675906064bb72fdcca75baa56cdf8bb8968d01John Du } 78017675906064bb72fdcca75baa56cdf8bb8968d01John Du 78117675906064bb72fdcca75baa56cdf8bb8968d01John Du private void notifyVolumeChanged(int oldVolume, int volume) { 78217675906064bb72fdcca75baa56cdf8bb8968d01John Du oldVolume = convertToAudioStreamVolume(oldVolume); 78317675906064bb72fdcca75baa56cdf8bb8968d01John Du volume = convertToAudioStreamVolume(volume); 78417675906064bb72fdcca75baa56cdf8bb8968d01John Du mAudioManager.avrcpUpdateVolume(oldVolume, volume); 78517675906064bb72fdcca75baa56cdf8bb8968d01John Du } 78617675906064bb72fdcca75baa56cdf8bb8968d01John Du 78717675906064bb72fdcca75baa56cdf8bb8968d01John Du private int convertToAudioStreamVolume(int volume) { 78817675906064bb72fdcca75baa56cdf8bb8968d01John Du // Rescale volume to match AudioSystem's volume 78917675906064bb72fdcca75baa56cdf8bb8968d01John Du return (int) Math.ceil((double) volume*AUDIO_STREAM_MAX_VOL/AVRCP_MAX_VOL); 79017675906064bb72fdcca75baa56cdf8bb8968d01John Du } 79117675906064bb72fdcca75baa56cdf8bb8968d01John Du 79217675906064bb72fdcca75baa56cdf8bb8968d01John Du private int convertToAvrcpVolume(int volume) { 79317675906064bb72fdcca75baa56cdf8bb8968d01John Du return (int) Math.ceil((double) volume*AVRCP_MAX_VOL/AUDIO_STREAM_MAX_VOL); 79417675906064bb72fdcca75baa56cdf8bb8968d01John Du } 79517675906064bb72fdcca75baa56cdf8bb8968d01John Du 796c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // Do not modify without updating the HAL bt_rc.h files. 797c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 798c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // match up with btrc_play_status_t enum of bt_rc.h 799c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_STOPPED = 0; 800c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_PLAYING = 1; 801c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_PAUSED = 2; 802c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_FWD_SEEK = 3; 803c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_REV_SEEK = 4; 804c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_ERROR = 255; 805c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 806c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // match up with btrc_media_attr_t enum of bt_rc.h 807c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_TITLE = 1; 808c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_ARTIST = 2; 809c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_ALBUM = 3; 810c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_TRACK_NUM = 4; 811c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_NUM_TRACKS = 5; 812c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_GENRE = 6; 813c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_PLAYING_TIME = 7; 814c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 815c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // match up with btrc_event_id_t enum of bt_rc.h 816c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_PLAY_STATUS_CHANGED = 1; 817c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_TRACK_CHANGED = 2; 818c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_TRACK_REACHED_END = 3; 819c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_TRACK_REACHED_START = 4; 820c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_PLAY_POS_CHANGED = 5; 821c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_BATT_STATUS_CHANGED = 6; 822c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_SYSTEM_STATUS_CHANGED = 7; 823c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_APP_SETTINGS_CHANGED = 8; 824c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 825c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // match up with btrc_notification_type_t enum of bt_rc.h 826c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int NOTIFICATION_TYPE_INTERIM = 0; 827c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int NOTIFICATION_TYPE_CHANGED = 1; 828c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 829c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // match up with BTRC_UID_SIZE of bt_rc.h 830c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int TRACK_ID_SIZE = 8; 831c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 832c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native static void classInitNative(); 833c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native void initNative(); 834c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native void cleanupNative(); 835c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native boolean getPlayStatusRspNative(int playStatus, int songLen, int songPos); 836c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native boolean getElementAttrRspNative(byte numAttr, int[] attrIds, String[] textArray); 837c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native boolean registerNotificationRspPlayStatusNative(int type, int playStatus); 838c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native boolean registerNotificationRspTrackChangeNative(int type, byte[] track); 839aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private native boolean registerNotificationRspPlayPosNative(int type, int playPos); 84017675906064bb72fdcca75baa56cdf8bb8968d01John Du private native boolean setVolumeNative(int volume); 841c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu} 842