package org.npr.android.util;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.util.Log;
import org.npr.android.news.PlaybackService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class AudioManagerProxy {
private static final String LOG_TAG = AudioManagerProxy.class.getName();
private static final int AUDIOMANAGER_AUDIOFOCUS_GAIN = 1;
private static final int AUDIOMANAGER_AUDIOFOCUS_LOSS = -1;
private static final int AUDIOMANAGER_AUDIO_REQUEST_GRANTED = 1;
private AudioManager audioManager;
private Object myOnAudioFocusChangeListener = null;
private boolean hasFocus = false;
public AudioManagerProxy(Context context) {
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
Log.v(LOG_TAG, "Looking for audio focus change support");
// instantiate the OnAudioFocusChangeListener using reflection (as it only exists from Android 2.2 onwards)
Class<?>[] innerClasses = audioManager.getClass().getDeclaredClasses();
for (Class<?> classInterface : innerClasses) {
if (classInterface.getSimpleName().equalsIgnoreCase("OnAudioFocusChangeListener")) {
Class<?>[] classArray = new Class<?>[1];
classArray[0] = classInterface;
myOnAudioFocusChangeListener = Proxy.newProxyInstance(classInterface.getClassLoader(),
classArray, new ProxyOnAudioFocusChangeListener(context));
Log.v(LOG_TAG, "Audio focus change support found");
}
}
}
public boolean getAudioFocus() {
if (myOnAudioFocusChangeListener != null) {
Log.v(LOG_TAG, "Getting audio focus");
try {
Method[] methods = audioManager.getClass().getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equalsIgnoreCase("requestAudioFocus")) {
Object object = method.invoke(audioManager,
myOnAudioFocusChangeListener,
AudioManager.STREAM_MUSIC,
AUDIOMANAGER_AUDIOFOCUS_GAIN);
if (object != null && (Integer) object == AUDIOMANAGER_AUDIO_REQUEST_GRANTED) {
hasFocus = true;
}
}
}
} catch (Exception e) {
Log.e(LOG_TAG, e.getMessage());
}
return hasFocus;
}
// If audio focus isn't supported by the OS, just return true
return true;
}
public void releaseAudioFocus() {
if (myOnAudioFocusChangeListener != null && hasFocus) {
Log.v(LOG_TAG, "Releasing audio focus");
try {
Method[] methods = audioManager.getClass().getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equalsIgnoreCase("abandonAudioFocus")) {
method.invoke(audioManager, myOnAudioFocusChangeListener);
hasFocus = false;
}
}
} catch (Exception e) {
Log.e(LOG_TAG, e.getMessage());
}
}
}
private class ProxyOnAudioFocusChangeListener implements InvocationHandler {
private Context context;
public ProxyOnAudioFocusChangeListener(Context context) {
this.context = context;
}
public void onAudioFocusChange(int focusChange) {
Log.v(LOG_TAG, "Audio focus change. focusChange = " + focusChange);
if (hasFocus) {
if (focusChange > 0) {
Log.v(LOG_TAG, "Audio focus gained");
Intent intent = new Intent(context, PlaybackService.class);
intent.setAction(PlaybackService.SERVICE_RESUME_PLAYING);
context.startService(intent);
} else {
Log.v(LOG_TAG, "Audio focus lost");
Intent intent = new Intent(context, PlaybackService.class);
intent.setAction(PlaybackService.SERVICE_PAUSE);
intent.putExtra(PlaybackService.EXTRA_KEEP_AUDIO_FOCUS,
(focusChange != AUDIOMANAGER_AUDIOFOCUS_LOSS));
context.startService(intent);
}
}
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
if (args != null) {
if (method.getName().equalsIgnoreCase("onAudioFocusChange") && args[0] instanceof Integer) {
onAudioFocusChange((Integer) args[0]);
}
}
} catch (Exception e) {
throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
}
return result;
}
}
}