1c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu/* 2c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * Copyright (C) 2012 The Android Open Source Project 3c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * 4c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * Licensed under the Apache License, Version 2.0 (the "License"); 5c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * you may not use this file except in compliance with the License. 6c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * You may obtain a copy of the License at 7c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * 8c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * http://www.apache.org/licenses/LICENSE-2.0 9c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * 10c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * Unless required by applicable law or agreed to in writing, software 11c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * distributed under the License is distributed on an "AS IS" BASIS, 12c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * See the License for the specific language governing permissions and 14c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * limitations under the License. 15c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu */ 16c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 17066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodpackage com.android.bluetooth.avrcp; 18c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 19ace834feb02adabd61f628c4471147aea02d939cJohn Duimport java.util.Timer; 20ace834feb02adabd61f628c4471147aea02d939cJohn Duimport java.util.TimerTask; 21ace834feb02adabd61f628c4471147aea02d939cJohn Du 22188f205b5f093850d4cc627917a21204be36c56aZhihai Xuimport android.bluetooth.BluetoothA2dp; 23066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodimport android.bluetooth.BluetoothAvrcp; 24c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.content.Context; 25aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport android.content.Intent; 2611798b011c962b602217b479130d413f3b30f19aLiejun Taoimport android.content.res.Resources; 2711798b011c962b602217b479130d413f3b30f19aLiejun Taoimport android.content.SharedPreferences; 28c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.graphics.Bitmap; 29c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.media.AudioManager; 300fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssenimport android.media.MediaDescription; 312fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssenimport android.media.MediaMetadata; 322fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssenimport android.media.session.MediaController; 332fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssenimport android.media.session.MediaSessionManager; 342fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssenimport android.media.session.PlaybackState; 35c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Bundle; 36c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Handler; 37c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.HandlerThread; 38c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Looper; 39c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.Message; 40c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.ParcelUuid; 41c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.PowerManager; 42c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.PowerManager.WakeLock; 43c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.RemoteException; 44c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.os.ServiceManager; 45aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport android.os.SystemClock; 46c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport android.util.Log; 47881675b362bde18acbbcf69c513175addca4a8baZhenye Zhuimport android.view.KeyEvent; 486e29e12add362546784126119f26f04fc760f021RoboErik 4911798b011c962b602217b479130d413f3b30f19aLiejun Taoimport com.android.bluetooth.R; 50c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.bluetooth.btservice.AdapterService; 51c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.bluetooth.btservice.ProfileService; 52aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xuimport com.android.bluetooth.Utils; 53c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.IState; 54c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.State; 55c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport com.android.internal.util.StateMachine; 566e29e12add362546784126119f26f04fc760f021RoboErik 57c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.lang.ref.WeakReference; 58c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.ArrayList; 5911798b011c962b602217b479130d413f3b30f19aLiejun Taoimport java.util.HashMap; 60c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.List; 61c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuimport java.util.Set; 62c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu/** 63c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * support Bluetooth AVRCP profile. 64c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu * support metadata, play status and event notification 65c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu */ 66066ad9e16a548218b139424f758b92db7af34af2Mike Lockwoodpublic final class Avrcp { 678e0d927632cce4ad53df85fb7627b915c5fbd64bRoboErik private static final boolean DEBUG = false; 68c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private static final String TAG = "Avrcp"; 6911798b011c962b602217b479130d413f3b30f19aLiejun Tao private static final String ABSOLUTE_VOLUME_BLACKLIST = "absolute_volume_blacklist"; 70c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 71c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private Context mContext; 72c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private final AudioManager mAudioManager; 73c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private AvrcpMessageHandler mHandler; 742fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen private MediaSessionManager mMediaSessionManager; 752fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen private MediaSessionChangeListener mSessionChangeListener; 762fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen private MediaController mMediaController; 772fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen private MediaControllerListener mMediaControllerCb; 780fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private MediaAttributes mMediaAttributes; 79c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private int mTransportControlFlags; 802fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen private PlaybackState mCurrentPlayState; 81eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen private long mLastStateUpdate; 82c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private int mPlayStatusChangedNT; 83c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private int mTrackChangedNT; 84eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen private int mPlayPosChangedNT; 85c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private long mTrackNumber; 86aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long mSongLengthMs; 87aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long mPlaybackIntervalMs; 887d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen private long mLastReportedPosition; 89aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long mNextPosMs; 90aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long mPrevPosMs; 91ace834feb02adabd61f628c4471147aea02d939cJohn Du private long mSkipStartTime; 9217675906064bb72fdcca75baa56cdf8bb8968d01John Du private int mFeatures; 9311798b011c962b602217b479130d413f3b30f19aLiejun Tao private int mRemoteVolume; 9411798b011c962b602217b479130d413f3b30f19aLiejun Tao private int mLastRemoteVolume; 9511798b011c962b602217b479130d413f3b30f19aLiejun Tao private int mInitialRemoteVolume; 9611798b011c962b602217b479130d413f3b30f19aLiejun Tao 9711798b011c962b602217b479130d413f3b30f19aLiejun Tao /* Local volume in audio index 0-15 */ 9811798b011c962b602217b479130d413f3b30f19aLiejun Tao private int mLocalVolume; 9911798b011c962b602217b479130d413f3b30f19aLiejun Tao private int mLastLocalVolume; 10011798b011c962b602217b479130d413f3b30f19aLiejun Tao private int mAbsVolThreshold; 10111798b011c962b602217b479130d413f3b30f19aLiejun Tao 10211798b011c962b602217b479130d413f3b30f19aLiejun Tao private String mAddress; 10311798b011c962b602217b479130d413f3b30f19aLiejun Tao private HashMap<Integer, Integer> mVolumeMapping; 10411798b011c962b602217b479130d413f3b30f19aLiejun Tao 10517675906064bb72fdcca75baa56cdf8bb8968d01John Du private int mLastDirection; 1062e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie private final int mVolumeStep; 1072e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie private final int mAudioStreamMax; 10811798b011c962b602217b479130d413f3b30f19aLiejun Tao private boolean mVolCmdAdjustInProgress; 10911798b011c962b602217b479130d413f3b30f19aLiejun Tao private boolean mVolCmdSetInProgress; 11017675906064bb72fdcca75baa56cdf8bb8968d01John Du private int mAbsVolRetryTimes; 11119e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu private int mSkipAmount; 112ace834feb02adabd61f628c4471147aea02d939cJohn Du 11317675906064bb72fdcca75baa56cdf8bb8968d01John Du /* BTRC features */ 11417675906064bb72fdcca75baa56cdf8bb8968d01John Du public static final int BTRC_FEAT_METADATA = 0x01; 11517675906064bb72fdcca75baa56cdf8bb8968d01John Du public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02; 11617675906064bb72fdcca75baa56cdf8bb8968d01John Du public static final int BTRC_FEAT_BROWSE = 0x04; 11717675906064bb72fdcca75baa56cdf8bb8968d01John Du 11817675906064bb72fdcca75baa56cdf8bb8968d01John Du /* AVRC response codes, from avrc_defs */ 11917675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_NOT_IMPL = 8; 12017675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_ACCEPT = 9; 12117675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_REJ = 10; 12217675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_IN_TRANS = 11; 12317675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_IMPL_STBL = 12; 12417675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_CHANGED = 13; 12517675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRC_RSP_INTERIM = 15; 12617675906064bb72fdcca75baa56cdf8bb8968d01John Du 12717675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_GET_RC_FEATURES = 1; 12817675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_GET_PLAY_STATUS = 2; 12917675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_GET_ELEM_ATTRS = 3; 13017675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_REGISTER_NOTIFICATION = 4; 13117675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_PLAY_INTERVAL_TIMEOUT = 5; 13217675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_VOLUME_CHANGED = 6; 13317675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_ADJUST_VOLUME = 7; 13417675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_SET_ABSOLUTE_VOLUME = 8; 13517675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_ABS_VOL_TIMEOUT = 9; 13617675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_FAST_FORWARD = 10; 13717675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int MESSAGE_REWIND = 11; 13819e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu private static final int MESSAGE_CHANGE_PLAY_POS = 12; 139188f205b5f093850d4cc627917a21204be36c56aZhihai Xu private static final int MESSAGE_SET_A2DP_AUDIO_STATE = 13; 140c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 141ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int BUTTON_TIMEOUT_TIME = 2000; 142ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int BASE_SKIP_AMOUNT = 2000; 143ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int KEY_STATE_PRESS = 1; 144ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int KEY_STATE_RELEASE = 0; 145ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int SKIP_PERIOD = 400; 146ace834feb02adabd61f628c4471147aea02d939cJohn Du private static final int SKIP_DOUBLE_INTERVAL = 3000; 14719e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu private static final long MAX_MULTIPLIER_VALUE = 128L; 14817675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int CMD_TIMEOUT_DELAY = 2000; 1492583f09407c8265c12d198d408692c75eabf22a3Liejun Tao private static final int MAX_ERROR_RETRY_TIMES = 6; 15017675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRCP_MAX_VOL = 127; 15117675906064bb72fdcca75baa56cdf8bb8968d01John Du private static final int AVRCP_BASE_VOLUME_STEP = 1; 152ace834feb02adabd61f628c4471147aea02d939cJohn Du 153c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu static { 154c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu classInitNative(); 155c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 156c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 157c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private Avrcp(Context context) { 1580fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen mMediaAttributes = new MediaAttributes(null); 1592fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mCurrentPlayState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build(); 160c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED; 161c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mTrackChangedNT = NOTIFICATION_TYPE_CHANGED; 16279d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu mTrackNumber = -1L; 163eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen mLastStateUpdate = -1L; 164aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mSongLengthMs = 0L; 165aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlaybackIntervalMs = 0L; 166aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED; 1677d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen mLastReportedPosition = -1; 16884d3f084d4d1a65eb7a481e5a7fe4a6ac827be7bMarie Janssen mNextPosMs = -1; 16984d3f084d4d1a65eb7a481e5a7fe4a6ac827be7bMarie Janssen mPrevPosMs = -1; 17017675906064bb72fdcca75baa56cdf8bb8968d01John Du mFeatures = 0; 17111798b011c962b602217b479130d413f3b30f19aLiejun Tao mRemoteVolume = -1; 17211798b011c962b602217b479130d413f3b30f19aLiejun Tao mInitialRemoteVolume = -1; 17311798b011c962b602217b479130d413f3b30f19aLiejun Tao mLastRemoteVolume = -1; 17417675906064bb72fdcca75baa56cdf8bb8968d01John Du mLastDirection = 0; 17511798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolCmdAdjustInProgress = false; 17611798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolCmdSetInProgress = false; 17717675906064bb72fdcca75baa56cdf8bb8968d01John Du mAbsVolRetryTimes = 0; 17811798b011c962b602217b479130d413f3b30f19aLiejun Tao mLocalVolume = -1; 17911798b011c962b602217b479130d413f3b30f19aLiejun Tao mLastLocalVolume = -1; 18011798b011c962b602217b479130d413f3b30f19aLiejun Tao mAbsVolThreshold = 0; 18111798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolumeMapping = new HashMap<Integer, Integer>(); 182c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 183c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mContext = context; 184c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 185c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu initNative(); 186c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 1872fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mMediaSessionManager = (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE); 188c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 1892e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie mAudioStreamMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); 1902e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie mVolumeStep = Math.max(AVRCP_BASE_VOLUME_STEP, AVRCP_MAX_VOL/mAudioStreamMax); 19111798b011c962b602217b479130d413f3b30f19aLiejun Tao Resources resources = context.getResources(); 19211798b011c962b602217b479130d413f3b30f19aLiejun Tao if (resources != null) { 19311798b011c962b602217b479130d413f3b30f19aLiejun Tao mAbsVolThreshold = resources.getInteger(R.integer.a2dp_absolute_volume_initial_threshold); 19411798b011c962b602217b479130d413f3b30f19aLiejun Tao } 195c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 196c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 197c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void start() { 198c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler"); 199c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu thread.start(); 200c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Looper looper = thread.getLooper(); 201c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mHandler = new AvrcpMessageHandler(looper); 2022fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen 2032fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mSessionChangeListener = new MediaSessionChangeListener(); 2042fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mMediaSessionManager.addOnActiveSessionsChangedListener(mSessionChangeListener, null, mHandler); 2052fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen List<MediaController> sessions = mMediaSessionManager.getActiveSessions(null); 2062fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mMediaControllerCb = new MediaControllerListener(); 2072fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if (sessions.size() > 0) { 2082fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen updateCurrentMediaController(sessions.get(0)); 2092fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen } 210c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 211c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 212066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood public static Avrcp make(Context context) { 213c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (DEBUG) Log.v(TAG, "make"); 214c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Avrcp ar = new Avrcp(context); 215c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu ar.start(); 216c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu return ar; 217c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 218c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 219c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public void doQuit() { 220c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mHandler.removeCallbacksAndMessages(null); 221c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Looper looper = mHandler.getLooper(); 222c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (looper != null) { 223c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu looper.quit(); 224c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 2252fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mMediaSessionManager.removeOnActiveSessionsChangedListener(mSessionChangeListener); 226c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 227c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 228c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public void cleanup() { 229c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu cleanupNative(); 23011798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mVolumeMapping != null) 23111798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolumeMapping.clear(); 232c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 233c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 2342fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen private class MediaControllerListener extends MediaController.Callback { 2352fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen @Override 2362fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen public void onMetadataChanged(MediaMetadata metadata) { 2372fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen Log.v(TAG, "MediaController metadata changed"); 2382fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen updateMetadata(metadata); 239c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 240c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 241bc10e7d58aa55da25c18d8056a0254a2b736146aZhihai Xu @Override 2422fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen public void onPlaybackStateChanged(PlaybackState state) { 2432fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen Log.v(TAG, "MediaController playback changed: " + state.toString()); 244eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen updatePlaybackState(state); 245c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 246c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 247c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu @Override 2482fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen public void onSessionDestroyed() { 2492fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen Log.v(TAG, "MediaController session destroyed"); 250c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 2512fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen } 252c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 2532fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen private class MediaSessionChangeListener implements MediaSessionManager.OnActiveSessionsChangedListener { 2542fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen public MediaSessionChangeListener() { 255c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 256c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 257c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu @Override 2582fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen public void onActiveSessionsChanged(List<MediaController> controllers) { 2592fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen Log.v(TAG, "Active sessions changed, " + controllers.size() + " sessions"); 2602fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if (controllers.size() > 0) { 2612fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen updateCurrentMediaController(controllers.get(0)); 262c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 263c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 2642fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen } 265c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 2662fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen private void updateCurrentMediaController(MediaController controller) { 2672fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen Log.v(TAG, "Updating media controller to " + controller); 2682fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if (mMediaController != null) { 2692fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mMediaController.unregisterCallback(mMediaControllerCb); 2702fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen } 2712fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mMediaController = controller; 2722fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if (mMediaController == null) { 2732fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen updateMetadata(null); 2742fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen return; 275c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 2762fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mMediaController.registerCallback(mMediaControllerCb, mHandler); 2772fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen updateMetadata(mMediaController.getMetadata()); 278c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 279c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 280c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu /** Handles Avrcp messages. */ 281c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private final class AvrcpMessageHandler extends Handler { 282c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private AvrcpMessageHandler(Looper looper) { 283c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu super(looper); 284c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 285c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 286c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu @Override 287c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public void handleMessage(Message msg) { 288c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu switch (msg.what) { 28917675906064bb72fdcca75baa56cdf8bb8968d01John Du case MESSAGE_GET_RC_FEATURES: 29017675906064bb72fdcca75baa56cdf8bb8968d01John Du String address = (String) msg.obj; 29117675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.v(TAG, "MESSAGE_GET_RC_FEATURES: address="+address+ 29217675906064bb72fdcca75baa56cdf8bb8968d01John Du ", features="+msg.arg1); 29317675906064bb72fdcca75baa56cdf8bb8968d01John Du mFeatures = msg.arg1; 29411798b011c962b602217b479130d413f3b30f19aLiejun Tao mFeatures = modifyRcFeatureFromBlacklist(mFeatures, address); 29517675906064bb72fdcca75baa56cdf8bb8968d01John Du mAudioManager.avrcpSupportsAbsoluteVolume(address, isAbsoluteVolumeSupported()); 29611798b011c962b602217b479130d413f3b30f19aLiejun Tao mLastLocalVolume = -1; 29711798b011c962b602217b479130d413f3b30f19aLiejun Tao mRemoteVolume = -1; 29811798b011c962b602217b479130d413f3b30f19aLiejun Tao mLocalVolume = -1; 29911798b011c962b602217b479130d413f3b30f19aLiejun Tao mInitialRemoteVolume = -1; 30011798b011c962b602217b479130d413f3b30f19aLiejun Tao mAddress = address; 30111798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mVolumeMapping != null) 30211798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolumeMapping.clear(); 30317675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 30417675906064bb72fdcca75baa56cdf8bb8968d01John Du 305c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MESSAGE_GET_PLAY_STATUS: 306c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (DEBUG) Log.v(TAG, "MESSAGE_GET_PLAY_STATUS"); 307aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu getPlayStatusRspNative(convertPlayStateToPlayStatus(mCurrentPlayState), 308aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu (int)mSongLengthMs, (int)getPlayPosition()); 309c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 310c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 311c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MESSAGE_GET_ELEM_ATTRS: 312c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu String[] textArray; 313c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu int[] attrIds; 314c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu byte numAttr = (byte) msg.arg1; 315c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu ArrayList<Integer> attrList = (ArrayList<Integer>) msg.obj; 31665e7943d098113c5aa56e9822b68f0c51c6dbe36Marie Janssen Log.v(TAG, "MESSAGE_GET_ELEM_ATTRS:numAttr=" + numAttr); 317c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu attrIds = new int[numAttr]; 318c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu textArray = new String[numAttr]; 319c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu for (int i = 0; i < numAttr; ++i) { 320c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu attrIds[i] = attrList.get(i).intValue(); 3210fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen textArray[i] = mMediaAttributes.getString(attrIds[i]); 3220fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen Log.v(TAG, "getAttributeString:attrId=" + attrIds[i] + 3230fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen " str=" + textArray[i]); 324c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 325c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu getElementAttrRspNative(numAttr, attrIds, textArray); 326c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 32765e7943d098113c5aa56e9822b68f0c51c6dbe36Marie Janssen 328c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case MESSAGE_REGISTER_NOTIFICATION: 329c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (DEBUG) Log.v(TAG, "MESSAGE_REGISTER_NOTIFICATION:event=" + msg.arg1 + 330c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu " param=" + msg.arg2); 331c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu processRegisterNotification(msg.arg1, msg.arg2); 332c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 333c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 334aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu case MESSAGE_PLAY_INTERVAL_TIMEOUT: 335aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu if (DEBUG) Log.v(TAG, "MESSAGE_PLAY_INTERVAL_TIMEOUT"); 336eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen sendPlayPosNotificationRsp(false); 337aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu break; 338aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 33917675906064bb72fdcca75baa56cdf8bb8968d01John Du case MESSAGE_VOLUME_CHANGED: 34011798b011c962b602217b479130d413f3b30f19aLiejun Tao if (!isAbsoluteVolumeSupported()) { 34111798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.v(TAG, "ignore MESSAGE_VOLUME_CHANGED"); 34211798b011c962b602217b479130d413f3b30f19aLiejun Tao break; 34311798b011c962b602217b479130d413f3b30f19aLiejun Tao } 34411798b011c962b602217b479130d413f3b30f19aLiejun Tao 3455c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta if (DEBUG) Log.v(TAG, "MESSAGE_VOLUME_CHANGED: volume=" + ((byte)msg.arg1 & 0x7f) 3465c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta + " ctype=" + msg.arg2); 34717675906064bb72fdcca75baa56cdf8bb8968d01John Du 34811798b011c962b602217b479130d413f3b30f19aLiejun Tao 34911798b011c962b602217b479130d413f3b30f19aLiejun Tao boolean volAdj = false; 35017675906064bb72fdcca75baa56cdf8bb8968d01John Du if (msg.arg2 == AVRC_RSP_ACCEPT || msg.arg2 == AVRC_RSP_REJ) { 35111798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mVolCmdAdjustInProgress == false && mVolCmdSetInProgress == false) { 35217675906064bb72fdcca75baa56cdf8bb8968d01John Du Log.e(TAG, "Unsolicited response, ignored"); 35317675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 35417675906064bb72fdcca75baa56cdf8bb8968d01John Du } 35517675906064bb72fdcca75baa56cdf8bb8968d01John Du removeMessages(MESSAGE_ABS_VOL_TIMEOUT); 35611798b011c962b602217b479130d413f3b30f19aLiejun Tao 35711798b011c962b602217b479130d413f3b30f19aLiejun Tao volAdj = mVolCmdAdjustInProgress; 35811798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolCmdAdjustInProgress = false; 35911798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolCmdSetInProgress = false; 36017675906064bb72fdcca75baa56cdf8bb8968d01John Du mAbsVolRetryTimes = 0; 36117675906064bb72fdcca75baa56cdf8bb8968d01John Du } 36211798b011c962b602217b479130d413f3b30f19aLiejun Tao 36311798b011c962b602217b479130d413f3b30f19aLiejun Tao byte absVol = (byte)((byte)msg.arg1 & 0x7f); // discard MSB as it is RFD 36411798b011c962b602217b479130d413f3b30f19aLiejun Tao // convert remote volume to local volume 36511798b011c962b602217b479130d413f3b30f19aLiejun Tao int volIndex = convertToAudioStreamVolume(absVol); 36611798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mInitialRemoteVolume == -1) { 36711798b011c962b602217b479130d413f3b30f19aLiejun Tao mInitialRemoteVolume = absVol; 36811798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mAbsVolThreshold > 0 && mAbsVolThreshold < mAudioStreamMax && volIndex > mAbsVolThreshold) { 36911798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.v(TAG, "remote inital volume too high " + volIndex + ">" + mAbsVolThreshold); 37011798b011c962b602217b479130d413f3b30f19aLiejun Tao Message msg1 = mHandler.obtainMessage(MESSAGE_SET_ABSOLUTE_VOLUME, mAbsVolThreshold , 0); 37111798b011c962b602217b479130d413f3b30f19aLiejun Tao mHandler.sendMessage(msg1); 37211798b011c962b602217b479130d413f3b30f19aLiejun Tao mRemoteVolume = absVol; 37311798b011c962b602217b479130d413f3b30f19aLiejun Tao mLocalVolume = volIndex; 37411798b011c962b602217b479130d413f3b30f19aLiejun Tao break; 37511798b011c962b602217b479130d413f3b30f19aLiejun Tao } 37611798b011c962b602217b479130d413f3b30f19aLiejun Tao } 37711798b011c962b602217b479130d413f3b30f19aLiejun Tao 3782fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if (mLocalVolume != volIndex && (msg.arg2 == AVRC_RSP_ACCEPT || 3792fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen msg.arg2 == AVRC_RSP_CHANGED || 3802fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen msg.arg2 == AVRC_RSP_INTERIM)) { 38111798b011c962b602217b479130d413f3b30f19aLiejun Tao /* If the volume has successfully changed */ 38211798b011c962b602217b479130d413f3b30f19aLiejun Tao mLocalVolume = volIndex; 38311798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mLastLocalVolume != -1 && msg.arg2 == AVRC_RSP_ACCEPT) { 38411798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mLastLocalVolume != volIndex) { 38511798b011c962b602217b479130d413f3b30f19aLiejun Tao /* remote volume changed more than requested due to 38611798b011c962b602217b479130d413f3b30f19aLiejun Tao * local and remote has different volume steps */ 38711798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.d(TAG, "Remote returned volume does not match desired volume " 38811798b011c962b602217b479130d413f3b30f19aLiejun Tao + mLastLocalVolume + " vs " 38911798b011c962b602217b479130d413f3b30f19aLiejun Tao + volIndex); 39011798b011c962b602217b479130d413f3b30f19aLiejun Tao mLastLocalVolume = mLocalVolume; 39111798b011c962b602217b479130d413f3b30f19aLiejun Tao } 39211798b011c962b602217b479130d413f3b30f19aLiejun Tao } 39311798b011c962b602217b479130d413f3b30f19aLiejun Tao // remember the remote volume value, as it's the one supported by remote 39411798b011c962b602217b479130d413f3b30f19aLiejun Tao if (volAdj) { 39511798b011c962b602217b479130d413f3b30f19aLiejun Tao synchronized (mVolumeMapping) { 39611798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolumeMapping.put(volIndex, (int)absVol); 39711798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.v(TAG, "remember volume mapping " +volIndex+ "-"+absVol); 39811798b011c962b602217b479130d413f3b30f19aLiejun Tao } 39911798b011c962b602217b479130d413f3b30f19aLiejun Tao } 40011798b011c962b602217b479130d413f3b30f19aLiejun Tao 40111798b011c962b602217b479130d413f3b30f19aLiejun Tao notifyVolumeChanged(mLocalVolume); 40211798b011c962b602217b479130d413f3b30f19aLiejun Tao mRemoteVolume = absVol; 4035c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta long pecentVolChanged = ((long)absVol * 100) / 0x7f; 4045c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta Log.e(TAG, "percent volume changed: " + pecentVolChanged + "%"); 40517675906064bb72fdcca75baa56cdf8bb8968d01John Du } else if (msg.arg2 == AVRC_RSP_REJ) { 40617675906064bb72fdcca75baa56cdf8bb8968d01John Du Log.e(TAG, "setAbsoluteVolume call rejected"); 40711798b011c962b602217b479130d413f3b30f19aLiejun Tao } else if (volAdj && mLastRemoteVolume > 0 && mLastRemoteVolume < AVRCP_MAX_VOL && 4082fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mLocalVolume == volIndex && 4092fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen (msg.arg2 == AVRC_RSP_ACCEPT )) { 41011798b011c962b602217b479130d413f3b30f19aLiejun Tao /* oops, the volume is still same, remote does not like the value 41111798b011c962b602217b479130d413f3b30f19aLiejun Tao * retry a volume one step up/down */ 41211798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.d(TAG, "Remote device didn't tune volume, let's try one more step."); 41311798b011c962b602217b479130d413f3b30f19aLiejun Tao int retry_volume = Math.min(AVRCP_MAX_VOL, 41411798b011c962b602217b479130d413f3b30f19aLiejun Tao Math.max(0, mLastRemoteVolume + mLastDirection)); 41511798b011c962b602217b479130d413f3b30f19aLiejun Tao if (setVolumeNative(retry_volume)) { 41611798b011c962b602217b479130d413f3b30f19aLiejun Tao mLastRemoteVolume = retry_volume; 41711798b011c962b602217b479130d413f3b30f19aLiejun Tao sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT), 41811798b011c962b602217b479130d413f3b30f19aLiejun Tao CMD_TIMEOUT_DELAY); 41911798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolCmdAdjustInProgress = true; 42011798b011c962b602217b479130d413f3b30f19aLiejun Tao } 42117675906064bb72fdcca75baa56cdf8bb8968d01John Du } 42217675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 42317675906064bb72fdcca75baa56cdf8bb8968d01John Du 42417675906064bb72fdcca75baa56cdf8bb8968d01John Du case MESSAGE_ADJUST_VOLUME: 42511798b011c962b602217b479130d413f3b30f19aLiejun Tao if (!isAbsoluteVolumeSupported()) { 42611798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.v(TAG, "ignore MESSAGE_ADJUST_VOLUME"); 42711798b011c962b602217b479130d413f3b30f19aLiejun Tao break; 42811798b011c962b602217b479130d413f3b30f19aLiejun Tao } 42911798b011c962b602217b479130d413f3b30f19aLiejun Tao 43017675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.d(TAG, "MESSAGE_ADJUST_VOLUME: direction=" + msg.arg1); 43111798b011c962b602217b479130d413f3b30f19aLiejun Tao 43211798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mVolCmdAdjustInProgress || mVolCmdSetInProgress) { 43317675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.w(TAG, "There is already a volume command in progress."); 43417675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 43517675906064bb72fdcca75baa56cdf8bb8968d01John Du } 43611798b011c962b602217b479130d413f3b30f19aLiejun Tao 43711798b011c962b602217b479130d413f3b30f19aLiejun Tao // Remote device didn't set initial volume. Let's black list it 43811798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mInitialRemoteVolume == -1) { 43911798b011c962b602217b479130d413f3b30f19aLiejun Tao Log.d(TAG, "remote " + mAddress + " never tell us initial volume, black list it."); 44011798b011c962b602217b479130d413f3b30f19aLiejun Tao blackListCurrentDevice(); 44111798b011c962b602217b479130d413f3b30f19aLiejun Tao break; 44211798b011c962b602217b479130d413f3b30f19aLiejun Tao } 44311798b011c962b602217b479130d413f3b30f19aLiejun Tao 44417675906064bb72fdcca75baa56cdf8bb8968d01John Du // Wait on verification on volume from device, before changing the volume. 44511798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mRemoteVolume != -1 && (msg.arg1 == -1 || msg.arg1 == 1)) { 44611798b011c962b602217b479130d413f3b30f19aLiejun Tao int setVol = -1; 44711798b011c962b602217b479130d413f3b30f19aLiejun Tao int targetVolIndex = -1; 44811798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mLocalVolume == 0 && msg.arg1 == -1) { 44911798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.w(TAG, "No need to Vol down from 0."); 45011798b011c962b602217b479130d413f3b30f19aLiejun Tao break; 45111798b011c962b602217b479130d413f3b30f19aLiejun Tao } 45211798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mLocalVolume == mAudioStreamMax && msg.arg1 == 1) { 45311798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.w(TAG, "No need to Vol up from max."); 45411798b011c962b602217b479130d413f3b30f19aLiejun Tao break; 45511798b011c962b602217b479130d413f3b30f19aLiejun Tao } 45611798b011c962b602217b479130d413f3b30f19aLiejun Tao 45711798b011c962b602217b479130d413f3b30f19aLiejun Tao targetVolIndex = mLocalVolume + msg.arg1; 45811798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.d(TAG, "Adjusting volume to " + targetVolIndex); 45911798b011c962b602217b479130d413f3b30f19aLiejun Tao 46011798b011c962b602217b479130d413f3b30f19aLiejun Tao Integer i; 46111798b011c962b602217b479130d413f3b30f19aLiejun Tao synchronized (mVolumeMapping) { 46211798b011c962b602217b479130d413f3b30f19aLiejun Tao i = mVolumeMapping.get(targetVolIndex); 46311798b011c962b602217b479130d413f3b30f19aLiejun Tao } 46411798b011c962b602217b479130d413f3b30f19aLiejun Tao 46511798b011c962b602217b479130d413f3b30f19aLiejun Tao if (i != null) { 46611798b011c962b602217b479130d413f3b30f19aLiejun Tao /* if we already know this volume mapping, use it */ 46711798b011c962b602217b479130d413f3b30f19aLiejun Tao setVol = i.byteValue(); 46811798b011c962b602217b479130d413f3b30f19aLiejun Tao if (setVol == mRemoteVolume) { 46911798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.d(TAG, "got same volume from mapping for " + targetVolIndex + ", ignore."); 47011798b011c962b602217b479130d413f3b30f19aLiejun Tao setVol = -1; 47111798b011c962b602217b479130d413f3b30f19aLiejun Tao } 47211798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.d(TAG, "set volume from mapping " + targetVolIndex + "-" + setVol); 47311798b011c962b602217b479130d413f3b30f19aLiejun Tao } 47411798b011c962b602217b479130d413f3b30f19aLiejun Tao 47511798b011c962b602217b479130d413f3b30f19aLiejun Tao if (setVol == -1) { 47611798b011c962b602217b479130d413f3b30f19aLiejun Tao /* otherwise use phone steps */ 47711798b011c962b602217b479130d413f3b30f19aLiejun Tao setVol = Math.min(AVRCP_MAX_VOL, 47811798b011c962b602217b479130d413f3b30f19aLiejun Tao convertToAvrcpVolume(Math.max(0, targetVolIndex))); 47911798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.d(TAG, "set volume from local volume "+ targetVolIndex+"-"+ setVol); 48011798b011c962b602217b479130d413f3b30f19aLiejun Tao } 48111798b011c962b602217b479130d413f3b30f19aLiejun Tao 48217675906064bb72fdcca75baa56cdf8bb8968d01John Du if (setVolumeNative(setVol)) { 48317675906064bb72fdcca75baa56cdf8bb8968d01John Du sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT), 48417675906064bb72fdcca75baa56cdf8bb8968d01John Du CMD_TIMEOUT_DELAY); 48511798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolCmdAdjustInProgress = true; 48617675906064bb72fdcca75baa56cdf8bb8968d01John Du mLastDirection = msg.arg1; 48711798b011c962b602217b479130d413f3b30f19aLiejun Tao mLastRemoteVolume = setVol; 48811798b011c962b602217b479130d413f3b30f19aLiejun Tao mLastLocalVolume = targetVolIndex; 48911798b011c962b602217b479130d413f3b30f19aLiejun Tao } else { 49011798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.d(TAG, "setVolumeNative failed"); 49117675906064bb72fdcca75baa56cdf8bb8968d01John Du } 49217675906064bb72fdcca75baa56cdf8bb8968d01John Du } else { 49317675906064bb72fdcca75baa56cdf8bb8968d01John Du Log.e(TAG, "Unknown direction in MESSAGE_ADJUST_VOLUME"); 49417675906064bb72fdcca75baa56cdf8bb8968d01John Du } 49517675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 49617675906064bb72fdcca75baa56cdf8bb8968d01John Du 49717675906064bb72fdcca75baa56cdf8bb8968d01John Du case MESSAGE_SET_ABSOLUTE_VOLUME: 49811798b011c962b602217b479130d413f3b30f19aLiejun Tao if (!isAbsoluteVolumeSupported()) { 49911798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.v(TAG, "ignore MESSAGE_SET_ABSOLUTE_VOLUME"); 50011798b011c962b602217b479130d413f3b30f19aLiejun Tao break; 50111798b011c962b602217b479130d413f3b30f19aLiejun Tao } 50211798b011c962b602217b479130d413f3b30f19aLiejun Tao 50317675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.v(TAG, "MESSAGE_SET_ABSOLUTE_VOLUME"); 50411798b011c962b602217b479130d413f3b30f19aLiejun Tao 50511798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mVolCmdSetInProgress || mVolCmdAdjustInProgress) { 50617675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.w(TAG, "There is already a volume command in progress."); 50717675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 50817675906064bb72fdcca75baa56cdf8bb8968d01John Du } 50911798b011c962b602217b479130d413f3b30f19aLiejun Tao 51011798b011c962b602217b479130d413f3b30f19aLiejun Tao // Remote device didn't set initial volume. Let's black list it 51111798b011c962b602217b479130d413f3b30f19aLiejun Tao if (mInitialRemoteVolume == -1) { 51211798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.d(TAG, "remote " + mAddress + " never tell us initial volume, black list it."); 51311798b011c962b602217b479130d413f3b30f19aLiejun Tao blackListCurrentDevice(); 51411798b011c962b602217b479130d413f3b30f19aLiejun Tao break; 51511798b011c962b602217b479130d413f3b30f19aLiejun Tao } 51611798b011c962b602217b479130d413f3b30f19aLiejun Tao 51711798b011c962b602217b479130d413f3b30f19aLiejun Tao int avrcpVolume = convertToAvrcpVolume(msg.arg1); 51811798b011c962b602217b479130d413f3b30f19aLiejun Tao avrcpVolume = Math.min(AVRCP_MAX_VOL, Math.max(0, avrcpVolume)); 5190fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (DEBUG) Log.d(TAG, "Setting volume to " + msg.arg1 + "-" + avrcpVolume); 52011798b011c962b602217b479130d413f3b30f19aLiejun Tao if (setVolumeNative(avrcpVolume)) { 52117675906064bb72fdcca75baa56cdf8bb8968d01John Du sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY); 52211798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolCmdSetInProgress = true; 52311798b011c962b602217b479130d413f3b30f19aLiejun Tao mLastRemoteVolume = avrcpVolume; 52411798b011c962b602217b479130d413f3b30f19aLiejun Tao mLastLocalVolume = msg.arg1; 52511798b011c962b602217b479130d413f3b30f19aLiejun Tao } else { 52611798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.d(TAG, "setVolumeNative failed"); 52717675906064bb72fdcca75baa56cdf8bb8968d01John Du } 52817675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 52917675906064bb72fdcca75baa56cdf8bb8968d01John Du 53017675906064bb72fdcca75baa56cdf8bb8968d01John Du case MESSAGE_ABS_VOL_TIMEOUT: 53117675906064bb72fdcca75baa56cdf8bb8968d01John Du if (DEBUG) Log.v(TAG, "MESSAGE_ABS_VOL_TIMEOUT: Volume change cmd timed out."); 53211798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolCmdAdjustInProgress = false; 53311798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolCmdSetInProgress = false; 53417675906064bb72fdcca75baa56cdf8bb8968d01John Du if (mAbsVolRetryTimes >= MAX_ERROR_RETRY_TIMES) { 53517675906064bb72fdcca75baa56cdf8bb8968d01John Du mAbsVolRetryTimes = 0; 5362583f09407c8265c12d198d408692c75eabf22a3Liejun Tao /* too many volume change failures, black list the device */ 5372583f09407c8265c12d198d408692c75eabf22a3Liejun Tao blackListCurrentDevice(); 53817675906064bb72fdcca75baa56cdf8bb8968d01John Du } else { 53917675906064bb72fdcca75baa56cdf8bb8968d01John Du mAbsVolRetryTimes += 1; 54011798b011c962b602217b479130d413f3b30f19aLiejun Tao if (setVolumeNative(mLastRemoteVolume)) { 54117675906064bb72fdcca75baa56cdf8bb8968d01John Du sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT), 54217675906064bb72fdcca75baa56cdf8bb8968d01John Du CMD_TIMEOUT_DELAY); 54311798b011c962b602217b479130d413f3b30f19aLiejun Tao mVolCmdSetInProgress = true; 54417675906064bb72fdcca75baa56cdf8bb8968d01John Du } 54517675906064bb72fdcca75baa56cdf8bb8968d01John Du } 54617675906064bb72fdcca75baa56cdf8bb8968d01John Du break; 54717675906064bb72fdcca75baa56cdf8bb8968d01John Du 548ace834feb02adabd61f628c4471147aea02d939cJohn Du case MESSAGE_FAST_FORWARD: 549ace834feb02adabd61f628c4471147aea02d939cJohn Du case MESSAGE_REWIND: 5502fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if (msg.what == MESSAGE_FAST_FORWARD) { 5512fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if ((mCurrentPlayState.getActions() & 5522fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen PlaybackState.ACTION_FAST_FORWARD) != 0) { 5532fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen int keyState = msg.arg1 == KEY_STATE_PRESS ? 5542fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP; 5552fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen KeyEvent keyEvent = 5562fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen new KeyEvent(keyState, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD); 5572fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mMediaController.dispatchMediaButtonEvent(keyEvent); 5582fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen break; 559881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu } 5602fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen } else if ((mCurrentPlayState.getActions() & 5612fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen PlaybackState.ACTION_REWIND) != 0) { 562881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu int keyState = msg.arg1 == KEY_STATE_PRESS ? 5632fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP; 564881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu KeyEvent keyEvent = 5652fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen new KeyEvent(keyState, KeyEvent.KEYCODE_MEDIA_REWIND); 5662fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mMediaController.dispatchMediaButtonEvent(keyEvent); 567881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu break; 568881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu } 569881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu 57019e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu int skipAmount; 571ace834feb02adabd61f628c4471147aea02d939cJohn Du if (msg.what == MESSAGE_FAST_FORWARD) { 572ace834feb02adabd61f628c4471147aea02d939cJohn Du if (DEBUG) Log.v(TAG, "MESSAGE_FAST_FORWARD"); 573881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu removeMessages(MESSAGE_FAST_FORWARD); 574ace834feb02adabd61f628c4471147aea02d939cJohn Du skipAmount = BASE_SKIP_AMOUNT; 575ace834feb02adabd61f628c4471147aea02d939cJohn Du } else { 576ace834feb02adabd61f628c4471147aea02d939cJohn Du if (DEBUG) Log.v(TAG, "MESSAGE_REWIND"); 577881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu removeMessages(MESSAGE_REWIND); 578ace834feb02adabd61f628c4471147aea02d939cJohn Du skipAmount = -BASE_SKIP_AMOUNT; 579ace834feb02adabd61f628c4471147aea02d939cJohn Du } 580ace834feb02adabd61f628c4471147aea02d939cJohn Du 58119e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu if (hasMessages(MESSAGE_CHANGE_PLAY_POS) && 58219e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu (skipAmount != mSkipAmount)) { 58319e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu Log.w(TAG, "missing release button event:" + mSkipAmount); 58419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu } 58519e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu 58619e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu if ((!hasMessages(MESSAGE_CHANGE_PLAY_POS)) || 58719e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu (skipAmount != mSkipAmount)) { 58819e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu mSkipStartTime = SystemClock.elapsedRealtime(); 58919e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu } 59019e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu 59119e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu removeMessages(MESSAGE_CHANGE_PLAY_POS); 592ace834feb02adabd61f628c4471147aea02d939cJohn Du if (msg.arg1 == KEY_STATE_PRESS) { 59319e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu mSkipAmount = skipAmount; 59419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu changePositionBy(mSkipAmount * getSkipMultiplier()); 59519e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS); 59619e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu posMsg.arg1 = 1; 59719e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu sendMessageDelayed(posMsg, SKIP_PERIOD); 598ace834feb02adabd61f628c4471147aea02d939cJohn Du } 599881675b362bde18acbbcf69c513175addca4a8baZhenye Zhu 600ace834feb02adabd61f628c4471147aea02d939cJohn Du break; 601ace834feb02adabd61f628c4471147aea02d939cJohn Du 60219e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu case MESSAGE_CHANGE_PLAY_POS: 60319e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu if (DEBUG) Log.v(TAG, "MESSAGE_CHANGE_PLAY_POS:" + msg.arg1); 60419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu changePositionBy(mSkipAmount * getSkipMultiplier()); 60519e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu if (msg.arg1 * SKIP_PERIOD < BUTTON_TIMEOUT_TIME) { 60619e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS); 60719e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu posMsg.arg1 = msg.arg1 + 1; 60819e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu sendMessageDelayed(posMsg, SKIP_PERIOD); 609ace834feb02adabd61f628c4471147aea02d939cJohn Du } 610ace834feb02adabd61f628c4471147aea02d939cJohn Du break; 611188f205b5f093850d4cc627917a21204be36c56aZhihai Xu 612188f205b5f093850d4cc627917a21204be36c56aZhihai Xu case MESSAGE_SET_A2DP_AUDIO_STATE: 613188f205b5f093850d4cc627917a21204be36c56aZhihai Xu if (DEBUG) Log.v(TAG, "MESSAGE_SET_A2DP_AUDIO_STATE:" + msg.arg1); 614188f205b5f093850d4cc627917a21204be36c56aZhihai Xu updateA2dpAudioState(msg.arg1); 615188f205b5f093850d4cc627917a21204be36c56aZhihai Xu break; 616c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 617c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 618c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 619c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 620188f205b5f093850d4cc627917a21204be36c56aZhihai Xu private void updateA2dpAudioState(int state) { 621188f205b5f093850d4cc627917a21204be36c56aZhihai Xu boolean isPlaying = (state == BluetoothA2dp.STATE_PLAYING); 622188f205b5f093850d4cc627917a21204be36c56aZhihai Xu if (isPlaying != isPlayingState(mCurrentPlayState)) { 62322bad7047263a6924423d12718738fdcc7b0352cRavi Nagarajan /* if a2dp is streaming, check to make sure music is active */ 6242fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if (isPlaying && !mAudioManager.isMusicActive()) 62522bad7047263a6924423d12718738fdcc7b0352cRavi Nagarajan return; 6262fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen PlaybackState.Builder builder = new PlaybackState.Builder(); 6272fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if (isPlaying) { 6282fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen builder.setState(PlaybackState.STATE_PLAYING, 6292fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f); 6302fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen } else { 6312fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen builder.setState(PlaybackState.STATE_PAUSED, 6322fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f); 6332fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen } 634eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen updatePlaybackState(builder.build()); 635188f205b5f093850d4cc627917a21204be36c56aZhihai Xu } 636188f205b5f093850d4cc627917a21204be36c56aZhihai Xu } 637188f205b5f093850d4cc627917a21204be36c56aZhihai Xu 638eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen private void updatePlaybackState(PlaybackState state) { 6392fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if (state == null) { 6402fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen state = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, 6412fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build(); 6422fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen } 643eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen 6447d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState); 645c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu int newPlayStatus = convertPlayStateToPlayStatus(state); 646f56b7b37a156d9207074af80c156db5884bb8c08Zhihai Xu 6477d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen if (DEBUG) { 6487d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen Log.v(TAG, "updatePlaybackState (" + mPlayStatusChangedNT + "): "+ 6497d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen "old=" + mCurrentPlayState + "(" + oldPlayStatus + "), "+ 6507d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen "new=" + state + "(" + newPlayStatus + ")"); 6517d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen } 6527d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen 653aa6c1cb7f08a5d1fe2c878b587c62cf4dbb6ee8fZhihai Xu mCurrentPlayState = state; 654eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen mLastStateUpdate = SystemClock.elapsedRealtime(); 655aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 656eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen sendPlayPosNotificationRsp(false); 657aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 6587d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen if (mPlayStatusChangedNT == NOTIFICATION_TYPE_INTERIM && 6597d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen (oldPlayStatus != newPlayStatus)) { 660c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED; 661c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, newPlayStatus); 662c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 663c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 664c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 665c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void updateTransportControls(int transportControlFlags) { 666c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mTransportControlFlags = transportControlFlags; 667c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 668c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 6690fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen class MediaAttributes { 6700fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private boolean exists; 6710fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private String title; 6720fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private String artistName; 6730fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private String albumName; 6740fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private String mediaNumber; 6750fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private String mediaTotalNumber; 6760fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private String genre; 6770fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private String playingTimeMs; 6780fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 6790fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private static final int ATTR_TITLE = 1; 6800fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private static final int ATTR_ARTIST_NAME = 2; 6810fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private static final int ATTR_ALBUM_NAME = 3; 6820fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private static final int ATTR_MEDIA_NUMBER = 4; 6830fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private static final int ATTR_MEDIA_TOTAL_NUMBER = 5; 6840fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private static final int ATTR_GENRE = 6; 6850fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private static final int ATTR_PLAYING_TIME_MS = 7; 6860fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 6870fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 6880fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen public MediaAttributes(MediaMetadata data) { 6890fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen exists = data != null; 6900fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (!exists) 6910fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return; 6920fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 6930fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen artistName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ARTIST)); 6940fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen albumName = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_ALBUM)); 6950fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen mediaNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER)); 6960fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen mediaTotalNumber = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS)); 6970fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen genre = stringOrBlank(data.getString(MediaMetadata.METADATA_KEY_GENRE)); 6980fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen playingTimeMs = longStringOrBlank(data.getLong(MediaMetadata.METADATA_KEY_DURATION)); 6990fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 7000fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen // Try harder for the title. 7010fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen title = data.getString(MediaMetadata.METADATA_KEY_TITLE); 7020fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 7030fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (title == null) { 7040fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen MediaDescription desc = data.getDescription(); 7050fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (desc != null) { 7060fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen CharSequence val = desc.getDescription(); 7070fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (val != null) 7080fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen title = val.toString(); 7090fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen } 7100fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen } 7110fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 7120fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (title == null) 7130fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen title = new String(); 7140fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen } 7150fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 7160fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen public boolean equals(MediaAttributes other) { 7170fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (other == null) 7180fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return false; 7190fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 7200fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (exists != other.exists) 7210fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return false; 7220fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 7230fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (exists == false) 7240fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return true; 7250fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 7260fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return (title.equals(other.title)) && 7270fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen (artistName.equals(other.artistName)) && 7280fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen (albumName.equals(other.albumName)) && 7290fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen (mediaNumber.equals(other.mediaNumber)) && 7300fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen (mediaTotalNumber.equals(other.mediaTotalNumber)) && 7310fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen (genre.equals(other.genre)) && 7320fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen (playingTimeMs.equals(other.playingTimeMs)); 7330fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen } 7340fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 7350fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen public String getString(int attrId) { 7360fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (!exists) 7370fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return new String(); 7380fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 7390fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen switch (attrId) { 7400fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen case ATTR_TITLE: 7410fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return title; 7420fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen case ATTR_ARTIST_NAME: 7430fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return artistName; 7440fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen case ATTR_ALBUM_NAME: 7450fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return albumName; 7460fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen case ATTR_MEDIA_NUMBER: 7470fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return mediaNumber; 7480fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen case ATTR_MEDIA_TOTAL_NUMBER: 7490fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return mediaTotalNumber; 7500fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen case ATTR_GENRE: 7510fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return genre; 7520fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen case ATTR_PLAYING_TIME_MS: 7530fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return playingTimeMs; 7540fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen default: 7550fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return new String(); 7560fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen } 7570fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen } 7580fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 7590fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private String stringOrBlank(String s) { 7600fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return s == null ? new String() : s; 7610fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen } 762c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 7630fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen private String longStringOrBlank(Long s) { 7640fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return s == null ? new String() : s.toString(); 765c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 766c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 767c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu public String toString() { 7680fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (!exists) 7690fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return "[MediaAttributes: none]"; 7700fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen 7710fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen return "[MediaAttributes: " + title + " - " + albumName + " by " 7720fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen + artistName + " (" + mediaNumber + "/" + mediaTotalNumber + ") " 7730fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen + genre + "]"; 774c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 775c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 776c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 7772fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen private void updateMetadata(MediaMetadata data) { 7780fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen MediaAttributes oldAttributes = mMediaAttributes; 7790fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen mMediaAttributes = new MediaAttributes(data); 7802fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if (data == null) { 7812fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mSongLengthMs = 0L; 7822fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen } else { 7832fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mSongLengthMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION); 7842fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen } 7850fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen if (!oldAttributes.equals(mMediaAttributes)) { 7860fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen Log.v(TAG, "MediaAttributes Changed to " + mMediaAttributes.toString()); 787c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mTrackNumber++; 788eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen 789c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu if (mTrackChangedNT == NOTIFICATION_TYPE_INTERIM) { 790c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mTrackChangedNT = NOTIFICATION_TYPE_CHANGED; 791c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu sendTrackChangedRsp(); 792c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 79365e7943d098113c5aa56e9822b68f0c51c6dbe36Marie Janssen } else { 7940fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen Log.v(TAG, "Updated " + mMediaAttributes.toString() + " but no change!"); 795c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 796aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 7977d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen // Update the play state, which sends play state and play position 7987d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen // notifications if needed. 7997d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen if (mMediaController != null) { 8007d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen updatePlaybackState(mMediaController.getPlaybackState()); 8017d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen } else { 8027d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen updatePlaybackState(null); 8037d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen } 804c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 805c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 80617675906064bb72fdcca75baa56cdf8bb8968d01John Du private void getRcFeatures(byte[] address, int features) { 80717675906064bb72fdcca75baa56cdf8bb8968d01John Du Message msg = mHandler.obtainMessage(MESSAGE_GET_RC_FEATURES, features, 0, 80817675906064bb72fdcca75baa56cdf8bb8968d01John Du Utils.getAddressStringFromByte(address)); 80917675906064bb72fdcca75baa56cdf8bb8968d01John Du mHandler.sendMessage(msg); 81017675906064bb72fdcca75baa56cdf8bb8968d01John Du } 81117675906064bb72fdcca75baa56cdf8bb8968d01John Du 812c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void getPlayStatus() { 813c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Message msg = mHandler.obtainMessage(MESSAGE_GET_PLAY_STATUS); 814c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mHandler.sendMessage(msg); 815c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 816c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 817c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void getElementAttr(byte numAttr, int[] attrs) { 818c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu int i; 819c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu ArrayList<Integer> attrList = new ArrayList<Integer>(); 820c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu for (i = 0; i < numAttr; ++i) { 821c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu attrList.add(attrs[i]); 822c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 8236e29e12add362546784126119f26f04fc760f021RoboErik Message msg = mHandler.obtainMessage(MESSAGE_GET_ELEM_ATTRS, numAttr, 0, attrList); 824c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mHandler.sendMessage(msg); 825c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 826c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 827c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void registerNotification(int eventId, int param) { 828c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_NOTIFICATION, eventId, param); 829c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mHandler.sendMessage(msg); 830c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 831c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 832c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void processRegisterNotification(int eventId, int param) { 833c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu switch (eventId) { 834c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case EVT_PLAY_STATUS_CHANGED: 835c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mPlayStatusChangedNT = NOTIFICATION_TYPE_INTERIM; 836c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, 8372fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen convertPlayStateToPlayStatus(mCurrentPlayState)); 838c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 839c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 840c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu case EVT_TRACK_CHANGED: 841c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu mTrackChangedNT = NOTIFICATION_TYPE_INTERIM; 842c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu sendTrackChangedRsp(); 843c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 844c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 845aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu case EVT_PLAY_POS_CHANGED: 846aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlayPosChangedNT = NOTIFICATION_TYPE_INTERIM; 847aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu mPlaybackIntervalMs = (long)param * 1000L; 8487d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen sendPlayPosNotificationRsp(true); 849aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu break; 850aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 851c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 852c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 853c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 854ace834feb02adabd61f628c4471147aea02d939cJohn Du private void handlePassthroughCmd(int id, int keyState) { 855ace834feb02adabd61f628c4471147aea02d939cJohn Du switch (id) { 856066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood case BluetoothAvrcp.PASSTHROUGH_ID_REWIND: 857ace834feb02adabd61f628c4471147aea02d939cJohn Du rewind(keyState); 858ace834feb02adabd61f628c4471147aea02d939cJohn Du break; 859066ad9e16a548218b139424f758b92db7af34af2Mike Lockwood case BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR: 860ace834feb02adabd61f628c4471147aea02d939cJohn Du fastForward(keyState); 861ace834feb02adabd61f628c4471147aea02d939cJohn Du break; 862ace834feb02adabd61f628c4471147aea02d939cJohn Du } 863ace834feb02adabd61f628c4471147aea02d939cJohn Du } 864ace834feb02adabd61f628c4471147aea02d939cJohn Du 865ace834feb02adabd61f628c4471147aea02d939cJohn Du private void fastForward(int keyState) { 866ace834feb02adabd61f628c4471147aea02d939cJohn Du Message msg = mHandler.obtainMessage(MESSAGE_FAST_FORWARD, keyState, 0); 867ace834feb02adabd61f628c4471147aea02d939cJohn Du mHandler.sendMessage(msg); 868ace834feb02adabd61f628c4471147aea02d939cJohn Du } 869ace834feb02adabd61f628c4471147aea02d939cJohn Du 870ace834feb02adabd61f628c4471147aea02d939cJohn Du private void rewind(int keyState) { 871ace834feb02adabd61f628c4471147aea02d939cJohn Du Message msg = mHandler.obtainMessage(MESSAGE_REWIND, keyState, 0); 872ace834feb02adabd61f628c4471147aea02d939cJohn Du mHandler.sendMessage(msg); 873ace834feb02adabd61f628c4471147aea02d939cJohn Du } 874ace834feb02adabd61f628c4471147aea02d939cJohn Du 875ace834feb02adabd61f628c4471147aea02d939cJohn Du private void changePositionBy(long amount) { 876ace834feb02adabd61f628c4471147aea02d939cJohn Du long currentPosMs = getPlayPosition(); 877ace834feb02adabd61f628c4471147aea02d939cJohn Du if (currentPosMs == -1L) return; 878ace834feb02adabd61f628c4471147aea02d939cJohn Du long newPosMs = Math.max(0L, currentPosMs + amount); 8792fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen mMediaController.getTransportControls().seekTo(newPosMs); 880ace834feb02adabd61f628c4471147aea02d939cJohn Du } 881ace834feb02adabd61f628c4471147aea02d939cJohn Du 882ace834feb02adabd61f628c4471147aea02d939cJohn Du private int getSkipMultiplier() { 883ace834feb02adabd61f628c4471147aea02d939cJohn Du long currentTime = SystemClock.elapsedRealtime(); 88419e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu long multi = (long) Math.pow(2, (currentTime - mSkipStartTime)/SKIP_DOUBLE_INTERVAL); 88519e4c6abe87d6c213e802ecf7af6c1d00e1f4b65Zhihai Xu return (int) Math.min(MAX_MULTIPLIER_VALUE, multi); 886ace834feb02adabd61f628c4471147aea02d939cJohn Du } 887ace834feb02adabd61f628c4471147aea02d939cJohn Du 888c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private void sendTrackChangedRsp() { 889c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu byte[] track = new byte[TRACK_ID_SIZE]; 890e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou 891e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou /* If no track is currently selected, then return 892e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou 0xFFFFFFFFFFFFFFFF in the interim response */ 893e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou long trackNumberRsp = -1L; 894e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou 8952fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen if (isPlayingState(mCurrentPlayState)) { 896e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou trackNumberRsp = mTrackNumber; 897e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou } 898e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou 89979d176b0f3d6cb33c7e52be6641fd4808ba87e93Zhihai Xu /* track is stored in big endian format */ 900c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu for (int i = 0; i < TRACK_ID_SIZE; ++i) { 901e8e870c24930f9b687572dbb80614e5aad6fbdfaberyl hou track[i] = (byte) (trackNumberRsp >> (56 - 8 * i)); 902c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 903c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu registerNotificationRspTrackChangeNative(mTrackChangedNT, track); 904c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 905c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 906aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private long getPlayPosition() { 907eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen if (mCurrentPlayState == null) 908eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen return -1L; 909eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen 910eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen if (mCurrentPlayState.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN) 911eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen return -1L; 912eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen 913eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen if (isPlayingState(mCurrentPlayState)) { 914eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen return SystemClock.elapsedRealtime() - mLastStateUpdate + mCurrentPlayState.getPosition(); 915aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 916eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen 91784d3f084d4d1a65eb7a481e5a7fe4a6ac827be7bMarie Janssen return mCurrentPlayState.getPosition(); 918aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu } 919aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu 9202fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen private int convertPlayStateToPlayStatus(PlaybackState state) { 921c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu int playStatus = PLAYSTATUS_ERROR; 9222fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen switch (state.getState()) { 9232fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen case PlaybackState.STATE_PLAYING: 9242fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen case PlaybackState.STATE_BUFFERING: 925c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_PLAYING; 926c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 927c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 9282fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen case PlaybackState.STATE_STOPPED: 9292fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen case PlaybackState.STATE_NONE: 930c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_STOPPED; 931c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 932c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 9332fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen case PlaybackState.STATE_PAUSED: 934c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_PAUSED; 935c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 936c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 9372fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen case PlaybackState.STATE_FAST_FORWARDING: 9382fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen case PlaybackState.STATE_SKIPPING_TO_NEXT: 9392fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM: 940c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_FWD_SEEK; 941c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 942c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 9432fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen case PlaybackState.STATE_REWINDING: 9442fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen case PlaybackState.STATE_SKIPPING_TO_PREVIOUS: 945c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_REV_SEEK; 946c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 947c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 9482fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen case PlaybackState.STATE_ERROR: 949c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu playStatus = PLAYSTATUS_ERROR; 950c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu break; 951c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 952c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 953c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu return playStatus; 954c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu } 955c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 9562fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen private boolean isPlayingState(PlaybackState state) { 9572fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen return (state.getState() == PlaybackState.STATE_PLAYING) || 9582fc493d0ea2b504df25d783a488dfadfe301329eMarie Janssen (state.getState() == PlaybackState.STATE_BUFFERING); 959188f205b5f093850d4cc627917a21204be36c56aZhihai Xu } 960188f205b5f093850d4cc627917a21204be36c56aZhihai Xu 96117675906064bb72fdcca75baa56cdf8bb8968d01John Du /** 962eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen * Sends a play position notification, or schedules one to be 963eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen * sent later at an appropriate time. If |requested| is true, 964eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen * does both because this was called in reponse to a request from the 965eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen * TG. 966eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen */ 967eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen private void sendPlayPosNotificationRsp(boolean requested) { 9687d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen if (!requested && mPlayPosChangedNT != NOTIFICATION_TYPE_INTERIM) { 9697d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: Not registered or requesting."); 9707d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen return; 9717d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen } 9727d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen 973eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen long playPositionMs = getPlayPosition(); 974eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen 975eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen // mNextPosMs is set to -1 when the previous position was invalid 976eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen // so this will be true if the new position is valid & old was invalid. 977eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen // mPlayPositionMs is set to -1 when the new position is invalid, 978eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen // and the old mPrevPosMs is >= 0 so this is true when the new is invalid 979eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen // and the old was valid. 9807d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: (" + requested + ") " 9817d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen + mPrevPosMs + " <=? " + playPositionMs + " <=? " + mNextPosMs); 9827d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen if (requested || ((mLastReportedPosition != playPositionMs) && 9837d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen (playPositionMs >= mNextPosMs) || (playPositionMs <= mPrevPosMs))) { 984eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen if (!requested) mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED; 9857d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)playPositionMs); 9867d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen mLastReportedPosition = playPositionMs; 987eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen if (playPositionMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) { 988eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen mNextPosMs = playPositionMs + mPlaybackIntervalMs; 989eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen mPrevPosMs = playPositionMs - mPlaybackIntervalMs; 990eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen } else { 991eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen mNextPosMs = -1; 992eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen mPrevPosMs = -1; 993eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen } 994eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen } 995eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen 996eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT); 9977d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen if (mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM && isPlayingState(mCurrentPlayState)) { 998eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT); 999eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen long delay = mPlaybackIntervalMs; 1000eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen if (mNextPosMs != -1) { 1001eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen delay = mNextPosMs - (playPositionMs > 0 ? playPositionMs : 0); 1002eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen } 10037d4aa832cb9a8a9f21ce0fad5510ae82526c3d28Marie Janssen if (DEBUG) Log.d(TAG, "PLAY_INTERVAL_TIMEOUT set for " + delay + "ms from now"); 1004eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen mHandler.sendMessageDelayed(msg, delay); 1005eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen } 1006eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen } 1007eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen 1008eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen /** 100917675906064bb72fdcca75baa56cdf8bb8968d01John Du * This is called from AudioService. It will return whether this device supports abs volume. 101017675906064bb72fdcca75baa56cdf8bb8968d01John Du * NOT USED AT THE MOMENT. 101117675906064bb72fdcca75baa56cdf8bb8968d01John Du */ 101217675906064bb72fdcca75baa56cdf8bb8968d01John Du public boolean isAbsoluteVolumeSupported() { 101317675906064bb72fdcca75baa56cdf8bb8968d01John Du return ((mFeatures & BTRC_FEAT_ABSOLUTE_VOLUME) != 0); 101417675906064bb72fdcca75baa56cdf8bb8968d01John Du } 101517675906064bb72fdcca75baa56cdf8bb8968d01John Du 101617675906064bb72fdcca75baa56cdf8bb8968d01John Du /** 101717675906064bb72fdcca75baa56cdf8bb8968d01John Du * We get this call from AudioService. This will send a message to our handler object, 101817675906064bb72fdcca75baa56cdf8bb8968d01John Du * requesting our handler to call setVolumeNative() 101917675906064bb72fdcca75baa56cdf8bb8968d01John Du */ 102017675906064bb72fdcca75baa56cdf8bb8968d01John Du public void adjustVolume(int direction) { 102117675906064bb72fdcca75baa56cdf8bb8968d01John Du Message msg = mHandler.obtainMessage(MESSAGE_ADJUST_VOLUME, direction, 0); 102217675906064bb72fdcca75baa56cdf8bb8968d01John Du mHandler.sendMessage(msg); 102317675906064bb72fdcca75baa56cdf8bb8968d01John Du } 102417675906064bb72fdcca75baa56cdf8bb8968d01John Du 102517675906064bb72fdcca75baa56cdf8bb8968d01John Du public void setAbsoluteVolume(int volume) { 102611798b011c962b602217b479130d413f3b30f19aLiejun Tao if (volume == mLocalVolume) { 102711798b011c962b602217b479130d413f3b30f19aLiejun Tao if (DEBUG) Log.v(TAG, "setAbsoluteVolume is setting same index, ignore "+volume); 102811798b011c962b602217b479130d413f3b30f19aLiejun Tao return; 102911798b011c962b602217b479130d413f3b30f19aLiejun Tao } 103011798b011c962b602217b479130d413f3b30f19aLiejun Tao 103117675906064bb72fdcca75baa56cdf8bb8968d01John Du mHandler.removeMessages(MESSAGE_ADJUST_VOLUME); 103211798b011c962b602217b479130d413f3b30f19aLiejun Tao Message msg = mHandler.obtainMessage(MESSAGE_SET_ABSOLUTE_VOLUME, volume, 0); 103317675906064bb72fdcca75baa56cdf8bb8968d01John Du mHandler.sendMessage(msg); 10345c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta } 10355c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta 103617675906064bb72fdcca75baa56cdf8bb8968d01John Du /* Called in the native layer as a btrc_callback to return the volume set on the carkit in the 103717675906064bb72fdcca75baa56cdf8bb8968d01John Du * case when the volume is change locally on the carkit. This notification is not called when 103817675906064bb72fdcca75baa56cdf8bb8968d01John Du * the volume is changed from the phone. 103917675906064bb72fdcca75baa56cdf8bb8968d01John Du * 104017675906064bb72fdcca75baa56cdf8bb8968d01John Du * This method will send a message to our handler to change the local stored volume and notify 104117675906064bb72fdcca75baa56cdf8bb8968d01John Du * AudioService to update the UI 104217675906064bb72fdcca75baa56cdf8bb8968d01John Du */ 104317675906064bb72fdcca75baa56cdf8bb8968d01John Du private void volumeChangeCallback(int volume, int ctype) { 104417675906064bb72fdcca75baa56cdf8bb8968d01John Du Message msg = mHandler.obtainMessage(MESSAGE_VOLUME_CHANGED, volume, ctype); 104517675906064bb72fdcca75baa56cdf8bb8968d01John Du mHandler.sendMessage(msg); 104617675906064bb72fdcca75baa56cdf8bb8968d01John Du } 104717675906064bb72fdcca75baa56cdf8bb8968d01John Du 10482e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie private void notifyVolumeChanged(int volume) { 10492e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 10502e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME); 105117675906064bb72fdcca75baa56cdf8bb8968d01John Du } 105217675906064bb72fdcca75baa56cdf8bb8968d01John Du 105317675906064bb72fdcca75baa56cdf8bb8968d01John Du private int convertToAudioStreamVolume(int volume) { 105417675906064bb72fdcca75baa56cdf8bb8968d01John Du // Rescale volume to match AudioSystem's volume 105511798b011c962b602217b479130d413f3b30f19aLiejun Tao return (int) Math.floor((double) volume*mAudioStreamMax/AVRCP_MAX_VOL); 105617675906064bb72fdcca75baa56cdf8bb8968d01John Du } 105717675906064bb72fdcca75baa56cdf8bb8968d01John Du 105817675906064bb72fdcca75baa56cdf8bb8968d01John Du private int convertToAvrcpVolume(int volume) { 10592e90040ffc6f1c4cd5187338c9f708df4d380aeeMatthew Xie return (int) Math.ceil((double) volume*AVRCP_MAX_VOL/mAudioStreamMax); 106017675906064bb72fdcca75baa56cdf8bb8968d01John Du } 106117675906064bb72fdcca75baa56cdf8bb8968d01John Du 106211798b011c962b602217b479130d413f3b30f19aLiejun Tao private void blackListCurrentDevice() { 106311798b011c962b602217b479130d413f3b30f19aLiejun Tao mFeatures &= ~BTRC_FEAT_ABSOLUTE_VOLUME; 106411798b011c962b602217b479130d413f3b30f19aLiejun Tao mAudioManager.avrcpSupportsAbsoluteVolume(mAddress, isAbsoluteVolumeSupported()); 106511798b011c962b602217b479130d413f3b30f19aLiejun Tao 106611798b011c962b602217b479130d413f3b30f19aLiejun Tao SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, 106711798b011c962b602217b479130d413f3b30f19aLiejun Tao Context.MODE_PRIVATE); 106811798b011c962b602217b479130d413f3b30f19aLiejun Tao SharedPreferences.Editor editor = pref.edit(); 106911798b011c962b602217b479130d413f3b30f19aLiejun Tao editor.putBoolean(mAddress, true); 107011798b011c962b602217b479130d413f3b30f19aLiejun Tao editor.commit(); 107111798b011c962b602217b479130d413f3b30f19aLiejun Tao } 107211798b011c962b602217b479130d413f3b30f19aLiejun Tao 107311798b011c962b602217b479130d413f3b30f19aLiejun Tao private int modifyRcFeatureFromBlacklist(int feature, String address) { 107411798b011c962b602217b479130d413f3b30f19aLiejun Tao SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, 107511798b011c962b602217b479130d413f3b30f19aLiejun Tao Context.MODE_PRIVATE); 107611798b011c962b602217b479130d413f3b30f19aLiejun Tao if (!pref.contains(address)) { 107711798b011c962b602217b479130d413f3b30f19aLiejun Tao return feature; 107811798b011c962b602217b479130d413f3b30f19aLiejun Tao } 107911798b011c962b602217b479130d413f3b30f19aLiejun Tao if (pref.getBoolean(address, false)) { 108011798b011c962b602217b479130d413f3b30f19aLiejun Tao feature &= ~BTRC_FEAT_ABSOLUTE_VOLUME; 108111798b011c962b602217b479130d413f3b30f19aLiejun Tao } 108211798b011c962b602217b479130d413f3b30f19aLiejun Tao return feature; 108311798b011c962b602217b479130d413f3b30f19aLiejun Tao } 108411798b011c962b602217b479130d413f3b30f19aLiejun Tao 108511798b011c962b602217b479130d413f3b30f19aLiejun Tao public void resetBlackList(String address) { 108611798b011c962b602217b479130d413f3b30f19aLiejun Tao SharedPreferences pref = mContext.getSharedPreferences(ABSOLUTE_VOLUME_BLACKLIST, 108711798b011c962b602217b479130d413f3b30f19aLiejun Tao Context.MODE_PRIVATE); 108811798b011c962b602217b479130d413f3b30f19aLiejun Tao SharedPreferences.Editor editor = pref.edit(); 108911798b011c962b602217b479130d413f3b30f19aLiejun Tao editor.remove(address); 109011798b011c962b602217b479130d413f3b30f19aLiejun Tao editor.commit(); 109111798b011c962b602217b479130d413f3b30f19aLiejun Tao } 109211798b011c962b602217b479130d413f3b30f19aLiejun Tao 1093188f205b5f093850d4cc627917a21204be36c56aZhihai Xu /** 1094188f205b5f093850d4cc627917a21204be36c56aZhihai Xu * This is called from A2dpStateMachine to set A2dp audio state. 1095188f205b5f093850d4cc627917a21204be36c56aZhihai Xu */ 1096188f205b5f093850d4cc627917a21204be36c56aZhihai Xu public void setA2dpAudioState(int state) { 1097188f205b5f093850d4cc627917a21204be36c56aZhihai Xu Message msg = mHandler.obtainMessage(MESSAGE_SET_A2DP_AUDIO_STATE, state, 0); 1098188f205b5f093850d4cc627917a21204be36c56aZhihai Xu mHandler.sendMessage(msg); 1099188f205b5f093850d4cc627917a21204be36c56aZhihai Xu } 1100188f205b5f093850d4cc627917a21204be36c56aZhihai Xu 1101838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood public void dump(StringBuilder sb) { 1102838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood sb.append("AVRCP:\n"); 11030fcd081cccbf624a3a886fe4eb68adc3498e695cMarie Janssen ProfileService.println(sb, "mMediaAttributes: " + mMediaAttributes); 1104838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags); 1105838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState); 1106eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen ProfileService.println(sb, "mLastStateUpdate: " + mLastStateUpdate); 1107838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT); 1108838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT); 1109838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mTrackNumber: " + mTrackNumber); 1110838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mSongLengthMs: " + mSongLengthMs); 1111838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs); 1112838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT); 1113838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mNextPosMs: " + mNextPosMs); 1114838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mPrevPosMs: " + mPrevPosMs); 1115838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mSkipStartTime: " + mSkipStartTime); 1116838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mFeatures: " + mFeatures); 111711798b011c962b602217b479130d413f3b30f19aLiejun Tao ProfileService.println(sb, "mRemoteVolume: " + mRemoteVolume); 111811798b011c962b602217b479130d413f3b30f19aLiejun Tao ProfileService.println(sb, "mLastRemoteVolume: " + mLastRemoteVolume); 1119838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mLastDirection: " + mLastDirection); 1120838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mVolumeStep: " + mVolumeStep); 1121838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mAudioStreamMax: " + mAudioStreamMax); 112211798b011c962b602217b479130d413f3b30f19aLiejun Tao ProfileService.println(sb, "mVolCmdAdjustInProgress: " + mVolCmdAdjustInProgress); 112311798b011c962b602217b479130d413f3b30f19aLiejun Tao ProfileService.println(sb, "mVolCmdSetInProgress: " + mVolCmdSetInProgress); 1124838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mAbsVolRetryTimes: " + mAbsVolRetryTimes); 1125838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood ProfileService.println(sb, "mSkipAmount: " + mSkipAmount); 112611798b011c962b602217b479130d413f3b30f19aLiejun Tao ProfileService.println(sb, "mVolumeMapping: " + mVolumeMapping.toString()); 1127eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen if (mMediaController != null) 1128eb9e6ef0ecde4929fa2df1aa4cc8954d88d3b452Marie Janssen ProfileService.println(sb, "mMediaSession pkg: " + mMediaController.getPackageName()); 1129838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 1130838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood 1131c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // Do not modify without updating the HAL bt_rc.h files. 1132c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 1133c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // match up with btrc_play_status_t enum of bt_rc.h 1134c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_STOPPED = 0; 1135c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_PLAYING = 1; 1136c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_PAUSED = 2; 1137c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_FWD_SEEK = 3; 1138c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_REV_SEEK = 4; 1139c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int PLAYSTATUS_ERROR = 255; 1140c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 1141c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // match up with btrc_media_attr_t enum of bt_rc.h 1142c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_TITLE = 1; 1143c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_ARTIST = 2; 1144c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_ALBUM = 3; 1145c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_TRACK_NUM = 4; 1146c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_NUM_TRACKS = 5; 1147c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_GENRE = 6; 1148c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int MEDIA_ATTR_PLAYING_TIME = 7; 1149c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 1150c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // match up with btrc_event_id_t enum of bt_rc.h 1151c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_PLAY_STATUS_CHANGED = 1; 1152c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_TRACK_CHANGED = 2; 1153c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_TRACK_REACHED_END = 3; 1154c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_TRACK_REACHED_START = 4; 1155c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_PLAY_POS_CHANGED = 5; 1156c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_BATT_STATUS_CHANGED = 6; 1157c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_SYSTEM_STATUS_CHANGED = 7; 1158c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int EVT_APP_SETTINGS_CHANGED = 8; 1159c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 1160c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // match up with btrc_notification_type_t enum of bt_rc.h 1161c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int NOTIFICATION_TYPE_INTERIM = 0; 1162c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int NOTIFICATION_TYPE_CHANGED = 1; 1163c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 1164c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu // match up with BTRC_UID_SIZE of bt_rc.h 1165c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu final static int TRACK_ID_SIZE = 8; 1166c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu 1167c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native static void classInitNative(); 1168c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native void initNative(); 1169c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native void cleanupNative(); 1170c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native boolean getPlayStatusRspNative(int playStatus, int songLen, int songPos); 1171c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native boolean getElementAttrRspNative(byte numAttr, int[] attrIds, String[] textArray); 1172c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native boolean registerNotificationRspPlayStatusNative(int type, int playStatus); 1173c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu private native boolean registerNotificationRspTrackChangeNative(int type, byte[] track); 1174aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu private native boolean registerNotificationRspPlayPosNative(int type, int playPos); 117517675906064bb72fdcca75baa56cdf8bb8968d01John Du private native boolean setVolumeNative(int volume); 11765c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta private native boolean sendPassThroughCommandNative(int keyCode, int keyState); 11775c86abdc7875a8fae28c57e3e36a0a8eaae5cb04Hemant Gupta 1178c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu} 1179