Audio focus

This commit is contained in:
Christopher Eby 2012-01-06 08:24:12 -06:00
parent 95b5965a12
commit 61a12c6140
2 changed files with 92 additions and 26 deletions

View File

@ -30,19 +30,58 @@ import android.media.AudioManager;
/** /**
* Framework methods only in Froyo or above go here. * 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) public static void registerMediaButtonEventReceiver(AudioManager manager, ComponentName receiver)
{ {
manager.registerMediaButtonEventReceiver(receiver); manager.registerMediaButtonEventReceiver(receiver);
} }
/**
* Calls {@link AudioManager#unregisterMediaButtonEventReceiver(ComponentName)}.
*/
public static void unregisterMediaButtonEventReceiver(AudioManager manager, ComponentName receiver) public static void unregisterMediaButtonEventReceiver(AudioManager manager, ComponentName receiver)
{ {
manager.unregisterMediaButtonEventReceiver(receiver); manager.unregisterMediaButtonEventReceiver(receiver);
} }
/**
* Calls {@link BackupManager#dataChanged()}.
*/
public static void dataChanged(Context context) public static void dataChanged(Context context)
{ {
new BackupManager(context).dataChanged(); 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);
}
}
} }

View File

@ -216,8 +216,11 @@ public final class PlaybackService extends Service
*/ */
private static final long IDLE_GRACE_PERIOD = 60000; private static final long IDLE_GRACE_PERIOD = 60000;
private static final Object sWait = new Object(); private static final Object sWait = new Object[0];
private static PlaybackService sInstance; /**
* The appplication-wide instance of the PlaybackService.
*/
public static PlaybackService sInstance;
private static final ArrayList<PlaybackActivity> sActivities = new ArrayList<PlaybackActivity>(5); private static final ArrayList<PlaybackActivity> sActivities = new ArrayList<PlaybackActivity>(5);
/** /**
* Cached app-wide SharedPreferences instance. * Cached app-wide SharedPreferences instance.
@ -300,6 +303,10 @@ public final class PlaybackService extends Service
* indicates that no timeout has occurred. * indicates that no timeout has occurred.
*/ */
private long mIdleStart = -1; private long mIdleStart = -1;
/**
* True if the last audio focus loss can be ducked.
*/
private boolean mDuckedLoss;
@Override @Override
public void onCreate() public void onCreate()
@ -319,6 +326,10 @@ public final class PlaybackService extends Service
mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE); mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
CompatFroyo.createAudioFocus();
}
SharedPreferences settings = getSettings(this); SharedPreferences settings = getSettings(this);
settings.registerOnSharedPreferenceChangeListener(this); settings.registerOnSharedPreferenceChangeListener(this);
mNotificationMode = Integer.parseInt(settings.getString("notification_mode", "1")); mNotificationMode = Integer.parseInt(settings.getString("notification_mode", "1"));
@ -335,13 +346,26 @@ public final class PlaybackService extends Service
mHeadsetPlay = settings.getBoolean("headset_play", false); mHeadsetPlay = settings.getBoolean("headset_play", false);
mInvertNotification = settings.getBoolean("notification_inverted_color", false); mInvertNotification = settings.getBoolean("notification_inverted_color", false);
mNotificationAction = createNotificationAction(settings); mNotificationAction = createNotificationAction(settings);
mHeadsetPause = getSettings(this).getBoolean("headset_pause", true);
PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE); PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "VanillaMusicLock"); 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(); mLooper = thread.getLooper();
mHandler = new Handler(mLooper, this); mHandler = new Handler(mLooper, this);
mHandler.sendEmptyMessage(POST_CREATE);
initWidgets(); initWidgets();
@ -556,6 +580,9 @@ public final class PlaybackService extends Service
if (mNotificationMode != NEVER) if (mNotificationMode != NEVER)
startForeground(NOTIFICATION_ID, createNotification(mCurrentSong, mState)); startForeground(NOTIFICATION_ID, createNotification(mCurrentSong, mState));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
CompatFroyo.requestAudioFocus(mAudioManager);
}
if (mWakeLock != null) if (mWakeLock != null)
mWakeLock.acquire(); mWakeLock.acquire();
} else { } else {
@ -968,18 +995,6 @@ public final class PlaybackService extends Service
loadPreference(key); 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. * Run the given query and add the results to the timeline.
* *
@ -1030,16 +1045,6 @@ public final class PlaybackService extends Service
case QUERY: case QUERY:
runQuery(message.arg1, (QueryTask)message.obj, message.arg2); runQuery(message.arg1, (QueryTask)message.obj, message.arg2);
break; 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: case IDLE_TIMEOUT:
if ((mState & FLAG_PLAYING) != 0) if ((mState & FLAG_PLAYING) != 0)
mHandler.sendMessage(mHandler.obtainMessage(FADE_OUT, 100, 0)); mHandler.sendMessage(mHandler.obtainMessage(FADE_OUT, 100, 0));
@ -1511,4 +1516,26 @@ public final class PlaybackService extends Service
notification.contentIntent = mNotificationAction; notification.contentIntent = mNotificationAction;
return notification; 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;
}
}
} }