Expand and improve headset detection

Modify it to mean play through anything but the internal speaker. Should now detect bluetooth and other sinks.

I have not tested this on Android 2.0+. I hope it works...
This commit is contained in:
Christopher Eby 2010-02-27 22:20:43 -06:00
parent a456aa8c04
commit cddfb03627
3 changed files with 52 additions and 27 deletions

View File

@ -13,9 +13,8 @@
<string name="paused">(Paused)</string> <string name="paused">(Paused)</string>
<string name="widget_start_service">Click to start the music service.</string> <string name="widget_start_service">Click to start the music service.</string>
<string name="headset_only_title">Headset only</string> <string name="headset_only_title">Disallow Use of Speaker</string>
<string name="headset_only_summary_on">Audio only plays when a headset is plugged in</string> <string name="headset_only_summary">Do not play music when the speaker would be used</string>
<string name="headset_only_summary_off">Audio may play without a headset plugged in</string>
<string name="remote_player_title">Use Remote Player</string> <string name="remote_player_title">Use Remote Player</string>
<string name="remote_player_summary_on">Clicking the notification will open a mini-player dialog</string> <string name="remote_player_summary_on">Clicking the notification will open a mini-player dialog</string>

View File

@ -6,8 +6,7 @@
android:key="headset_only" android:key="headset_only"
android:title="@string/headset_only_title" android:title="@string/headset_only_title"
android:defaultValue="false" android:defaultValue="false"
android:summaryOn="@string/headset_only_summary_on" android:summary="@string/headset_only_summary" />
android:summaryOff="@string/headset_only_summary_off" />
<CheckBoxPreference <CheckBoxPreference
android:key="remote_player" android:key="remote_player"
android:title="@string/remote_player_title" android:title="@string/remote_player_title"

View File

