From cddfb03627ad7f2009327a6d10f5309200f10cd8 Mon Sep 17 00:00:00 2001 From: Christopher Eby Date: Sat, 27 Feb 2010 22:20:43 -0600 Subject: [PATCH] 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... --- res/values/strings.xml | 5 +- res/xml/preferences.xml | 3 +- src/org/kreed/vanilla/PlaybackService.java | 71 +++++++++++++++------- 3 files changed, 52 insertions(+), 27 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 4d83092a..cfbb8aee 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -13,9 +13,8 @@ (Paused) Click to start the music service. - Headset only - Audio only plays when a headset is plugged in - Audio may play without a headset plugged in + Disallow Use of Speaker + Do not play music when the speaker would be used Use Remote Player Clicking the notification will open a mini-player dialog diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index b96adbcd..533e2eb2 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -6,8 +6,7 @@ android:key="headset_only" android:title="@string/headset_only_title" android:defaultValue="false" - android:summaryOn="@string/headset_only_summary_on" - android:summaryOff="@string/headset_only_summary_off" /> + android:summary="@string/headset_only_summary" /> mWatchers; - private NotificationManager mNotificationManager; - private Method mStartForeground; - private Method mStopForeground; public IPlaybackService.Stub mBinder = new IPlaybackService.Stub() { public Song[] getCurrentSongs() @@ -150,15 +147,6 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On @Override 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(); new Thread(this).start(); @@ -203,13 +191,12 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On setForeground(true); mNotificationManager.notify(id, notification); } else { - Object[] startForegroundArgs = { Integer.valueOf(id), notification }; try { - mStartForeground.invoke(this, startForegroundArgs); + mStartForeground.invoke(this, Integer.valueOf(id), notification); } catch (InvocationTargetException e) { - Log.w("VanillaMusic", "Unable to invoke startForeground", e); + Log.w("VanillaMusic", 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) { setForeground(false); } else { - Object[] topForegroundArgs = { Boolean.FALSE }; try { - mStopForeground.invoke(this, topForegroundArgs); + mStopForeground.invoke(this, Boolean.FALSE); } catch (InvocationTargetException e) { - Log.w("VanillaMusic", "Unable to invoke stopForeground", e); + Log.w("VanillaMusic", 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 Notification mNotification; private SharedPreferences mSettings; + private AudioManager mAudioManager; + private NotificationManager mNotificationManager; private int[] mSongs; private ArrayList mSongTimeline; @@ -313,6 +301,12 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On private int mState = STATE_NORMAL; 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 PLAY_PAUSE = 1; 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.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.setWakeMode(this, PowerManager.PARTIAL_WAKE_LOCK); mMediaPlayer.setOnCompletionListener(this); @@ -455,7 +466,7 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On { if ("headset_only".equals(key)) { mHeadsetOnly = mSettings.getBoolean(key, false); - if (mHeadsetOnly && !mPlugged && mMediaPlayer.isPlaying()) + if (mHeadsetOnly && isSpeakerOn() && mMediaPlayer.isPlaying()) pause(); } else if ("remote_player".equals(key)) { mUseRemotePlayer = mSettings.getBoolean(key, true); @@ -536,9 +547,25 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On 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() { - if (mHeadsetOnly && !mPlugged) + if (mHeadsetOnly && isSpeakerOn()) return; mMediaPlayer.start();