Merge "Move media key processing to sessions"
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 1dcfcb8..3a3f76d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -428,7 +428,6 @@
public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
private static IAudioService sService;
- private MediaSessionLegacyHelper mSessionHelper;
/**
* @hide
@@ -439,9 +438,6 @@
com.android.internal.R.bool.config_useMasterVolume);
mUseVolumeKeySounds = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_useVolumeKeySounds);
- if (USE_SESSIONS) {
- mSessionHelper = MediaSessionLegacyHelper.getHelper(context);
- }
}
private static IAudioService getService()
@@ -478,11 +474,16 @@
* or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
*/
public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
- IAudioService service = getService();
- try {
- service.dispatchMediaKeyEvent(keyEvent);
- } catch (RemoteException e) {
- Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
+ if (USE_SESSIONS) {
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+ helper.sendMediaButtonEvent(keyEvent, false);
+ } else {
+ IAudioService service = getService();
+ try {
+ service.dispatchMediaKeyEvent(keyEvent);
+ } catch (RemoteException e) {
+ Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
+ }
}
}
@@ -2178,7 +2179,8 @@
Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
}
if (USE_SESSIONS) {
- mSessionHelper.addMediaButtonListener(pi, mContext);
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+ helper.addMediaButtonListener(pi, mContext);
}
}
@@ -2254,7 +2256,8 @@
Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
}
if (USE_SESSIONS) {
- mSessionHelper.removeMediaButtonListener(pi);
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+ helper.removeMediaButtonListener(pi);
}
}
@@ -2281,7 +2284,7 @@
Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
}
if (USE_SESSIONS) {
- rcClient.registerWithSession(mSessionHelper);
+ rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mContext));
}
}
@@ -2303,7 +2306,7 @@
Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
}
if (USE_SESSIONS) {
- rcClient.unregisterWithSession(mSessionHelper);
+ rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mContext));
}
}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 724022b..bb8cfa6 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -46,6 +46,7 @@
import android.hardware.usb.UsbManager;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
+import android.media.session.MediaSessionLegacyHelper;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
@@ -108,6 +109,10 @@
/** Debug volumes */
protected static final boolean DEBUG_VOL = false;
+ /** Reroute calls to media session apis */
+ private static final boolean USE_SESSIONS = true;
+ private static final boolean DEBUG_SESSIONS = true;
+
/** How long to delay before persisting a change in volume/ringer mode. */
private static final int PERSIST_DELAY = 500;
@@ -3472,7 +3477,7 @@
if (volume < 0) {
volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
} else {
- volFloat = (float) volume / 1000.0f;
+ volFloat = volume / 1000.0f;
}
if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
@@ -3554,7 +3559,7 @@
}
Settings.System.putFloatForUser(mContentResolver,
Settings.System.VOLUME_MASTER,
- (float)msg.arg1 / (float)1000.0,
+ msg.arg1 / (float)1000.0,
UserHandle.USER_CURRENT);
break;
@@ -4325,11 +4330,27 @@
}
public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
- mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
+ if (USE_SESSIONS) {
+ if (DEBUG_SESSIONS) {
+ int pid = getCallingPid();
+ Log.w(TAG, "Call to dispatchMediaKeyEvent from " + pid);
+ }
+ MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
+ } else {
+ mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
+ }
}
public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
- mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
+ if (USE_SESSIONS) {
+ if (DEBUG_SESSIONS) {
+ int pid = getCallingPid();
+ Log.w(TAG, "Call to dispatchMediaKeyEventUnderWakelock from " + pid);
+ }
+ MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, true);
+ } else {
+ mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
+ }
}
//==========================================================================================
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 1552513..7b0412e 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -28,7 +28,7 @@
*/
oneway interface ISessionCallback {
void onCommand(String command, in Bundle extras, in ResultReceiver cb);
- void onMediaButton(in Intent mediaButtonIntent);
+ void onMediaButton(in Intent mediaButtonIntent, in ResultReceiver cb);
void onRequestRouteChange(in RouteInfo route);
void onRouteConnected(in RouteInfo route, in RouteOptions options);
void onRouteDisconnected(in RouteInfo route, int reason);
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index e341647..38b92932 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -19,6 +19,7 @@
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.os.Bundle;
+import android.view.KeyEvent;
/**
* Interface to the MediaSessionManagerService
@@ -27,4 +28,5 @@
interface ISessionManager {
ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
List<IBinder> getSessions(in ComponentName compName, int userId);
+ void dispatchMediaKeyEvent(in KeyEvent keyEvent, boolean needWakeLock);
}
\ No newline at end of file
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index c07229d..e1eae09 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -35,6 +35,7 @@
*/
public class MediaSessionLegacyHelper {
private static final String TAG = "MediaSessionHelper";
+ private static final boolean DEBUG = true;
private static final Object sLock = new Object();
private static MediaSessionLegacyHelper sInstance;
@@ -52,6 +53,9 @@
}
public static MediaSessionLegacyHelper getHelper(Context context) {
+ if (DEBUG) {
+ Log.d(TAG, "Attempting to get helper with context " + context);
+ }
synchronized (sLock) {
if (sInstance == null) {
sInstance = new MediaSessionLegacyHelper(context);
@@ -65,12 +69,25 @@
return holder == null ? null : holder.mSession;
}
- public void addRccListener(PendingIntent pi, TransportPerformer.Listener listener) {
+ public void sendMediaButtonEvent(KeyEvent keyEvent, boolean needWakeLock) {
+ mSessionManager.dispatchMediaKeyEvent(keyEvent, needWakeLock);
+ if (DEBUG) {
+ Log.d(TAG, "dispatched media key " + keyEvent);
+ }
+ }
+ public void addRccListener(PendingIntent pi, TransportPerformer.Listener listener) {
+ if (pi == null) {
+ Log.w(TAG, "Pending intent was null, can't add rcc listener.");
+ return;
+ }
SessionHolder holder = getHolder(pi, true);
TransportPerformer performer = holder.mSession.getTransportPerformer();
if (holder.mRccListener != null) {
if (holder.mRccListener == listener) {
+ if (DEBUG) {
+ Log.d(TAG, "addRccListener listener already added.");
+ }
// This is already the registered listener, ignore
return;
}
@@ -82,9 +99,15 @@
holder.mFlags |= Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
holder.mSession.setFlags(holder.mFlags);
holder.update();
+ if (DEBUG) {
+ Log.d(TAG, "Added rcc listener for " + pi + ".");
+ }
}
public void removeRccListener(PendingIntent pi) {
+ if (pi == null) {
+ return;
+ }
SessionHolder holder = getHolder(pi, false);
if (holder != null && holder.mRccListener != null) {
holder.mSession.getTransportPerformer().removeListener(holder.mRccListener);
@@ -92,30 +115,56 @@
holder.mFlags &= ~Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
holder.mSession.setFlags(holder.mFlags);
holder.update();
+ if (DEBUG) {
+ Log.d(TAG, "Removed rcc listener for " + pi + ".");
+ }
}
}
public void addMediaButtonListener(PendingIntent pi,
Context context) {
+ if (pi == null) {
+ Log.w(TAG, "Pending intent was null, can't addMediaButtonListener.");
+ return;
+ }
SessionHolder holder = getHolder(pi, true);
if (holder.mMediaButtonListener != null) {
- // Already have this listener registered
+ // Already have this listener registered, but update it anyway as
+ // the extras may have changed.
+ if (DEBUG) {
+ Log.d(TAG, "addMediaButtonListener already added " + pi);
+ }
return;
}
holder.mMediaButtonListener = new MediaButtonListener(pi, context);
holder.mFlags |= Session.FLAG_HANDLES_MEDIA_BUTTONS;
holder.mSession.setFlags(holder.mFlags);
holder.mSession.getTransportPerformer().addListener(holder.mMediaButtonListener, mHandler);
+
+ holder.mMediaButtonReceiver = new MediaButtonReceiver(pi, context);
+ holder.mSession.addCallback(holder.mMediaButtonReceiver, mHandler);
+ if (DEBUG) {
+ Log.d(TAG, "addMediaButtonListener added " + pi);
+ }
}
public void removeMediaButtonListener(PendingIntent pi) {
+ if (pi == null) {
+ return;
+ }
SessionHolder holder = getHolder(pi, false);
if (holder != null && holder.mMediaButtonListener != null) {
holder.mSession.getTransportPerformer().removeListener(holder.mMediaButtonListener);
holder.mFlags &= ~Session.FLAG_HANDLES_MEDIA_BUTTONS;
holder.mSession.setFlags(holder.mFlags);
holder.mMediaButtonListener = null;
+
+ holder.mSession.removeCallback(holder.mMediaButtonReceiver);
+ holder.mMediaButtonReceiver = null;
holder.update();
+ if (DEBUG) {
+ Log.d(TAG, "removeMediaButtonListener removed " + pi);
+ }
}
}
@@ -130,7 +179,32 @@
return holder;
}
- public static class MediaButtonListener extends TransportPerformer.Listener {
+ private static void sendKeyEvent(PendingIntent pi, Context context, Intent intent) {
+ try {
+ pi.send(context, 0, intent);
+ } catch (CanceledException e) {
+ Log.e(TAG, "Error sending media key down event:", e);
+ // Don't bother sending up if down failed
+ return;
+ }
+ }
+
+ private static final class MediaButtonReceiver extends Session.Callback {
+ private final PendingIntent mPendingIntent;
+ private final Context mContext;
+
+ public MediaButtonReceiver(PendingIntent pi, Context context) {
+ mPendingIntent = pi;
+ mContext = context;
+ }
+
+ @Override
+ public void onMediaButton(Intent mediaButtonIntent) {
+ MediaSessionLegacyHelper.sendKeyEvent(mPendingIntent, mContext, mediaButtonIntent);
+ }
+ }
+
+ private static final class MediaButtonListener extends TransportPerformer.Listener {
private final PendingIntent mPendingIntent;
private final Context mContext;
@@ -179,20 +253,14 @@
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
intent.putExtra(Intent.EXTRA_KEY_EVENT, ke);
- try {
- mPendingIntent.send(mContext, 0, intent);
- } catch (CanceledException e) {
- Log.e(TAG, "Error sending media key down event:", e);
- // Don't bother sending up if down failed
- return;
- }
+ MediaSessionLegacyHelper.sendKeyEvent(mPendingIntent, mContext, intent);
ke = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
intent.putExtra(Intent.EXTRA_KEY_EVENT, ke);
- try {
- mPendingIntent.send(mContext, 0, intent);
- } catch (CanceledException e) {
- Log.e(TAG, "Error sending media key up event:", e);
+ MediaSessionLegacyHelper.sendKeyEvent(mPendingIntent, mContext, intent);
+
+ if (DEBUG) {
+ Log.d(TAG, "Sent " + keyCode + " to pending intent " + mPendingIntent);
}
}
}
@@ -201,6 +269,7 @@
public final Session mSession;
public final PendingIntent mPi;
public MediaButtonListener mMediaButtonListener;
+ public MediaButtonReceiver mMediaButtonReceiver;
public TransportPerformer.Listener mRccListener;
public int mFlags;
@@ -213,10 +282,6 @@
if (mMediaButtonListener == null && mRccListener == null) {
mSession.release();
mSessions.remove(mPi);
- } else if (mMediaButtonListener != null && mRccListener != null) {
- // TODO set session to active
- } else {
- // TODO set session to inactive
}
}
}
diff --git a/media/java/android/media/session/Session.java b/media/java/android/media/session/Session.java
index 2ffced6..e439772 100644
--- a/media/java/android/media/session/Session.java
+++ b/media/java/android/media/session/Session.java
@@ -114,6 +114,13 @@
*/
public static final int DISCONNECT_REASON_SESSION_DESTROYED = 5;
+ /**
+ * Status code indicating the call was handled.
+ *
+ * @hide
+ */
+ public static final int RESULT_SUCCESS = 0;
+
private static final int MSG_MEDIA_BUTTON = 1;
private static final int MSG_COMMAND = 2;
private static final int MSG_ROUTE_CHANGE = 3;
@@ -544,11 +551,15 @@
}
@Override
- public void onMediaButton(Intent mediaButtonIntent) throws RemoteException {
+ public void onMediaButton(Intent mediaButtonIntent, ResultReceiver cb)
+ throws RemoteException {
Session session = mMediaSession.get();
if (session != null) {
session.postMediaButton(mediaButtonIntent);
}
+ if (cb != null) {
+ cb.send(RESULT_SUCCESS, null);
+ }
}
@Override
diff --git a/media/java/android/media/session/SessionManager.java b/media/java/android/media/session/SessionManager.java
index 1eb3b7a..1838132 100644
--- a/media/java/android/media/session/SessionManager.java
+++ b/media/java/android/media/session/SessionManager.java
@@ -25,6 +25,7 @@
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.util.Log;
+import android.view.KeyEvent;
import java.util.ArrayList;
import java.util.List;
@@ -138,4 +139,30 @@
}
return controllers;
}
+
+ /**
+ * Send a media key event. The receiver will be selected automatically.
+ *
+ * @param keyEvent The KeyEvent to send.
+ * @hide
+ */
+ public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+ dispatchMediaKeyEvent(keyEvent, false);
+ }
+
+ /**
+ * Send a media key event. The receiver will be selected automatically.
+ *
+ * @param keyEvent The KeyEvent to send
+ * @param needWakeLock true if a wake lock should be held while sending the
+ * key
+ * @hide
+ */
+ public void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+ try {
+ mService.dispatchMediaKeyEvent(keyEvent, needWakeLock);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send key event.", e);
+ }
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 466c8ed..7c89d23 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -46,6 +46,7 @@
import android.media.IAudioService;
import android.media.Ringtone;
import android.media.RingtoneManager;
+import android.media.session.MediaSessionLegacyHelper;
import android.os.Bundle;
import android.os.FactoryTest;
import android.os.Handler;
@@ -137,6 +138,9 @@
static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
+ // Whether to use the new Session APIs
+ static final boolean USE_SESSIONS = true;
+
static final int LONG_PRESS_POWER_NOTHING = 0;
static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
static final int LONG_PRESS_POWER_SHUT_OFF = 2;
@@ -1325,11 +1329,11 @@
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
}
}
-
+
void readLidState() {
mLidState = mWindowManagerFuncs.getLidState();
}
-
+
private boolean isHidden(int accessibilityMode) {
switch (accessibilityMode) {
case 1:
@@ -1676,16 +1680,16 @@
/**
* Preflight adding a window to the system.
- *
+ *
* Currently enforces that three window types are singletons:
* <ul>
* <li>STATUS_BAR_TYPE</li>
* <li>KEYGUARD_TYPE</li>
* </ul>
- *
+ *
* @param win The window to be added
* @param attrs Information about the window to be added
- *
+ *
* @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
* WindowManagerImpl.ADD_MULTIPLE_SINGLETON
*/
@@ -1758,7 +1762,7 @@
}
static final boolean PRINT_ANIM = false;
-
+
/** {@inheritDoc} */
@Override
public int selectAnimationLw(WindowState win, int transit) {
@@ -2337,7 +2341,7 @@
Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
- // TODO: This only stops the factory-installed search manager.
+ // TODO: This only stops the factory-installed search manager.
// Need to formalize an API to handle others
SearchManager searchManager = getSearchManager();
if (searchManager != null) {
@@ -3032,7 +3036,7 @@
if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
== (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ "): IN_SCREEN, INSET_DECOR");
// This is the case for a normal activity window: we want it
// to cover all of the screen space, and it can take care of
@@ -3316,7 +3320,7 @@
if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
+ ": sim=#" + Integer.toHexString(sim)
- + " attach=" + attached + " type=" + attrs.type
+ + " attach=" + attached + " type=" + attrs.type
+ String.format(" flags=0x%08x", fl)
+ " pf=" + pf.toShortString() + " df=" + df.toShortString()
+ " of=" + of.toShortString()
@@ -3365,7 +3369,7 @@
mForceStatusBarFromKeyguard = false;
mForcingShowNavBar = false;
mForcingShowNavBarLayer = -1;
-
+
mHideLockScreen = false;
mAllowLockscreenWhenOn = false;
mDismissKeyguard = DISMISS_KEYGUARD_NONE;
@@ -4209,12 +4213,16 @@
void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) {
if (ActivityManagerNative.isSystemReady()) {
- IAudioService audioService = getAudioService();
- if (audioService != null) {
- try {
- audioService.dispatchMediaKeyEventUnderWakelock(event);
- } catch (RemoteException e) {
- Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
+ if (USE_SESSIONS) {
+ MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true);
+ } else {
+ IAudioService audioService = getAudioService();
+ if (audioService != null) {
+ try {
+ audioService.dispatchMediaKeyEventUnderWakelock(event);
+ } catch (RemoteException e) {
+ Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
+ }
}
}
}
@@ -4440,7 +4448,7 @@
}
public void dismissKeyguardLw() {
- if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
+ if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
mHandler.post(new Runnable() {
public void run() {
if (mKeyguardDelegate.isDismissable()) {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 9677577..f6be1ff 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -365,6 +365,10 @@
return mSessionCb.mCb;
}
+ public void sendMediaButton(KeyEvent ke, ResultReceiver cb) {
+ mSessionCb.sendMediaButton(ke, cb);
+ }
+
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + mTag + " " + this);
@@ -645,11 +649,11 @@
mCb = cb;
}
- public void sendMediaButton(KeyEvent keyEvent) {
+ public void sendMediaButton(KeyEvent keyEvent, ResultReceiver cb) {
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
try {
- mCb.onMediaButton(mediaButtonIntent);
+ mCb.onMediaButton(mediaButtonIntent, cb);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
}
@@ -785,7 +789,7 @@
@Override
public void sendMediaButton(KeyEvent mediaButtonIntent) {
- mSessionCb.sendMediaButton(mediaButtonIntent);
+ mSessionCb.sendMediaButton(mediaButtonIntent, null);
}
@Override
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 78f3b5f..a2ca2a1 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -17,9 +17,12 @@
package com.android.server.media;
import android.Manifest;
+import android.app.Activity;
import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.routeprovider.RouteRequest;
import android.media.session.ISession;
@@ -29,14 +32,18 @@
import android.media.session.RouteOptions;
import android.media.session.Session;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
+import android.view.KeyEvent;
import com.android.server.SystemService;
import com.android.server.Watchdog;
@@ -64,6 +71,7 @@
// = new ArrayList<MediaRouteProviderProxy>();
private final Object mLock = new Object();
private final Handler mHandler = new Handler();
+ private final PowerManager.WakeLock mMediaEventWakeLock;
private MediaSessionRecord mPrioritySession;
private int mCurrentUserId = -1;
@@ -79,6 +87,8 @@
super(context);
mSessionManagerImpl = new SessionManagerImpl();
mPriorityStack = new MediaSessionStack();
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
}
@Override
@@ -377,7 +387,7 @@
/*
* When a session is created the following things need to happen.
- * 1. It's callback binder needs a link to death
+ * 1. Its callback binder needs a link to death
* 2. It needs to be added to all sessions.
* 3. It needs to be added to the priority stack.
* 4. It needs to be added to the relevant user record.
@@ -585,9 +595,10 @@
}
class SessionManagerImpl extends ISessionManager.Stub {
- // TODO add createSessionAsUser, pass user-id to
- // ActivityManagerNative.handleIncomingUser and stash result for use
- // when starting services on that session's behalf.
+ private static final String EXTRA_WAKELOCK_ACQUIRED =
+ "android.media.AudioService.WAKELOCK_ACQUIRED";
+ private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
+
@Override
public ISession createSession(String packageName, ISessionCallback cb, String tag,
int userId) throws RemoteException {
@@ -644,6 +655,59 @@
}
}
+ /**
+ * Handles the dispatching of the media button events to one of the
+ * registered listeners, or if there was none, broadcast an
+ * ACTION_MEDIA_BUTTON intent to the rest of the system.
+ *
+ * @param keyEvent a non-null KeyEvent whose key code is one of the
+ * supported media buttons
+ * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
+ * while this key event is dispatched.
+ */
+ @Override
+ public void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+ if (keyEvent == null || !KeyEvent.isMediaKey(keyEvent.getKeyCode())) {
+ Log.w(TAG, "Attempted to dispatch null or non-media key event.");
+ return;
+ }
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ if (needWakeLock) {
+ mMediaEventWakeLock.acquire();
+ }
+ synchronized (mLock) {
+ MediaSessionRecord mbSession = mPriorityStack
+ .getDefaultMediaButtonSession(mCurrentUserId);
+ if (mbSession != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Sending media key to " + mbSession.getSessionInfo());
+ }
+ mbSession.sendMediaButton(keyEvent,
+ needWakeLock ? mKeyEventDoneReceiver : null);
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Sending media key ordered broadcast");
+ }
+ // Fallback to legacy behavior
+ Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+ keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ if (needWakeLock) {
+ keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED,
+ WAKELOCK_RELEASE_ON_FINISHED);
+ }
+ getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
+ null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(Manifest.permission.DUMP)
@@ -678,6 +742,36 @@
}
}
}
+
+ ResultReceiver mKeyEventDoneReceiver = new ResultReceiver(mHandler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ synchronized (mLock) {
+ if (mMediaEventWakeLock.isHeld()) {
+ mMediaEventWakeLock.release();
+ }
+ }
+ }
+ };
+
+ BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent == null) {
+ return;
+ }
+ Bundle extras = intent.getExtras();
+ if (extras == null) {
+ return;
+ }
+ synchronized (mLock) {
+ if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)
+ && mMediaEventWakeLock.isHeld()) {
+ mMediaEventWakeLock.release();
+ }
+ }
+ }
+ };
}
}