@ -65,9 +65,6 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
public static final int STATE_PLAYING = 2; public static final int STATE_PLAYING = 2;
private RemoteCallbackList<IMusicPlayerWatcher> mWatchers; private RemoteCallbackList<IMusicPlayerWatcher> mWatchers;
private NotificationManager mNotificationManager;
private Method mStartForeground;
private Method mStopForeground;
public IPlaybackService.Stub mBinder = new IPlaybackService.Stub() { public IPlaybackService.Stub mBinder = new IPlaybackService.Stub() {
public Song[] getCurrentSongs() public Song[] getCurrentSongs()
@ -150,15 +147,6 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
@Override @Override
public void onCreate() public void onCreate()
{ {
mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
mStartForeground = getClass().getMethod("startForeground", new Class[] { int.class, Notification.class });
mStopForeground = getClass().getMethod("stopForeground", new Class[] { boolean.class });
} catch (NoSuchMethodException e) {
// Running on an older platform.
mStartForeground = mStopForeground = null;
}
mWatchers = new RemoteCallbackList<IMusicPlayerWatcher>(); mWatchers = new RemoteCallbackList<IMusicPlayerWatcher>();
new Thread(this).start(); new Thread(this).start();
@ -203,13 +191,12 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
setForeground(true); setForeground(true);
mNotificationManager.notify(id, notification); mNotificationManager.notify(id, notification);
} else { } else {
Object[] startForegroundArgs = { Integer.valueOf(id), notification };
try { try {
mStartForeground.invoke(this, startForegroundArgs); mStartForeground.invoke(this, Integer.valueOf(id), notification);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
Log.w("VanillaMusic", "Unable to invoke startForeground", e); Log.w("VanillaMusic", e);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
Log.w("VanillaMusic", "Unable to invoke startForeground", e); Log.w("VanillaMusic", e);
} }
} }
} }
@ -219,13 +206,12 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
if (mStopForeground == null) { if (mStopForeground == null) {
setForeground(false); setForeground(false);
} else { } else {
Object[] topForegroundArgs = { Boolean.FALSE };
try { try {
mStopForeground.invoke(this, topForegroundArgs); mStopForeground.invoke(this, Boolean.FALSE);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
Log.w("VanillaMusic", "Unable to invoke stopForeground", e); Log.w("VanillaMusic", e);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
Log.w("VanillaMusic", "Unable to invoke stopForeground", e); Log.w("VanillaMusic", e);
} }
} }
} }
@ -304,6 +290,8 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
private PowerManager.WakeLock mWakeLock; private PowerManager.WakeLock mWakeLock;
private Notification mNotification; private Notification mNotification;
private SharedPreferences mSettings; private SharedPreferences mSettings;
private AudioManager mAudioManager;
private NotificationManager mNotificationManager;
private int[] mSongs; private int[] mSongs;
private ArrayList<Song> mSongTimeline; private ArrayList<Song> mSongTimeline;
@ -313,6 +301,12 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
private int mState = STATE_NORMAL; private int mState = STATE_NORMAL;
private boolean mPlayingBeforeCall; private boolean mPlayingBeforeCall;
private Method mIsWiredHeadsetOn;
private Method mIsBluetoothScoOn;
private Method mIsBluetoothA2dpOn;
private Method mStartForeground;
private Method mStopForeground;
private static final int SET_SONG = 0; private static final int SET_SONG = 0;
private static final int PLAY_PAUSE = 1; private static final int PLAY_PAUSE = 1;
private static final int HEADSET_PLUGGED = 2; private static final int HEADSET_PLUGGED = 2;
@ -433,6 +427,23 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(mCallListener, PhoneStateListener.LISTEN_CALL_STATE); telephonyManager.listen(mCallListener, PhoneStateListener.LISTEN_CALL_STATE);
mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
try {
mIsWiredHeadsetOn = mAudioManager.getClass().getMethod("isWiredHeadsetOn", (Class[]) null);
mIsBluetoothScoOn = mAudioManager.getClass().getMethod("isBluetoothScoOn", (Class[]) null);
mIsBluetoothA2dpOn = mAudioManager.getClass().getMethod("isBluetoothA2dpOn", (Class[]) null);
} catch (NoSuchMethodException e) {
Log.d("VanillaMusic", "falling back to pre-2.0 AudioManager APIs");
}
mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
mStartForeground = getClass().getMethod("startForeground", int.class, Notification.class);
mStopForeground = getClass().getMethod("stopForeground", boolean.class);
} catch (NoSuchMethodException e) {
Log.d("VanillaMusic", "falling back to pre-2.0 Service APIs");
}
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setWakeMode(this, PowerManager.PARTIAL_WAKE_LOCK); mMediaPlayer.setWakeMode(this, PowerManager.PARTIAL_WAKE_LOCK);
mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.setOnCompletionListener(this);
@ -455,7 +466,7 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
{ {
if ("headset_only".equals(key)) { if ("headset_only".equals(key)) {
mHeadsetOnly = mSettings.getBoolean(key, false); mHeadsetOnly = mSettings.getBoolean(key, false);
if (mHeadsetOnly && !mPlugged && mMediaPlayer.isPlaying()) if (mHeadsetOnly && isSpeakerOn() && mMediaPlayer.isPlaying())
pause(); pause();
} else if ("remote_player".equals(key)) { } else if ("remote_player".equals(key)) {
mUseRemotePlayer = mSettings.getBoolean(key, true); mUseRemotePlayer = mSettings.getBoolean(key, true);
@ -536,9 +547,25 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
mNotificationManager.notify(NOTIFICATION_ID, mNotification); mNotificationManager.notify(NOTIFICATION_ID, mNotification);
} }
private boolean isSpeakerOn()
{
try {
return !(Boolean)mIsWiredHeadsetOn.invoke(mAudioManager, (Object[])null)
&& !(Boolean)mIsBluetoothScoOn.invoke(mAudioManager, (Object[])null)
&& !(Boolean)mIsBluetoothA2dpOn.invoke(mAudioManager, (Object[])null);
} catch (InvocationTargetException e) {
Log.w("VanillaMusic", e);
} catch (IllegalAccessException e) {
Log.w("VanillaMusic", e);
}
// Why is there no true equivalent to this in Android 2.0?
return (mAudioManager.getRouting(mAudioManager.getMode()) & AudioManager.ROUTE_SPEAKER) != 0;
}
private void play() private void play()
{ {
if (mHeadsetOnly && !mPlugged) if (mHeadsetOnly && isSpeakerOn())
return; return;
mMediaPlayer.start(); mMediaPlayer.start();