From 61a12c614037a6d97e62db38c7e10a405ff4bee3 Mon Sep 17 00:00:00 2001 From: Christopher Eby Date: Fri, 6 Jan 2012 08:24:12 -0600 Subject: [PATCH] Audio focus --- src/org/kreed/vanilla/CompatFroyo.java | 41 +++++++++++- src/org/kreed/vanilla/PlaybackService.java | 77 +++++++++++++++------- 2 files changed, 92 insertions(+), 26 deletions(-) diff --git a/src/org/kreed/vanilla/CompatFroyo.java b/src/org/kreed/vanilla/CompatFroyo.java index 472ddf67..593f06ae 100644 --- a/src/org/kreed/vanilla/CompatFroyo.java +++ b/src/org/kreed/vanilla/CompatFroyo.java @@ -30,19 +30,58 @@ import android.media.AudioManager; /** * Framework methods only in Froyo or above go here. */ -public class CompatFroyo { +public class CompatFroyo implements AudioManager.OnAudioFocusChangeListener { + /** + * Instance of the audio focus listener created by {@link #createAudioFocus()}. + */ + private static CompatFroyo sAudioFocus; + + /** + * Calls {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}. + */ public static void registerMediaButtonEventReceiver(AudioManager manager, ComponentName receiver) { manager.registerMediaButtonEventReceiver(receiver); } + /** + * Calls {@link AudioManager#unregisterMediaButtonEventReceiver(ComponentName)}. + */ public static void unregisterMediaButtonEventReceiver(AudioManager manager, ComponentName receiver) { manager.unregisterMediaButtonEventReceiver(receiver); } + /** + * Calls {@link BackupManager#dataChanged()}. + */ public static void dataChanged(Context context) { new BackupManager(context).dataChanged(); } + + /** + * Creates an audio focus listener that calls back to {@link PlaybackService#onAudioFocusChange(int)}. + */ + public static void createAudioFocus() + { + sAudioFocus = new CompatFroyo(); + } + + /** + * Calls {@link AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int)} + */ + public static void requestAudioFocus(AudioManager manager) + { + manager.requestAudioFocus(sAudioFocus, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); + } + + @Override + public void onAudioFocusChange(int type) + { + PlaybackService service = PlaybackService.sInstance; + if (service != null) { + service.onAudioFocusChange(type); + } + } } diff --git a/src/org/kreed/vanilla/PlaybackService.java b/src/org/kreed/vanilla/PlaybackService.java index ace04abf..be9a8509 100644 --- a/src/org/kreed/vanilla/PlaybackService.java +++ b/src/org/kreed/vanilla/PlaybackService.java @@ -216,8 +216,11 @@ public final class PlaybackService extends Service */ private static final long IDLE_GRACE_PERIOD = 60000; - private static final Object sWait = new Object(); - private static PlaybackService sInstance; + private static final Object sWait = new Object[0]; + /** + * The appplication-wide instance of the PlaybackService. + */ + public static PlaybackService sInstance; private static final ArrayList sActivities = new ArrayList(5); /** * Cached app-wide SharedPreferences instance. @@ -300,6 +303,10 @@ public final class PlaybackService extends Service * indicates that no timeout has occurred. */ private long mIdleStart = -1; + /** + * True if the last audio focus loss can be ducked. + */ + private boolean mDuckedLoss; @Override public void onCreate() @@ -319,6 +326,10 @@ public final class PlaybackService extends Service mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { + CompatFroyo.createAudioFocus(); + } + SharedPreferences settings = getSettings(this); settings.registerOnSharedPreferenceChangeListener(this); mNotificationMode = Integer.parseInt(settings.getString("notification_mode", "1")); @@ -335,13 +346,26 @@ public final class PlaybackService extends Service mHeadsetPlay = settings.getBoolean("headset_play", false); mInvertNotification = settings.getBoolean("notification_inverted_color", false); mNotificationAction = createNotificationAction(settings); + mHeadsetPause = getSettings(this).getBoolean("headset_pause", true); PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "VanillaMusicLock"); + mCallListener = new InCallListener(); + TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); + telephonyManager.listen(mCallListener, PhoneStateListener.LISTEN_CALL_STATE); + + mReceiver = new Receiver(); + IntentFilter filter = new IntentFilter(); + filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY); + filter.addAction(Intent.ACTION_HEADSET_PLUG); + filter.addAction(Intent.ACTION_SCREEN_ON); + registerReceiver(mReceiver, filter); + + getContentResolver().registerContentObserver(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, true, mObserver); + mLooper = thread.getLooper(); mHandler = new Handler(mLooper, this); - mHandler.sendEmptyMessage(POST_CREATE); initWidgets(); @@ -556,6 +580,9 @@ public final class PlaybackService extends Service if (mNotificationMode != NEVER) startForeground(NOTIFICATION_ID, createNotification(mCurrentSong, mState)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { + CompatFroyo.requestAudioFocus(mAudioManager); + } if (mWakeLock != null) mWakeLock.acquire(); } else { @@ -968,18 +995,6 @@ public final class PlaybackService extends Service loadPreference(key); } - private void setupReceiver() - { - if (mReceiver == null) - mReceiver = new Receiver(); - IntentFilter filter = new IntentFilter(); - filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY); - filter.addAction(Intent.ACTION_HEADSET_PLUG); - filter.addAction(Intent.ACTION_SCREEN_ON); - registerReceiver(mReceiver, filter); - } - - private static final int POST_CREATE = 1; /** * Run the given query and add the results to the timeline. * @@ -1030,16 +1045,6 @@ public final class PlaybackService extends Service case QUERY: runQuery(message.arg1, (QueryTask)message.obj, message.arg2); break; - case POST_CREATE: - mHeadsetPause = getSettings(this).getBoolean("headset_pause", true); - setupReceiver(); - - mCallListener = new InCallListener(); - TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); - telephonyManager.listen(mCallListener, PhoneStateListener.LISTEN_CALL_STATE); - - getContentResolver().registerContentObserver(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, true, mObserver); - break; case IDLE_TIMEOUT: if ((mState & FLAG_PLAYING) != 0) mHandler.sendMessage(mHandler.obtainMessage(FADE_OUT, 100, 0)); @@ -1511,4 +1516,26 @@ public final class PlaybackService extends Service notification.contentIntent = mNotificationAction; return notification; } + + public void onAudioFocusChange(int type) + { + Log.d("VanillaMusic", "audio focus change: " + type); + switch (type) { + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: + mDuckedLoss = (mState & FLAG_PLAYING) != 0; + unsetFlag(FLAG_PLAYING); + break; + case AudioManager.AUDIOFOCUS_LOSS: + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: + mDuckedLoss = false; + unsetFlag(FLAG_PLAYING); + break; + case AudioManager.AUDIOFOCUS_GAIN: + if (mDuckedLoss) { + mDuckedLoss = false; + setFlag(FLAG_PLAYING); + } + break; + } + } }