Remove some more old code and fix Media command
Removes some more hidden apis from AudioService/Manager. This also
fixes up Media.java to support commands for the new service to help
with debugging. Also fixes a couple bugs that were found while fixing
up Media.
Change-Id: I68e4aa80a4de430b98236aafc883664b9432c62b
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index 92c6a51..4e91361 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -17,12 +17,19 @@
package com.android.commands.media;
-import android.app.PendingIntent;
+import android.app.ActivityManager;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.media.IAudioService;
-import android.media.IRemoteControlDisplay;
+import android.media.MediaMetadata;
+import android.media.session.ISessionController;
+import android.media.session.ISessionManager;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionInfo;
+import android.media.session.PlaybackState;
+import android.media.session.RouteInfo;
import android.os.Bundle;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -30,16 +37,17 @@
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
+
import com.android.internal.os.BaseCommand;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
+import java.util.List;
public class Media extends BaseCommand {
-
- private IAudioService mAudioService;
+ private ISessionManager mSessionService;
/**
* Command-line entry point.
@@ -54,29 +62,35 @@
out.println(
"usage: media [subcommand] [options]\n" +
" media dispatch KEY\n" +
- " media remote-display\n" +
+ " media list-sessions\n" +
+ " media monitor <sessionId>\n" +
"\n" +
- "media dispatch: dispatch a media key to the current media client.\n" +
+ "media dispatch: dispatch a media key to the system.\n" +
" KEY may be: play, pause, play-pause, mute, headsethook,\n" +
- " stop, next, previous, rewind, recordm fast-forword.\n" +
- "media remote-display: monitor remote display updates.\n"
+ " stop, next, previous, rewind, record, fast-forword.\n" +
+ "media list-sessions: print a list of the current sessions.\n" +
+ "media monitor: monitor updates to the specified session.\n" +
+ " Use the sessionId from list-sessions.\n"
);
}
public void onRun() throws Exception {
- mAudioService = IAudioService.Stub.asInterface(ServiceManager.checkService(
- Context.AUDIO_SERVICE));
- if (mAudioService == null) {
+ mSessionService = ISessionManager.Stub.asInterface(ServiceManager.checkService(
+ Context.MEDIA_SESSION_SERVICE));
+ if (mSessionService == null) {
System.err.println(NO_SYSTEM_ERROR_CODE);
- throw new AndroidException("Can't connect to audio service; is the system running?");
+ throw new AndroidException(
+ "Can't connect to media session service; is the system running?");
}
String op = nextArgRequired();
if (op.equals("dispatch")) {
runDispatch();
- } else if (op.equals("remote-display")) {
- runRemoteDisplay();
+ } else if (op.equals("list-sessions")) {
+ runListSessions();
+ } else if (op.equals("monitor")) {
+ runMonitor();
} else {
showError("Error: unknown command '" + op + "'");
return;
@@ -85,11 +99,39 @@
private void sendMediaKey(KeyEvent event) {
try {
- mAudioService.dispatchMediaKeyEvent(event);
+ mSessionService.dispatchMediaKeyEvent(event, false);
} catch (RemoteException e) {
}
}
+ private void runMonitor() throws Exception {
+ String id = nextArgRequired();
+ if (id == null) {
+ showError("Error: must include a session id");
+ return;
+ }
+ boolean success = false;
+ try {
+ List<IBinder> sessions = mSessionService
+ .getSessions(null, ActivityManager.getCurrentUser());
+ for (IBinder session : sessions) {
+ MediaController controller = MediaController.fromBinder(ISessionController.Stub
+ .asInterface(session));
+ if (controller != null && controller.getSessionInfo().getId().equals(id)) {
+ ControllerMonitor monitor = new ControllerMonitor(controller);
+ monitor.run();
+ success = true;
+ break;
+ }
+ }
+ } catch (Exception e) {
+ System.out.println("***Error monitoring session*** " + e.getMessage());
+ }
+ if (!success) {
+ System.out.println("No session found with id " + id);
+ }
+ }
+
private void runDispatch() throws Exception {
String cmd = nextArgRequired();
int keycode;
@@ -127,65 +169,49 @@
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
}
- class RemoteDisplayMonitor extends IRemoteControlDisplay.Stub {
- RemoteDisplayMonitor() {
+ class ControllerMonitor extends MediaController.Callback {
+ private final MediaController mController;
+
+ public ControllerMonitor(MediaController controller) {
+ mController = controller;
}
-
-
@Override
- public void setCurrentClientId(int clientGeneration, PendingIntent clientMediaIntent,
- boolean clearing) {
- System.out.println("New client: id=" + clientGeneration
- + " intent=" + clientMediaIntent + " clearing=" + clearing);
+ public void onSessionEvent(String event, Bundle extras) {
+ System.out.println("onSessionEvent event=" + event + ", extras=" + extras);
}
@Override
- public void setEnabled(boolean enabled) {
- System.out.println("New enable state= " + (enabled ? "enabled" : "disabled"));
+ public void onRouteChanged(RouteInfo route) {
+ System.out.println("onRouteChanged " + route);
}
@Override
- public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
- long currentPosMs, float speed) {
- System.out.println("New state: id=" + generationId + " state=" + state
- + " time=" + stateChangeTimeMs + " pos=" + currentPosMs + " speed=" + speed);
+ public void onPlaybackStateChanged(PlaybackState state) {
+ System.out.println("onPlaybackStateChanged " + state);
}
@Override
- public void setTransportControlInfo(int generationId, int transportControlFlags,
- int posCapabilities) {
- System.out.println("New control info: id=" + generationId
- + " flags=0x" + Integer.toHexString(transportControlFlags)
- + " cap=0x" + Integer.toHexString(posCapabilities));
- }
-
- @Override
- public void setMetadata(int generationId, Bundle metadata) {
- System.out.println("New metadata: id=" + generationId
- + " data=" + metadata);
- }
-
- @Override
- public void setArtwork(int generationId, Bitmap artwork) {
- System.out.println("New artwork: id=" + generationId
- + " art=" + artwork);
- }
-
- @Override
- public void setAllMetadata(int generationId, Bundle metadata, Bitmap artwork) {
- System.out.println("New metadata+artwork: id=" + generationId
- + " data=" + metadata + " art=" + artwork);
+ public void onMetadataChanged(MediaMetadata metadata) {
+ String mmString = metadata == null ? null : "title=" + metadata
+ .getString(MediaMetadata.METADATA_KEY_TITLE);
+ System.out.println("onMetadataChanged " + mmString);
}
void printUsageMessage() {
- System.out.println("Monitoring remote control displays... available commands:");
+ System.out.println("V2Monitoring session " + mController.getSessionInfo().getId()
+ + "... available commands:");
System.out.println("(q)uit: finish monitoring");
}
void run() throws RemoteException {
printUsageMessage();
-
- mAudioService.registerRemoteControlDisplay(this, 0, 0);
+ HandlerThread cbThread = new HandlerThread("MediaCb") {
+ @Override
+ protected void onLooperPrepared() {
+ mController.addCallback(ControllerMonitor.this);
+ }
+ };
+ cbThread.start();
try {
InputStreamReader converter = new InputStreamReader(System.in);
@@ -209,17 +235,35 @@
printUsageMessage();
}
}
-
} catch (IOException e) {
e.printStackTrace();
} finally {
- mAudioService.unregisterRemoteControlDisplay(this);
+ cbThread.getLooper().quit();
+ try {
+ mController.removeCallback(this);
+ } catch (Exception e) {
+ // ignoring
+ }
}
}
}
- private void runRemoteDisplay() throws Exception {
- RemoteDisplayMonitor monitor = new RemoteDisplayMonitor();
- monitor.run();
+ private void runListSessions() {
+ System.out.println("Sessions:");
+ try {
+ List<IBinder> sessions = mSessionService
+ .getSessions(null, ActivityManager.getCurrentUser());
+ for (IBinder session : sessions) {
+ MediaController controller = MediaController.fromBinder(ISessionController.Stub
+ .asInterface(session));
+ if (controller != null) {
+ MediaSessionInfo info = controller.getSessionInfo();
+ System.out.println(" id=" + info.getId() + ", package="
+ + info.getPackageName());
+ }
+ }
+ } catch (Exception e) {
+ System.out.println("***Error listing sessions***");
+ }
}
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index cf6d35ee8..d35225a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1616,26 +1616,6 @@
}
/**
- * @hide
- * If the stream is active locally or remotely, adjust its volume according to the enforced
- * priority rules.
- * Note: only AudioManager.STREAM_MUSIC is supported at the moment
- */
- public void adjustLocalOrRemoteStreamVolume(int streamType, int direction) {
- if (streamType != STREAM_MUSIC) {
- Log.w(TAG, "adjustLocalOrRemoteStreamVolume() doesn't support stream " + streamType);
- }
- IAudioService service = getService();
- try {
- service.adjustLocalOrRemoteStreamVolume(streamType, direction,
- mContext.getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in adjustLocalOrRemoteStreamVolume", e);
- }
- }
-
-
- /**
* Return a new audio session identifier not associated with any player or effect.
* It can for instance be used to create one of the {@link android.media.audiofx.AudioEffect}
* objects.
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 72f4a58..48479a4 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -830,24 +830,6 @@
}
/** @see AudioManager#adjustVolume(int, int) */
- public void adjustVolume(int direction, int flags, String callingPackage) {
- adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags,
- callingPackage);
- }
-
- /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption
- * on streamType: fixed to STREAM_MUSIC */
- public void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
- String callingPackage) {
- if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")");
- if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
- adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0, callingPackage);
- } else if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
- mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
- }
- }
-
- /** @see AudioManager#adjustVolume(int, int) */
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage) {
if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
@@ -4482,22 +4464,6 @@
mMediaFocusControl.setPlaybackInfoForRcc(rccId, what, value);
}
- public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
- if (DEBUG_SESSIONS) {
- int pid = getCallingPid();
- Log.w(TAG, "Call to dispatchMediaKeyEvent from " + pid);
- }
- MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
- }
-
- public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
- if (DEBUG_SESSIONS) {
- int pid = getCallingPid();
- Log.w(TAG, "Call to dispatchMediaKeyEventUnderWakelock from " + pid);
- }
- MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, true);
- }
-
//==========================================================================================
// Audio Focus
//==========================================================================================
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index c29e967..169631e 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -36,13 +36,8 @@
*/
interface IAudioService {
- void adjustVolume(int direction, int flags, String callingPackage);
-
boolean isLocalOrRemoteMusicActive();
- oneway void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
- String callingPackage);
-
void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage);
@@ -127,9 +122,6 @@
int getCurrentAudioFocus();
- oneway void dispatchMediaKeyEvent(in KeyEvent keyEvent);
- void dispatchMediaKeyEventUnderWakelock(in KeyEvent keyEvent);
-
void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c, IBinder token);
oneway void unregisterMediaButtonIntent(in PendingIntent pi);
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 5ca7daa..87a43e4 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -70,14 +70,7 @@
* @hide
*/
public static MediaController fromBinder(ISessionController sessionBinder) {
- MediaController controller = new MediaController(sessionBinder);
- try {
- controller.mSessionBinder.registerCallbackListener(controller.mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "MediaController created with expired token", e);
- controller = null;
- }
- return controller;
+ return new MediaController(sessionBinder);
}
/**
@@ -305,7 +298,7 @@
mSessionBinder.registerCallbackListener(mCbStub);
mCbRegistered = true;
} catch (RemoteException e) {
- Log.d(TAG, "Dead object in registerCallback", e);
+ Log.e(TAG, "Dead object in registerCallback", e);
}
}
}
@@ -314,14 +307,23 @@
if (cb == null) {
throw new IllegalArgumentException("Callback cannot be null");
}
+ boolean success = false;
for (int i = mCallbacks.size() - 1; i >= 0; i--) {
MessageHandler handler = mCallbacks.get(i);
if (cb == handler.mCallback) {
mCallbacks.remove(i);
- return true;
+ success = true;
}
}
- return false;
+ if (mCbRegistered && mCallbacks.size() == 0) {
+ try {
+ mSessionBinder.unregisterCallbackListener(mCbStub);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in removeCallbackLocked");
+ }
+ mCbRegistered = false;
+ }
+ return success;
}
private MessageHandler getHandlerForCallbackLocked(Callback cb) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
index 3e444fa..8945b15 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
@@ -341,11 +341,11 @@
}
// Volume buttons should only function for music (local or remote).
// TODO: Actually handle MUTE.
- mAudioManager.adjustLocalOrRemoteStreamVolume(
- AudioManager.STREAM_MUSIC,
+ mAudioManager.adjustSuggestedStreamVolume(
keyCode == KeyEvent.KEYCODE_VOLUME_UP
? AudioManager.ADJUST_RAISE
- : AudioManager.ADJUST_LOWER);
+ : AudioManager.ADJUST_LOWER /* direction */,
+ AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
// Don't execute default volume behavior
return true;
} else {
@@ -376,17 +376,13 @@
}
private void handleMediaKeyEvent(KeyEvent keyEvent) {
- IAudioService audioService = IAudioService.Stub.asInterface(
- ServiceManager.checkService(Context.AUDIO_SERVICE));
- if (audioService != null) {
- try {
- audioService.dispatchMediaKeyEvent(keyEvent);
- } catch (RemoteException e) {
- Log.e("KeyguardViewBase", "dispatchMediaKeyEvent threw exception " + e);
+ synchronized (this) {
+ if (mAudioManager == null) {
+ mAudioManager = (AudioManager) getContext().getSystemService(
+ Context.AUDIO_SERVICE);
}
- } else {
- Slog.w("KeyguardViewBase", "Unable to find IAudioService for media key event");
}
+ mAudioManager.dispatchMediaKeyEvent(keyEvent);
}
@Override
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 9ae8aed..9d61493 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -38,6 +38,7 @@
import android.media.MediaMetadata;
import android.media.Rating;
import android.os.Bundle;
+import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -63,6 +64,7 @@
*/
public class MediaSessionRecord implements IBinder.DeathRecipient {
private static final String TAG = "MediaSessionRecord";
+ private static final boolean DEBUG = false;
/**
* These are the playback states that count as currently active.
@@ -506,9 +508,12 @@
ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
cb.onPlaybackStateChanged(mPlaybackState);
- } catch (RemoteException e) {
- Log.w(TAG, "Removing dead callback in pushPlaybackStateUpdate.", e);
+ } catch (DeadObjectException e) {
mControllerCallbacks.remove(i);
+ Log.w(TAG, "Removed dead callback in pushPlaybackStateUpdate. size="
+ + mControllerCallbacks.size() + " cb=" + cb, e);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unexpected exception in pushPlaybackStateUpdate.", e);
}
}
}
@@ -523,9 +528,11 @@
ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
cb.onMetadataChanged(mMetadata);
- } catch (RemoteException e) {
- Log.w(TAG, "Removing dead callback in pushMetadataUpdate.", e);
+ } catch (DeadObjectException e) {
+ Log.w(TAG, "Removing dead callback in pushMetadataUpdate. " + cb, e);
mControllerCallbacks.remove(i);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unexpected exception in pushMetadataUpdate. " + cb, e);
}
}
}
@@ -540,9 +547,11 @@
ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
cb.onRouteChanged(mRoute);
- } catch (RemoteException e) {
+ } catch (DeadObjectException e) {
Log.w(TAG, "Removing dead callback in pushRouteUpdate.", e);
mControllerCallbacks.remove(i);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unexpected exception in pushRouteUpdate.", e);
}
}
}
@@ -557,8 +566,11 @@
ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
cb.onEvent(event, data);
+ } catch (DeadObjectException e) {
+ Log.w(TAG, "Removing dead callback in pushEvent.", e);
+ mControllerCallbacks.remove(i);
} catch (RemoteException e) {
- Log.w(TAG, "Error with callback in pushEvent.", e);
+ Log.w(TAG, "unexpected exception in pushEvent.", e);
}
}
}
@@ -611,6 +623,16 @@
return result == null ? state : result;
}
+ private int getControllerCbIndexForCb(ISessionControllerCallback cb) {
+ IBinder binder = cb.asBinder();
+ for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+ if (binder.equals(mControllerCallbacks.get(i).asBinder())) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
private final RouteConnectionRecord.Listener mConnectionListener
= new RouteConnectionRecord.Listener() {
@Override
@@ -929,8 +951,11 @@
@Override
public void registerCallbackListener(ISessionControllerCallback cb) {
synchronized (mLock) {
- if (!mControllerCallbacks.contains(cb)) {
+ if (getControllerCbIndexForCb(cb) < 0) {
mControllerCallbacks.add(cb);
+ if (DEBUG) {
+ Log.d(TAG, "registering controller callback " + cb);
+ }
}
}
}
@@ -939,7 +964,13 @@
public void unregisterCallbackListener(ISessionControllerCallback cb)
throws RemoteException {
synchronized (mLock) {
- mControllerCallbacks.remove(cb);
+ int index = getControllerCbIndexForCb(cb);
+ if (index != -1) {
+ mControllerCallbacks.remove(index);
+ }
+ if (DEBUG) {
+ Log.d(TAG, "unregistering callback " + cb + ". index=" + index);
+ }
}
}