Add AudioManager and MediaSession support in sl4a.
Add limited amount of functionalities from both classes
in order to support PTS automation.
Put facade imports in alphabetic order.
Change-Id: Ie385a88e2ef8a9ff0ef088cedc3898a774299ee8
diff --git a/Common/src/com/googlecode/android_scripting/facade/AudioManagerFacade.java b/Common/src/com/googlecode/android_scripting/facade/AudioManagerFacade.java
new file mode 100644
index 0000000..a18d620
--- /dev/null
+++ b/Common/src/com/googlecode/android_scripting/facade/AudioManagerFacade.java
@@ -0,0 +1,68 @@
+
+package com.googlecode.android_scripting.facade;
+
+import android.app.Service;
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioManager.OnAudioFocusChangeListener;
+
+import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
+import com.googlecode.android_scripting.rpc.Rpc;
+
+public class AudioManagerFacade extends RpcReceiver {
+
+ private final Service mService;
+ private final EventFacade mEventFacade;
+ private final AudioManager mAudio;
+ private final OnAudioFocusChangeListener mFocusChangeListener;
+ private boolean mIsFocused;
+
+ public AudioManagerFacade(FacadeManager manager) {
+ super(manager);
+ mService = manager.getService();
+ mEventFacade = manager.getReceiver(EventFacade.class);
+ mAudio = (AudioManager) mService.getSystemService(Context.AUDIO_SERVICE);
+ mFocusChangeListener = new OnAudioFocusChangeListener() {
+ public void onAudioFocusChange(int focusChange) {
+ if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
+ mIsFocused = false;
+ } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
+ mIsFocused = true;
+ }
+ }
+ };
+ }
+
+ @Rpc(description = "Checks whether any music is active.")
+ public Boolean audioIsMusicActive() {
+ return mAudio.isMusicActive();
+ }
+
+ @Rpc(description = "Checks whether A2DP audio routing to the Bluetooth headset is on or off.")
+ public Boolean audioIsBluetoothA2dpOn() {
+ return mAudio.isBluetoothA2dpOn();
+ }
+
+ @Rpc(description = "Request audio focus for sl4a.")
+ public Boolean audioRequestAudioFocus() {
+ int status = mAudio.requestAudioFocus(mFocusChangeListener,
+ AudioManager.STREAM_MUSIC,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+ if (status == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+ mIsFocused = true;
+ return true;
+ }
+ mIsFocused = false;
+ return false;
+ }
+
+ @Rpc(description = "Whether sl4a has the audio focus or not.")
+ public Boolean audioIsFocused() {
+ return mIsFocused;
+ }
+
+ @Override
+ public void shutdown() {
+ mAudio.abandonAudioFocus(mFocusChangeListener);
+ }
+}
diff --git a/Common/src/com/googlecode/android_scripting/facade/MediaSessionFacade.java b/Common/src/com/googlecode/android_scripting/facade/MediaSessionFacade.java
new file mode 100644
index 0000000..5af0f35
--- /dev/null
+++ b/Common/src/com/googlecode/android_scripting/facade/MediaSessionFacade.java
@@ -0,0 +1,100 @@
+
+package com.googlecode.android_scripting.facade;
+
+import java.util.concurrent.Callable;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
+import android.media.session.MediaSession.Callback;
+import android.view.KeyEvent;
+
+import com.googlecode.android_scripting.Log;
+import com.googlecode.android_scripting.MainThread;
+import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
+import com.googlecode.android_scripting.rpc.Rpc;
+
+public class MediaSessionFacade extends RpcReceiver {
+
+ private final Service mService;
+ private final EventFacade mEventFacade;
+ private MediaSessionManager mMediaManager;
+ private MediaSession mMedia;
+ private Callback mCallback;
+
+ public MediaSessionFacade(FacadeManager manager) {
+ super(manager);
+ mService = manager.getService();
+ mEventFacade = manager.getReceiver(EventFacade.class);
+ Log.d("Creating MediaSession.");
+ mMediaManager = (MediaSessionManager) mService.getSystemService(Context.MEDIA_SESSION_SERVICE);
+ mMedia = mMediaManager.createSession("SL4A");
+ mMedia.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
+ mMedia.setActive(true);
+ mCallback = new ButtonCallback(mEventFacade);
+ }
+
+ public static class ButtonCallback extends MediaSession.Callback {
+ private final EventFacade mEventFacade;
+ public ButtonCallback(EventFacade eventFacade) {
+ this.mEventFacade = eventFacade;
+ }
+ @Override
+ public void onMediaButtonEvent(Intent mediaButtonIntent) {
+ String action = mediaButtonIntent.getAction();
+ Log.d("Received intent with action " + action);
+ if (action.equals(Intent.ACTION_MEDIA_BUTTON)) {
+ KeyEvent event = (KeyEvent) mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+ int keyAction = event.getAction();
+ Log.d("Received KeyEvent with action " + keyAction);
+ if (keyAction == KeyEvent.ACTION_DOWN) {
+ int keyCode = event.getKeyCode();
+ Log.d("Received ACTION_DOWN with keycode " + keyCode);
+ if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
+ mEventFacade.postEvent("mediaKeyOnPlay", null);
+ } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
+ mEventFacade.postEvent("mediaOnPause", null);
+ } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
+ mEventFacade.postEvent("mediaOnStop", null);
+ } else if (keyCode == KeyEvent.KEYCODE_MEDIA_NEXT) {
+ mEventFacade.postEvent("mediaOnNext", null);
+ } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS) {
+ mEventFacade.postEvent("mediaOnPrevious", null);
+ } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
+ mEventFacade.postEvent("mediaOnPlayPause", null);
+ }
+ }
+ }
+ }
+ }
+
+ @Rpc(description = "Checks whether any music is active.")
+ public void mediaSessionAddCallback() {
+ MainThread.run(mService, new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ Log.d("Adding callback.");
+ mMedia.addCallback(mCallback);
+ PlaybackState state = new PlaybackState();
+ state.setActions(PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_STOP);
+ state.setState(PlaybackState.STATE_PLAYING, 0, 1);
+ mMedia.setPlaybackState(state);
+ return null;
+ }
+ });
+ }
+
+ @Rpc(description = "Whether current media session is active.")
+ public Boolean mediaSessionIsActive() {
+ return mMedia.isActive();
+ }
+
+ @Override
+ public void shutdown() {
+ mMedia.removeCallback(mCallback);
+ mMedia.release();
+ }
+}
diff --git a/ScriptingLayer/src/com/googlecode/android_scripting/facade/FacadeConfiguration.java b/ScriptingLayer/src/com/googlecode/android_scripting/facade/FacadeConfiguration.java
index 39451bb..cde8f19 100644
--- a/ScriptingLayer/src/com/googlecode/android_scripting/facade/FacadeConfiguration.java
+++ b/ScriptingLayer/src/com/googlecode/android_scripting/facade/FacadeConfiguration.java
@@ -17,6 +17,7 @@
package com.googlecode.android_scripting.facade;
import com.google.common.collect.Maps;
+import com.googlecode.android_scripting.Log;
import com.googlecode.android_scripting.facade.bluetooth.BluetoothA2dpFacade;
import com.googlecode.android_scripting.facade.bluetooth.BluetoothAvrcpFacade;
import com.googlecode.android_scripting.facade.bluetooth.BluetoothConnectionFacade;
@@ -64,15 +65,21 @@
sSdkLevel = android.os.Build.VERSION.SDK_INT;
sFacadeClassList = new HashSet<Class<? extends RpcReceiver>>();
+ sFacadeClassList.add(ActivityResultFacade.class);
sFacadeClassList.add(AndroidFacade.class);
sFacadeClassList.add(ApplicationManagerFacade.class);
+ sFacadeClassList.add(AudioManagerFacade.class);
+ sFacadeClassList.add(BatteryManagerFacade.class);
sFacadeClassList.add(CameraFacade.class);
sFacadeClassList.add(CommonIntentsFacade.class);
sFacadeClassList.add(ContactsFacade.class);
sFacadeClassList.add(EventFacade.class);
sFacadeClassList.add(LocationFacade.class);
sFacadeClassList.add(PhoneFacade.class);
+ sFacadeClassList.add(PreferencesFacade.class);
+ sFacadeClassList.add(MediaPlayerFacade.class);
sFacadeClassList.add(MediaRecorderFacade.class);
+ sFacadeClassList.add(MediaSessionFacade.class);
sFacadeClassList.add(SensorManagerFacade.class);
sFacadeClassList.add(SettingsFacade.class);
// Could not get SmsFacade to compile. APIs are deprecated
@@ -82,10 +89,6 @@
sFacadeClassList.add(WakeLockFacade.class);
sFacadeClassList.add(WifiManagerFacade.class);
sFacadeClassList.add(UiFacade.class);
- sFacadeClassList.add(BatteryManagerFacade.class);
- sFacadeClassList.add(ActivityResultFacade.class);
- sFacadeClassList.add(MediaPlayerFacade.class);
- sFacadeClassList.add(PreferencesFacade.class);
if (sSdkLevel >= 4) {
sFacadeClassList.add(TextToSpeechFacade.class);
@@ -95,13 +98,13 @@
if (sSdkLevel >= 5) {
sFacadeClassList.add(BluetoothFacade.class);
- sFacadeClassList.add(BluetoothRfcommFacade.class);
- sFacadeClassList.add(BluetoothConnectionFacade.class);
sFacadeClassList.add(BluetoothA2dpFacade.class);
sFacadeClassList.add(BluetoothAvrcpFacade.class);
+ sFacadeClassList.add(BluetoothConnectionFacade.class);
sFacadeClassList.add(BluetoothHspFacade.class);
sFacadeClassList.add(BluetoothHidFacade.class);
sFacadeClassList.add(BluetoothMapFacade.class);
+ sFacadeClassList.add(BluetoothRfcommFacade.class);
}
if (sSdkLevel >= 7) {
@@ -116,8 +119,8 @@
sFacadeClassList.add(BluetoothLeScanFacade.class);
sFacadeClassList.add(BluetoothGattFacade.class);
sFacadeClassList.add(BluetoothLeAdvertiseFacade.class);
- sFacadeClassList.add(WifiScannerFacade.class);
sFacadeClassList.add(WifiPasspointManagerFacade.class);
+ sFacadeClassList.add(WifiScannerFacade.class);
}
@@ -169,6 +172,7 @@
if (method.isAnnotationPresent(RpcStartEvent.class)) {
String eventName = method.getAnnotation(RpcStartEvent.class).value();
if (map.containsKey(eventName)) {
+ Log.d("Duplicate eventName " + eventName);
throw new RuntimeException("Duplicate start event method descriptor found.");
}
map.put(eventName, descriptor);