OSDN Git Service

AudioService: remove dead code
authorJean-Michel Trivi <jmtrivi@google.com>
Wed, 4 Nov 2015 22:45:54 +0000 (14:45 -0800)
committerJean-Michel Trivi <jmtrivi@google.com>
Mon, 23 Nov 2015 23:16:04 +0000 (23:16 +0000)
Remove dead code related to media button event receiver and
  remote control display, now handled by MediaSession*

Change-Id: I4bd621240ddddf4df079df8d551c72b232c3301d

Android.mk
CleanSpec.mk
media/java/android/media/AudioManager.java
media/java/android/media/IAudioService.aidl
media/java/android/media/IRemoteControlClient.aidl [deleted file]
media/java/android/media/IRemoteControlDisplay.aidl [deleted file]
media/java/android/media/RemoteControlClient.java
media/java/android/media/RemoteController.java
services/core/java/com/android/server/audio/AudioService.java
services/core/java/com/android/server/audio/MediaFocusControl.java
services/core/java/com/android/server/audio/PlayerRecord.java [deleted file]

index 1eff5cc..7ca04a5 100644 (file)
@@ -344,8 +344,6 @@ LOCAL_SRC_FILES += \
        media/java/android/media/IMediaRouterService.aidl \
        media/java/android/media/IMediaScannerListener.aidl \
        media/java/android/media/IMediaScannerService.aidl \
-       media/java/android/media/IRemoteControlClient.aidl \
-       media/java/android/media/IRemoteControlDisplay.aidl \
        media/java/android/media/IRemoteDisplayCallback.aidl \
        media/java/android/media/IRemoteDisplayProvider.aidl \
        media/java/android/media/IRemoteVolumeController.aidl \
index 6e44d77..40908f1 100644 (file)
@@ -236,6 +236,8 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libinputflinge
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/target/common/obj/framework.aidl)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/DocumentsUI_intermediates)
+$(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IRemoteControlClient.*)
+$(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IRemoteControlDisplay.*)
 
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
index 50df556..c658675 100644 (file)
@@ -2658,107 +2658,6 @@ public class AudioManager {
         rctlr.stopListeningToSessions();
     }
 
-    /**
-     * @hide
-     * Registers a remote control display that will be sent information by remote control clients.
-     * Use this method if your IRemoteControlDisplay is not going to display artwork, otherwise
-     * use {@link #registerRemoteControlDisplay(IRemoteControlDisplay, int, int)} to pass the
-     * artwork size directly, or
-     * {@link #remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay, int, int)} later if artwork
-     * is not yet needed.
-     * <p>Registration requires the {@link Manifest.permission#MEDIA_CONTENT_CONTROL} permission.
-     * @param rcd the IRemoteControlDisplay
-     */
-    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
-        // passing a negative value for art work width and height as they are unknown at this stage
-        registerRemoteControlDisplay(rcd, /*w*/-1, /*h*/ -1);
-    }
-
-    /**
-     * @hide
-     * Registers a remote control display that will be sent information by remote control clients.
-     * <p>Registration requires the {@link Manifest.permission#MEDIA_CONTENT_CONTROL} permission.
-     * @param rcd
-     * @param w the maximum width of the expected bitmap. Negative values indicate it is
-     *   useless to send artwork.
-     * @param h the maximum height of the expected bitmap. Negative values indicate it is
-     *   useless to send artwork.
-     */
-    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
-        if (rcd == null) {
-            return;
-        }
-        IAudioService service = getService();
-        try {
-            service.registerRemoteControlDisplay(rcd, w, h);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
-        }
-    }
-
-    /**
-     * @hide
-     * Unregisters a remote control display that was sent information by remote control clients.
-     * @param rcd
-     */
-    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
-        if (rcd == null) {
-            return;
-        }
-        IAudioService service = getService();
-        try {
-            service.unregisterRemoteControlDisplay(rcd);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e);
-        }
-    }
-
-    /**
-     * @hide
-     * Sets the artwork size a remote control display expects when receiving bitmaps.
-     * @param rcd
-     * @param w the maximum width of the expected bitmap. Negative values indicate it is
-     *   useless to send artwork.
-     * @param h the maximum height of the expected bitmap. Negative values indicate it is
-     *   useless to send artwork.
-     */
-    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
-        if (rcd == null) {
-            return;
-        }
-        IAudioService service = getService();
-        try {
-            service.remoteControlDisplayUsesBitmapSize(rcd, w, h);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in remoteControlDisplayUsesBitmapSize " + e);
-        }
-    }
-
-    /**
-     * @hide
-     * Controls whether a remote control display needs periodic checks of the RemoteControlClient
-     * playback position to verify that the estimated position has not drifted from the actual
-     * position. By default the check is not performed.
-     * The IRemoteControlDisplay must have been previously registered for this to have any effect.
-     * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled
-     *     or disabled. No effect is null.
-     * @param wantsSync if true, RemoteControlClient instances which expose their playback position
-     *     to the framework will regularly compare the estimated playback position with the actual
-     *     position, and will update the IRemoteControlDisplay implementation whenever a drift is
-     *     detected.
-     */
-    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
-            boolean wantsSync) {
-        if (rcd == null) {
-            return;
-        }
-        IAudioService service = getService();
-        try {
-            service.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in remoteControlDisplayWantsPlaybackPositionSync " + e);
-        }
-    }
 
     /**
      * @hide
index 8aebe11..693a519 100644 (file)
@@ -23,9 +23,6 @@ import android.media.AudioAttributes;
 import android.media.AudioRoutesInfo;
 import android.media.IAudioFocusDispatcher;
 import android.media.IAudioRoutesObserver;
-import android.media.IRemoteControlClient;
-import android.media.IRemoteControlDisplay;
-import android.media.IRemoteVolumeObserver;
 import android.media.IRingtonePlayer;
 import android.media.IVolumeController;
 import android.media.Rating;
@@ -47,8 +44,6 @@ interface IAudioService {
 
     void setStreamVolume(int streamType, int index, int flags, String callingPackage);
 
-    oneway void setRemoteStreamVolume(int index);
-
     boolean isStreamMute(int streamType);
 
     void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb);
@@ -121,59 +116,6 @@ interface IAudioService {
 
     int getCurrentAudioFocus();
 
-    /**
-     * Register an IRemoteControlDisplay.
-     * Success of registration is subject to a check on
-     *   the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission.
-     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
-     * at the top of the stack to update the new display with its information.
-     * @param rcd the IRemoteControlDisplay to register. No effect if null.
-     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     */
-    boolean registerRemoteControlDisplay(in IRemoteControlDisplay rcd, int w, int h);
-
-    /**
-     * Like registerRemoteControlDisplay, but with success being subject to a check on
-     *   the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission, and if it fails,
-     *   success is subject to listenerComp being one of the ENABLED_NOTIFICATION_LISTENERS
-     *   components.
-     */
-    boolean registerRemoteController(in IRemoteControlDisplay rcd, int w, int h,
-            in ComponentName listenerComp);
-
-    /**
-     * Unregister an IRemoteControlDisplay.
-     * No effect if the IRemoteControlDisplay hasn't been successfully registered.
-     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
-     */
-    oneway void unregisterRemoteControlDisplay(in IRemoteControlDisplay rcd);
-    /**
-     * Update the size of the artwork used by an IRemoteControlDisplay.
-     * @param rcd the IRemoteControlDisplay with the new artwork size requirement
-     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     */
-    oneway void remoteControlDisplayUsesBitmapSize(in IRemoteControlDisplay rcd, int w, int h);
-    /**
-     * Controls whether a remote control display needs periodic checks of the RemoteControlClient
-     * playback position to verify that the estimated position has not drifted from the actual
-     * position. By default the check is not performed.
-     * The IRemoteControlDisplay must have been previously registered for this to have any effect.
-     * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled
-     *     or disabled. Not null.
-     * @param wantsSync if true, RemoteControlClient instances which expose their playback position
-     *     to the framework will regularly compare the estimated playback position with the actual
-     *     position, and will update the IRemoteControlDisplay implementation whenever a drift is
-     *     detected.
-     */
-    oneway void remoteControlDisplayWantsPlaybackPositionSync(in IRemoteControlDisplay rcd,
-            boolean wantsSync);
-
     void startBluetoothSco(IBinder cb, int targetSdkVersion);
     void startBluetoothScoVirtualCall(IBinder cb);
     void stopBluetoothSco(IBinder cb);
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
deleted file mode 100644 (file)
index aa142d6..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-import android.graphics.Bitmap;
-import android.media.IRemoteControlDisplay;
-import android.media.Rating;
-
-/**
- * @hide
- * Interface registered by AudioManager to notify a source of remote control information
- * that information is requested to be displayed on the remote control (through
- * IRemoteControlDisplay).
- * {@see AudioManager#registerRemoteControlClient(RemoteControlClient)}.
- */
-oneway interface IRemoteControlClient
-{
-    /**
-     * Notifies a remote control client that information for the given generation ID is
-     * requested. If the flags contains
-     * {@link RemoteControlClient#FLAG_INFORMATION_REQUESTED_ALBUM_ART} then the width and height
-     *   parameters are valid.
-     * @param generationId
-     * @param infoFlags
-     * FIXME: is infoFlags required? since the RCC pushes info, this might always be called
-     *        with RC_INFO_ALL
-     */
-    void onInformationRequested(int generationId, int infoFlags);
-
-    /**
-     * Notifies a remote control client that information for the given generation ID is
-     * requested for the given IRemoteControlDisplay alone.
-     * @param rcd the display to which current info should be sent
-     */
-    void informationRequestForDisplay(IRemoteControlDisplay rcd, int w, int h);
-
-    /**
-     * Sets the generation counter of the current client that is displayed on the remote control.
-     */
-    void setCurrentClientGenerationId(int clientGeneration);
-
-    void   plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h);
-    void unplugRemoteControlDisplay(IRemoteControlDisplay rcd);
-    void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h);
-    void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync);
-    void enableRemoteControlDisplay(IRemoteControlDisplay rcd, boolean enabled);
-    void seekTo(int clientGeneration, long timeMs);
-    void updateMetadata(int clientGeneration, int key, in Rating value);
-}
\ No newline at end of file
diff --git a/media/java/android/media/IRemoteControlDisplay.aidl b/media/java/android/media/IRemoteControlDisplay.aidl
deleted file mode 100644 (file)
index 1609030..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.graphics.Bitmap;
-import android.os.Bundle;
-
-/**
- * @hide
- * Interface registered through AudioManager of an object that displays information
- * received from a remote control client.
- * {@see AudioManager#registerRemoteControlDisplay(IRemoteControlDisplay)}.
- */
-oneway interface IRemoteControlDisplay
-{
-    /**
-     * Sets the generation counter of the current client that is displayed on the remote control.
-     * @param clientGeneration the new RemoteControlClient generation
-     * @param clientMediaIntent the PendingIntent associated with the client.
-     *    May be null, which implies there is no registered media button event receiver.
-     * @param clearing true if the new client generation value maps to a remote control update
-     *    where the display should be cleared.
-     */
-    void setCurrentClientId(int clientGeneration, in PendingIntent clientMediaIntent,
-            boolean clearing);
-
-    /**
-     * Sets whether the controls of this display are enabled
-     * @param if false, the display shouldn't any commands
-     */
-    void setEnabled(boolean enabled);
-
-    /**
-     * Sets the playback information (state, position and speed) of a client.
-     * @param generationId the current generation ID as known by this client
-     * @param state the current playback state, one of the following values:
-     *       {@link RemoteControlClient#PLAYSTATE_STOPPED},
-     *       {@link RemoteControlClient#PLAYSTATE_PAUSED},
-     *       {@link RemoteControlClient#PLAYSTATE_PLAYING},
-     *       {@link RemoteControlClient#PLAYSTATE_FAST_FORWARDING},
-     *       {@link RemoteControlClient#PLAYSTATE_REWINDING},
-     *       {@link RemoteControlClient#PLAYSTATE_SKIPPING_FORWARDS},
-     *       {@link RemoteControlClient#PLAYSTATE_SKIPPING_BACKWARDS},
-     *       {@link RemoteControlClient#PLAYSTATE_BUFFERING},
-     *       {@link RemoteControlClient#PLAYSTATE_ERROR}.
-     * @param stateChangeTimeMs the time at which the client reported the playback information
-     * @param currentPosMs a 0 or positive value for the current media position expressed in ms
-     *    Strictly negative values imply that position is not known:
-     *    a value of {@link RemoteControlClient#PLAYBACK_POSITION_INVALID} is intended to express
-     *    that an application doesn't know the position (e.g. listening to a live stream of a radio)
-     *    or that the position information is not applicable (e.g. when state
-     *    is {@link RemoteControlClient#PLAYSTATE_BUFFERING} and nothing had played yet);
-     *    a value of {@link RemoteControlClient#PLAYBACK_POSITION_ALWAYS_UNKNOWN} implies that the
-     *    application uses {@link RemoteControlClient#setPlaybackState(int)} (legacy API) and will
-     *    never pass a playback position.
-     * @param speed a value expressed as a ratio of 1x playback: 1.0f is normal playback,
-     *    2.0f is 2x, 0.5f is half-speed, -2.0f is rewind at 2x speed. 0.0f means nothing is
-     *    playing (e.g. when state is {@link RemoteControlClient#PLAYSTATE_ERROR}).
-     */
-    void setPlaybackState(int generationId, int state, long stateChangeTimeMs, long currentPosMs,
-            float speed);
-
-    /**
-     * Sets the transport control flags and playback position capabilities of a client.
-     * @param generationId the current generation ID as known by this client
-     * @param transportControlFlags bitmask of the transport controls this client supports, see
-     *         {@link RemoteControlClient#setTransportControlFlags(int)}
-     * @param posCapabilities a bit mask for playback position capabilities, see
-     *         {@link RemoteControlClient#MEDIA_POSITION_READABLE} and
-     *         {@link RemoteControlClient#MEDIA_POSITION_WRITABLE}
-     */
-    void setTransportControlInfo(int generationId, int transportControlFlags, int posCapabilities);
-
-    void setMetadata(int generationId, in Bundle metadata);
-
-    void setArtwork(int generationId, in Bitmap artwork);
-
-    /**
-     * To combine metadata text and artwork in one binder call
-     */
-    void setAllMetadata(int generationId, in Bundle metadata, in Bitmap artwork);
-}
index c9a86d8..6d32eff 100644 (file)
@@ -349,16 +349,6 @@ import java.lang.IllegalArgumentException;
      */
     public RemoteControlClient(PendingIntent mediaButtonIntent) {
         mRcMediaIntent = mediaButtonIntent;
-
-        Looper looper;
-        if ((looper = Looper.myLooper()) != null) {
-            mEventHandler = new EventHandler(this, looper);
-        } else if ((looper = Looper.getMainLooper()) != null) {
-            mEventHandler = new EventHandler(this, looper);
-        } else {
-            mEventHandler = null;
-            Log.e(TAG, "RemoteControlClient() couldn't find main application thread");
-        }
     }
 
     /**
@@ -378,8 +368,6 @@ import java.lang.IllegalArgumentException;
      */
     public RemoteControlClient(PendingIntent mediaButtonIntent, Looper looper) {
         mRcMediaIntent = mediaButtonIntent;
-
-        mEventHandler = new EventHandler(this, looper);
     }
 
     /**
@@ -707,39 +695,6 @@ import java.lang.IllegalArgumentException;
         }
     }
 
-    // TODO investigate if we still need position drift checking
-    private void onPositionDriftCheck() {
-        if (DEBUG) { Log.d(TAG, "onPositionDriftCheck()"); }
-        synchronized(mCacheLock) {
-            if ((mEventHandler == null) || (mPositionProvider == null) || !mNeedsPositionSync) {
-                return;
-            }
-            if ((mPlaybackPositionMs < 0) || (mPlaybackSpeed == 0.0f)) {
-                if (DEBUG) { Log.d(TAG, " no valid position or 0 speed, no check needed"); }
-                return;
-            }
-            long estPos = mPlaybackPositionMs + (long)
-                    ((SystemClock.elapsedRealtime() - mPlaybackStateChangeTimeMs) / mPlaybackSpeed);
-            long actPos = mPositionProvider.onGetPlaybackPosition();
-            if (actPos >= 0) {
-                if (Math.abs(estPos - actPos) > POSITION_DRIFT_MAX_MS) {
-                    // drift happened, report the new position
-                    if (DEBUG) { Log.w(TAG, " drift detected: actual=" +actPos +"  est=" +estPos); }
-                    setPlaybackState(mPlaybackState, actPos, mPlaybackSpeed);
-                } else {
-                    if (DEBUG) { Log.d(TAG, " no drift: actual=" + actPos +"  est=" + estPos); }
-                    // no drift, schedule the next drift check
-                    mEventHandler.sendMessageDelayed(
-                            mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
-                            getCheckPeriodFromSpeed(mPlaybackSpeed));
-                }
-            } else {
-                // invalid position (negative value), can't check for drift
-                mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
-            }
-        }
-    }
-
     /**
      * Sets the flags for the media transport control buttons that this client supports.
      * @param transportControlFlags A combination of the following flags:
@@ -856,14 +811,6 @@ import java.lang.IllegalArgumentException;
     public void setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener l) {
         synchronized(mCacheLock) {
             mPositionProvider = l;
-            if ((mPositionProvider != null) && (mEventHandler != null)
-                    && playbackPositionShouldMove(mPlaybackState)) {
-                // playback position is already moving, but now we have a position provider,
-                // so schedule a drift check right now
-                mEventHandler.sendMessageDelayed(
-                        mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
-                        0 /*check now*/);
-            }
         }
     }
 
@@ -1001,26 +948,6 @@ import java.lang.IllegalArgumentException;
         }
     };
 
-    private EventHandler mEventHandler;
-    private final static int MSG_POSITION_DRIFT_CHECK = 11;
-
-    private class EventHandler extends Handler {
-        public EventHandler(RemoteControlClient rcc, Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-                case MSG_POSITION_DRIFT_CHECK:
-                    onPositionDriftCheck();
-                    break;
-                default:
-                    Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
-            }
-        }
-    }
-
     //===========================================================
     // Message handlers
 
index d84cf30..90f2163 100644 (file)
@@ -17,8 +17,6 @@
 package android.media;
 
 import android.app.ActivityManager;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -32,7 +30,6 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -61,15 +58,10 @@ import java.util.List;
 @Deprecated public final class RemoteController
 {
     private final static int MAX_BITMAP_DIMENSION = 512;
-    private final static int TRANSPORT_UNKNOWN = 0;
     private final static String TAG = "RemoteController";
     private final static boolean DEBUG = false;
-    private final static boolean USE_SESSIONS = true;
-    private final static Object mGenLock = new Object();
     private final static Object mInfoLock = new Object();
-    private final RcDisplay mRcd;
     private final Context mContext;
-    private final AudioManager mAudioManager;
     private final int mMaxBitmapDimension;
     private MetadataEditor mMetadataEditor;
 
@@ -78,15 +70,9 @@ import java.util.List;
     private MediaController.Callback mSessionCb = new MediaControllerCallback();
 
     /**
-     * Synchronized on mGenLock
-     */
-    private int mClientGenerationIdCurrent = 0;
-
-    /**
      * Synchronized on mInfoLock
      */
     private boolean mIsRegistered = false;
-    private PendingIntent mClientPendingIntentCurrent;
     private OnClientUpdateListener mOnClientUpdateListener;
     private PlaybackInfo mLastPlaybackInfo;
     private int mArtworkWidth = -1;
@@ -136,8 +122,6 @@ import java.util.List;
         }
         mOnClientUpdateListener = updateListener;
         mContext = context;
-        mRcd = new RcDisplay(this);
-        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mSessionManager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         mSessionListener = new TopTransportSessionListener();
@@ -207,22 +191,6 @@ import java.util.List;
         public void onClientMetadataUpdate(MetadataEditor metadataEditor);
     };
 
-
-    /**
-     * @hide
-     */
-    public String getRemoteControlClientPackageName() {
-        if (USE_SESSIONS) {
-            synchronized (mInfoLock) {
-                return mCurrentSession != null ? mCurrentSession.getPackageName()
-                        : null;
-            }
-        } else {
-            return mClientPendingIntentCurrent != null ?
-                    mClientPendingIntentCurrent.getCreatorPackage() : null;
-        }
-    }
-
     /**
      * Return the estimated playback position of the current media track or a negative value
      * if not available.
@@ -240,37 +208,12 @@ import java.util.List;
      * @see OnClientUpdateListener#onClientPlaybackStateUpdate(int, long, long, float)
      */
     public long getEstimatedMediaPosition() {
-        if (USE_SESSIONS) {
-            synchronized (mInfoLock) {
-                if (mCurrentSession != null) {
-                    PlaybackState state = mCurrentSession.getPlaybackState();
-                    if (state != null) {
-                        return state.getPosition();
-                    }
-                }
-            }
-        } else {
-            final PlaybackInfo lastPlaybackInfo;
-            synchronized (mInfoLock) {
-                lastPlaybackInfo = mLastPlaybackInfo;
-            }
-            if (lastPlaybackInfo != null) {
-                if (!RemoteControlClient.playbackPositionShouldMove(lastPlaybackInfo.mState)) {
-                    return lastPlaybackInfo.mCurrentPosMs;
-                }
-
-                // Take the current position at the time of state change and
-                // estimate.
-                final long thenPos = lastPlaybackInfo.mCurrentPosMs;
-                if (thenPos < 0) {
-                    return -1;
+        synchronized (mInfoLock) {
+            if (mCurrentSession != null) {
+                PlaybackState state = mCurrentSession.getPlaybackState();
+                if (state != null) {
+                    return state.getPosition();
                 }
-
-                final long now = SystemClock.elapsedRealtime();
-                final long then = lastPlaybackInfo.mStateChangeTimeMs;
-                final long sinceThen = now - then;
-                final long scaledSinceThen = (long) (sinceThen * lastPlaybackInfo.mSpeed);
-                return thenPos + scaledSinceThen;
             }
         }
         return -1;
@@ -308,42 +251,12 @@ import java.util.List;
         if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) {
             throw new IllegalArgumentException("not a media key event");
         }
-        if (USE_SESSIONS) {
-            synchronized (mInfoLock) {
-                if (mCurrentSession != null) {
-                    return mCurrentSession.dispatchMediaButtonEvent(keyEvent);
-                }
-                return false;
-            }
-        } else {
-            final PendingIntent pi;
-            synchronized (mInfoLock) {
-                if (!mIsRegistered) {
-                    Log.e(TAG,
-                            "Cannot use sendMediaKeyEvent() from an unregistered RemoteController");
-                    return false;
-                }
-                if (!mEnabled) {
-                    Log.e(TAG, "Cannot use sendMediaKeyEvent() from a disabled RemoteController");
-                    return false;
-                }
-                pi = mClientPendingIntentCurrent;
-            }
-            if (pi != null) {
-                Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-                intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-                try {
-                    pi.send(mContext, 0, intent);
-                } catch (CanceledException e) {
-                    Log.e(TAG, "Error sending intent for media button down: ", e);
-                    return false;
-                }
-            } else {
-                Log.i(TAG, "No-op when sending key click, no receiver right now");
-                return false;
+        synchronized (mInfoLock) {
+            if (mCurrentSession != null) {
+                return mCurrentSession.dispatchMediaButtonEvent(keyEvent);
             }
+            return false;
         }
-        return true;
     }
 
 
@@ -453,8 +366,7 @@ import java.util.List;
             Log.e(TAG, "Cannot set synchronization mode on an unregistered RemoteController");
             return false;
         }
-        mAudioManager.remoteControlDisplayWantsPlaybackPositionSync(mRcd,
-                POSITION_SYNCHRONIZATION_CHECK == sync);
+        // deprecated, no-op
         return true;
     }
 
@@ -541,154 +453,6 @@ import java.util.List;
 
     }
 
-
-    //==================================================
-    // Implementation of IRemoteControlDisplay interface
-    private static class RcDisplay extends IRemoteControlDisplay.Stub {
-        private final WeakReference<RemoteController> mController;
-
-        RcDisplay(RemoteController rc) {
-            mController = new WeakReference<RemoteController>(rc);
-        }
-
-        public void setCurrentClientId(int genId, PendingIntent clientMediaIntent,
-                boolean clearing) {
-            final RemoteController rc = mController.get();
-            if (rc == null) {
-                return;
-            }
-            boolean isNew = false;
-            synchronized(mGenLock) {
-                if (rc.mClientGenerationIdCurrent != genId) {
-                    rc.mClientGenerationIdCurrent = genId;
-                    isNew = true;
-                }
-            }
-            if (clientMediaIntent != null) {
-                sendMsg(rc.mEventHandler, MSG_NEW_PENDING_INTENT, SENDMSG_REPLACE,
-                        genId /*arg1*/, 0, clientMediaIntent /*obj*/, 0 /*delay*/);
-            }
-            if (isNew || clearing) {
-                sendMsg(rc.mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
-                        genId /*arg1*/, clearing ? 1 : 0, null /*obj*/, 0 /*delay*/);
-            }
-        }
-
-        public void setEnabled(boolean enabled) {
-            final RemoteController rc = mController.get();
-            if (rc == null) {
-                return;
-            }
-            sendMsg(rc.mEventHandler, MSG_DISPLAY_ENABLE, SENDMSG_REPLACE,
-                    enabled ? 1 : 0 /*arg1*/, 0, null /*obj*/, 0 /*delay*/);
-        }
-
-        public void setPlaybackState(int genId, int state,
-                long stateChangeTimeMs, long currentPosMs, float speed) {
-            final RemoteController rc = mController.get();
-            if (rc == null) {
-                return;
-            }
-            if (DEBUG) {
-                Log.d(TAG, "> new playback state: genId="+genId
-                        + " state="+ state
-                        + " changeTime="+ stateChangeTimeMs
-                        + " pos=" + currentPosMs
-                        + "ms speed=" + speed);
-            }
-
-            synchronized(mGenLock) {
-                if (rc.mClientGenerationIdCurrent != genId) {
-                    return;
-                }
-            }
-            final PlaybackInfo playbackInfo =
-                    new PlaybackInfo(state, stateChangeTimeMs, currentPosMs, speed);
-            sendMsg(rc.mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE,
-                    genId /*arg1*/, 0, playbackInfo /*obj*/, 0 /*delay*/);
-
-        }
-
-        public void setTransportControlInfo(int genId, int transportControlFlags,
-                int posCapabilities) {
-            final RemoteController rc = mController.get();
-            if (rc == null) {
-                return;
-            }
-            synchronized(mGenLock) {
-                if (rc.mClientGenerationIdCurrent != genId) {
-                    return;
-                }
-            }
-            sendMsg(rc.mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE,
-                    genId /*arg1*/, transportControlFlags /*arg2*/,
-                    null /*obj*/, 0 /*delay*/);
-        }
-
-        public void setMetadata(int genId, Bundle metadata) {
-            final RemoteController rc = mController.get();
-            if (rc == null) {
-                return;
-            }
-            if (DEBUG) { Log.e(TAG, "setMetadata("+genId+")"); }
-            if (metadata == null) {
-                return;
-            }
-            synchronized(mGenLock) {
-                if (rc.mClientGenerationIdCurrent != genId) {
-                    return;
-                }
-            }
-            sendMsg(rc.mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
-                    genId /*arg1*/, 0 /*arg2*/,
-                    metadata /*obj*/, 0 /*delay*/);
-        }
-
-        public void setArtwork(int genId, Bitmap artwork) {
-            final RemoteController rc = mController.get();
-            if (rc == null) {
-                return;
-            }
-            if (DEBUG) { Log.v(TAG, "setArtwork("+genId+")"); }
-            synchronized(mGenLock) {
-                if (rc.mClientGenerationIdCurrent != genId) {
-                    return;
-                }
-            }
-            Bundle metadata = new Bundle(1);
-            metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), artwork);
-            sendMsg(rc.mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
-                    genId /*arg1*/, 0 /*arg2*/,
-                    metadata /*obj*/, 0 /*delay*/);
-        }
-
-        public void setAllMetadata(int genId, Bundle metadata, Bitmap artwork) {
-            final RemoteController rc = mController.get();
-            if (rc == null) {
-                return;
-            }
-            if (DEBUG) { Log.e(TAG, "setAllMetadata("+genId+")"); }
-            if ((metadata == null) && (artwork == null)) {
-                return;
-            }
-            synchronized(mGenLock) {
-                if (rc.mClientGenerationIdCurrent != genId) {
-                    return;
-                }
-            }
-            if (metadata == null) {
-                metadata = new Bundle(1);
-            }
-            if (artwork != null) {
-                metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
-                        artwork);
-            }
-            sendMsg(rc.mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
-                    genId /*arg1*/, 0 /*arg2*/,
-                    metadata /*obj*/, 0 /*delay*/);
-        }
-    }
-
     /**
      * This receives updates when the current session changes. This is
      * registered to receive the updates on the handler thread so it can call
@@ -734,14 +498,9 @@ import java.util.List;
     //==================================================
     // Event handling
     private final EventHandler mEventHandler;
-    private final static int MSG_NEW_PENDING_INTENT = 0;
-    private final static int MSG_NEW_PLAYBACK_INFO =  1;
-    private final static int MSG_NEW_TRANSPORT_INFO = 2;
-    private final static int MSG_NEW_METADATA       = 3; // msg always has non-null obj parameter
-    private final static int MSG_CLIENT_CHANGE      = 4;
-    private final static int MSG_DISPLAY_ENABLE     = 5;
-    private final static int MSG_NEW_PLAYBACK_STATE = 6;
-    private final static int MSG_NEW_MEDIA_METADATA = 7;
+    private final static int MSG_CLIENT_CHANGE      = 0;
+    private final static int MSG_NEW_PLAYBACK_STATE = 1;
+    private final static int MSG_NEW_MEDIA_METADATA = 2;
 
     private class EventHandler extends Handler {
 
@@ -752,26 +511,10 @@ import java.util.List;
         @Override
         public void handleMessage(Message msg) {
             switch(msg.what) {
-                case MSG_NEW_PENDING_INTENT:
-                    onNewPendingIntent(msg.arg1, (PendingIntent) msg.obj);
-                    break;
-                case MSG_NEW_PLAYBACK_INFO:
-                    onNewPlaybackInfo(msg.arg1, (PlaybackInfo) msg.obj);
-                    break;
-                case MSG_NEW_TRANSPORT_INFO:
-                    onNewTransportInfo(msg.arg1, msg.arg2);
-                    break;
-                case MSG_NEW_METADATA:
-                    onNewMetadata(msg.arg1, (Bundle)msg.obj);
-                    break;
                 case MSG_CLIENT_CHANGE:
-                    onClientChange(msg.arg1, msg.arg2 == 1);
-                    break;
-                case MSG_DISPLAY_ENABLE:
-                    onDisplayEnable(msg.arg1 == 1);
+                    onClientChange(msg.arg2 == 1);
                     break;
                 case MSG_NEW_PLAYBACK_STATE:
-                    // same as new playback info but using new apis
                     onNewPlaybackState((PlaybackState) msg.obj);
                     break;
                 case MSG_NEW_MEDIA_METADATA:
@@ -835,100 +578,7 @@ import java.util.List;
         handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delayMs);
     }
 
-    ///////////// These calls are used by the old APIs with RCC and RCD //////////////////////
-    private void onNewPendingIntent(int genId, PendingIntent pi) {
-        synchronized(mGenLock) {
-            if (mClientGenerationIdCurrent != genId) {
-                return;
-            }
-        }
-        synchronized(mInfoLock) {
-            mClientPendingIntentCurrent = pi;
-        }
-    }
-
-    private void onNewPlaybackInfo(int genId, PlaybackInfo pi) {
-        synchronized(mGenLock) {
-            if (mClientGenerationIdCurrent != genId) {
-                return;
-            }
-        }
-        final OnClientUpdateListener l;
-        synchronized(mInfoLock) {
-            l = this.mOnClientUpdateListener;
-            mLastPlaybackInfo = pi;
-        }
-        if (l != null) {
-            if (pi.mCurrentPosMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
-                l.onClientPlaybackStateUpdate(pi.mState);
-            } else {
-                l.onClientPlaybackStateUpdate(pi.mState, pi.mStateChangeTimeMs, pi.mCurrentPosMs,
-                        pi.mSpeed);
-            }
-        }
-    }
-
-    private void onNewTransportInfo(int genId, int transportControlFlags) {
-        synchronized(mGenLock) {
-            if (mClientGenerationIdCurrent != genId) {
-                return;
-            }
-        }
-        final OnClientUpdateListener l;
-        synchronized(mInfoLock) {
-            l = mOnClientUpdateListener;
-        }
-        if (l != null) {
-            l.onClientTransportControlUpdate(transportControlFlags);
-        }
-    }
-
-    /**
-     * @param genId
-     * @param metadata guaranteed to be always non-null
-     */
-    private void onNewMetadata(int genId, Bundle metadata) {
-        synchronized(mGenLock) {
-            if (mClientGenerationIdCurrent != genId) {
-                return;
-            }
-        }
-        final OnClientUpdateListener l;
-        final MetadataEditor metadataEditor;
-        // prepare the received Bundle to be used inside a MetadataEditor
-        final long editableKeys = metadata.getLong(
-                String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK), 0);
-        if (editableKeys != 0) {
-            metadata.remove(String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK));
-        }
-        synchronized(mInfoLock) {
-            l = mOnClientUpdateListener;
-            if ((mMetadataEditor != null) && (mMetadataEditor.mEditorMetadata != null)) {
-                if (mMetadataEditor.mEditorMetadata != metadata) {
-                    // existing metadata, merge existing and new
-                    mMetadataEditor.mEditorMetadata.putAll(metadata);
-                }
-
-                mMetadataEditor.putBitmap(MediaMetadataEditor.BITMAP_KEY_ARTWORK,
-                        (Bitmap)metadata.getParcelable(
-                                String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK)));
-                mMetadataEditor.cleanupBitmapFromBundle(MediaMetadataEditor.BITMAP_KEY_ARTWORK);
-            } else {
-                mMetadataEditor = new MetadataEditor(metadata, editableKeys);
-            }
-            metadataEditor = mMetadataEditor;
-        }
-        if (l != null) {
-            l.onClientMetadataUpdate(metadataEditor);
-        }
-    }
-
-    private void onClientChange(int genId, boolean clearing) {
-        synchronized(mGenLock) {
-            if (mClientGenerationIdCurrent != genId) {
-                return;
-            }
-        }
+    private void onClientChange(boolean clearing) {
         final OnClientUpdateListener l;
         synchronized(mInfoLock) {
             l = mOnClientUpdateListener;
@@ -939,39 +589,6 @@ import java.util.List;
         }
     }
 
-    private void onDisplayEnable(boolean enabled) {
-        final OnClientUpdateListener l;
-        synchronized(mInfoLock) {
-            mEnabled = enabled;
-            l = this.mOnClientUpdateListener;
-        }
-        if (!enabled) {
-            // when disabling, reset all info sent to the user
-            final int genId;
-            synchronized (mGenLock) {
-                genId = mClientGenerationIdCurrent;
-            }
-            // send "stopped" state, happened "now", playback position is 0, speed 0.0f
-            final PlaybackInfo pi = new PlaybackInfo(RemoteControlClient.PLAYSTATE_STOPPED,
-                    SystemClock.elapsedRealtime() /*stateChangeTimeMs*/,
-                    0 /*currentPosMs*/, 0.0f /*speed*/);
-            sendMsg(mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE,
-                    genId /*arg1*/, 0 /*arg2, ignored*/, pi /*obj*/, 0 /*delay*/);
-            // send "blank" transport control info: no controls are supported
-            sendMsg(mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE,
-                    genId /*arg1*/, 0 /*arg2, no flags*/,
-                    null /*obj, ignored*/, 0 /*delay*/);
-            // send dummy metadata with empty string for title and artist, duration of 0
-            Bundle metadata = new Bundle(3);
-            metadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_TITLE), "");
-            metadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ARTIST), "");
-            metadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DURATION), 0);
-            sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
-                    genId /*arg1*/, 0 /*arg2, ignored*/, metadata /*obj*/, 0 /*delay*/);
-        }
-    }
-
-    ///////////// These calls are used by the new APIs with Sessions //////////////////////
     private void updateController(MediaController controller) {
         if (DEBUG) {
             Log.d(TAG, "Updating controller to " + controller + " previous controller is "
@@ -983,7 +600,7 @@ import java.util.List;
                     mCurrentSession.unregisterCallback(mSessionCb);
                     mCurrentSession = null;
                     sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
-                            0 /* genId */, 1 /* clearing */, null /* obj */, 0 /* delay */);
+                            0 /* arg1 ignored */, 1 /* clearing */, null /* obj */, 0 /* delay */);
                 }
             } else if (mCurrentSession == null
                     || !controller.getSessionToken()
@@ -992,17 +609,17 @@ import java.util.List;
                     mCurrentSession.unregisterCallback(mSessionCb);
                 }
                 sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
-                        0 /* genId */, 0 /* clearing */, null /* obj */, 0 /* delay */);
+                        0 /* arg1 ignored */, 0 /* clearing */, null /* obj */, 0 /* delay */);
                 mCurrentSession = controller;
                 mCurrentSession.registerCallback(mSessionCb, mEventHandler);
 
                 PlaybackState state = controller.getPlaybackState();
                 sendMsg(mEventHandler, MSG_NEW_PLAYBACK_STATE, SENDMSG_REPLACE,
-                        0 /* genId */, 0, state /* obj */, 0 /* delay */);
+                        0 /* arg1 ignored */, 0 /* arg2 ignored */, state /* obj */, 0 /* delay */);
 
                 MediaMetadata metadata = controller.getMetadata();
                 sendMsg(mEventHandler, MSG_NEW_MEDIA_METADATA, SENDMSG_REPLACE,
-                        0 /* arg1 */, 0 /* arg2 */, metadata /* obj */, 0 /* delay */);
+                        0 /* arg1 ignored */, 0 /* arg2 ignored*/, metadata /* obj */, 0 /*delay*/);
             }
             // else same controller, no need to update
         }
@@ -1069,38 +686,6 @@ import java.util.List;
 
     /**
      * @hide
-     * Used by AudioManager to mark this instance as registered.
-     * @param registered
-     */
-    void setIsRegistered(boolean registered) {
-        synchronized (mInfoLock) {
-            mIsRegistered = registered;
-        }
-    }
-
-    /**
-     * @hide
-     * Used by AudioManager to access binder to be registered/unregistered inside MediaFocusControl
-     * @return
-     */
-    RcDisplay getRcDisplay() {
-        return mRcd;
-    }
-
-    /**
-     * @hide
-     * Used by AudioManager to read the current artwork dimension
-     * @return array containing width (index 0) and height (index 1) of currently set artwork size
-     */
-    int[] getArtworkSize() {
-        synchronized (mInfoLock) {
-            int[] size = { mArtworkWidth, mArtworkHeight };
-            return size;
-        }
-    }
-
-    /**
-     * @hide
      * Used by AudioManager to access user listener receiving the client update notifications
      * @return
      */
index 75886aa..4f2f486 100644 (file)
@@ -62,7 +62,6 @@ import android.media.AudioRoutesInfo;
 import android.media.IAudioFocusDispatcher;
 import android.media.IAudioRoutesObserver;
 import android.media.IAudioService;
-import android.media.IRemoteControlDisplay;
 import android.media.IRingtonePlayer;
 import android.media.IVolumeController;
 import android.media.MediaPlayer;
@@ -667,8 +666,7 @@ public class AudioService extends IAudioService.Stub {
         mSettingsObserver = new SettingsObserver();
         createStreamStates();
 
-        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
-                mContext, mVolumeController, this);
+        mMediaFocusControl = new MediaFocusControl(mContext);
 
         readAndSetLowRamDevice();
 
@@ -5235,36 +5233,6 @@ public class AudioService extends IAudioService.Stub {
         }
     }
 
-    //==========================================================================================
-    // RemoteControlDisplay / RemoteControlClient / Remote info
-    //==========================================================================================
-    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
-            ComponentName listenerComp) {
-        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
-    }
-
-    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
-        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
-    }
-
-    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
-        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
-    }
-
-    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
-        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
-    }
-
-    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
-            boolean wantsSync) {
-        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
-    }
-
-    @Override
-    public void setRemoteStreamVolume(int index) {
-        enforceVolumeController("set the remote stream volume");
-        mMediaFocusControl.setRemoteStreamVolume(index);
-    }
 
     //==========================================================================================
     // Audio Focus
index f72b598..d44d89d 100644 (file)
 
 package com.android.server.audio;
 
-import android.app.Activity;
-import android.app.ActivityManager;
 import android.app.AppOpsManager;
-import android.app.KeyguardManager;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.app.PendingIntent.OnFinished;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.database.ContentObserver;
 import android.media.AudioAttributes;
 import android.media.AudioFocusInfo;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.IAudioFocusDispatcher;
-import android.media.IRemoteControlClient;
-import android.media.IRemoteControlDisplay;
-import android.media.IRemoteVolumeObserver;
-import android.media.RemoteControlClient;
 import android.media.audiopolicy.IAudioPolicyCallback;
-import android.net.Uri;
 import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.IDeviceIdleController;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
 import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.speech.RecognizerIntent;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
 import android.util.Log;
-import android.util.Slog;
-import android.view.KeyEvent;
-
-import com.android.server.audio.PlayerRecord.RemotePlaybackState;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -74,329 +40,22 @@ import java.text.DateFormat;
  * @hide
  *
  */
-public class MediaFocusControl implements OnFinished {
+public class MediaFocusControl {
 
     private static final String TAG = "MediaFocusControl";
 
-    /** Debug remote control client/display feature */
-    protected static final boolean DEBUG_RC = false;
-    /** Debug volumes */
-    protected static final boolean DEBUG_VOL = false;
-
-    /** Used to alter media button redirection when the phone is ringing. */
-    private boolean mIsRinging = false;
-
-    private final PowerManager.WakeLock mMediaEventWakeLock;
-    private final MediaEventHandler mEventHandler;
     private final Context mContext;
-    private final ContentResolver mContentResolver;
-    private final AudioService.VolumeController mVolumeController;
     private final AppOpsManager mAppOps;
-    private final KeyguardManager mKeyguardManager;
-    private final AudioService mAudioService;
-    private final NotificationListenerObserver mNotifListenerObserver;
 
-    protected MediaFocusControl(Looper looper, Context cntxt,
-            AudioService.VolumeController volumeCtrl, AudioService as) {
-        mEventHandler = new MediaEventHandler(looper);
+    protected MediaFocusControl(Context cntxt) {
         mContext = cntxt;
-        mContentResolver = mContext.getContentResolver();
-        mVolumeController = volumeCtrl;
-        mAudioService = as;
-
-        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
-        int maxMusicLevel = as.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
-        mMainRemote = new RemotePlaybackState(-1, maxMusicLevel, maxMusicLevel);
-
-        // Register for phone state monitoring
-        TelephonyManager tmgr = (TelephonyManager)
-                mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
-
         mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
-        mKeyguardManager =
-                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        mNotifListenerObserver = new NotificationListenerObserver();
-
-        mHasRemotePlayback = false;
-        mMainRemoteIsActive = false;
-
-        PlayerRecord.setMediaFocusControl(this);
-
-        postReevaluateRemote();
     }
 
     protected void dump(PrintWriter pw) {
         pw.println("\nMediaFocusControl dump time: "
                 + DateFormat.getTimeInstance().format(new Date()));
         dumpFocusStack(pw);
-        dumpRCStack(pw);
-        dumpRCCStack(pw);
-        dumpRCDList(pw);
-    }
-
-    //==========================================================================================
-    // Management of RemoteControlDisplay registration permissions
-    //==========================================================================================
-    private final static Uri ENABLED_NOTIFICATION_LISTENERS_URI =
-            Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-
-    private class NotificationListenerObserver extends ContentObserver {
-
-        NotificationListenerObserver() {
-            super(mEventHandler);
-            mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ENABLED_NOTIFICATION_LISTENERS), false, this);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            if (!ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri) || selfChange) {
-                return;
-            }
-            if (DEBUG_RC) { Log.d(TAG, "NotificationListenerObserver.onChange()"); }
-            postReevaluateRemoteControlDisplays();
-        }
-    }
-
-    private final static int RCD_REG_FAILURE = 0;
-    private final static int RCD_REG_SUCCESS_PERMISSION = 1;
-    private final static int RCD_REG_SUCCESS_ENABLED_NOTIF = 2;
-
-    /**
-     * Checks a caller's authorization to register an IRemoteControlDisplay.
-     * Authorization is granted if one of the following is true:
-     * <ul>
-     * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL permission</li>
-     * <li>the caller's listener is one of the enabled notification listeners</li>
-     * </ul>
-     * @return RCD_REG_FAILURE if it's not safe to proceed with the IRemoteControlDisplay
-     *     registration.
-     */
-    private int checkRcdRegistrationAuthorization(ComponentName listenerComp) {
-        // MEDIA_CONTENT_CONTROL permission check
-        if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.MEDIA_CONTENT_CONTROL)) {
-            if (DEBUG_RC) { Log.d(TAG, "ok to register Rcd: has MEDIA_CONTENT_CONTROL permission");}
-            return RCD_REG_SUCCESS_PERMISSION;
-        }
-
-        // ENABLED_NOTIFICATION_LISTENERS settings check
-        if (listenerComp != null) {
-            // this call is coming from an app, can't use its identity to read secure settings
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                final int currentUser = ActivityManager.getCurrentUser();
-                final String enabledNotifListeners = Settings.Secure.getStringForUser(
-                        mContext.getContentResolver(),
-                        Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
-                        currentUser);
-                if (enabledNotifListeners != null) {
-                    final String[] components = enabledNotifListeners.split(":");
-                    for (int i=0; i<components.length; i++) {
-                        final ComponentName component =
-                                ComponentName.unflattenFromString(components[i]);
-                        if (component != null) {
-                            if (listenerComp.equals(component)) {
-                                if (DEBUG_RC) { Log.d(TAG, "ok to register RCC: " + component +
-                                        " is authorized notification listener"); }
-                                return RCD_REG_SUCCESS_ENABLED_NOTIF;
-                            }
-                        }
-                    }
-                }
-                if (DEBUG_RC) { Log.d(TAG, "not ok to register RCD, " + listenerComp +
-                        " is not in list of ENABLED_NOTIFICATION_LISTENERS"); }
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-
-        return RCD_REG_FAILURE;
-    }
-
-    protected boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
-            ComponentName listenerComp) {
-        int reg = checkRcdRegistrationAuthorization(listenerComp);
-        if (reg != RCD_REG_FAILURE) {
-            registerRemoteControlDisplay_int(rcd, w, h, listenerComp);
-            return true;
-        } else {
-            Slog.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
-                    ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
-                    " or be an enabled NotificationListenerService for registerRemoteController");
-            return false;
-        }
-    }
-
-    protected boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
-        int reg = checkRcdRegistrationAuthorization(null);
-        if (reg != RCD_REG_FAILURE) {
-            registerRemoteControlDisplay_int(rcd, w, h, null);
-            return true;
-        } else {
-            Slog.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
-                    ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
-                    " to register IRemoteControlDisplay");
-            return false;
-        }
-    }
-
-    private void postReevaluateRemoteControlDisplays() {
-        sendMsg(mEventHandler, MSG_REEVALUATE_RCD, SENDMSG_QUEUE, 0, 0, null, 0);
-    }
-
-    private void onReevaluateRemoteControlDisplays() {
-        if (DEBUG_RC) { Log.d(TAG, "onReevaluateRemoteControlDisplays()"); }
-        // read which components are enabled notification listeners
-        final int currentUser = ActivityManager.getCurrentUser();
-        final String enabledNotifListeners = Settings.Secure.getStringForUser(
-                mContext.getContentResolver(),
-                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
-                currentUser);
-        if (DEBUG_RC) { Log.d(TAG, " > enabled list: " + enabledNotifListeners); }
-        synchronized(mAudioFocusLock) {
-            synchronized(mPRStack) {
-                // check whether the "enable" status of each RCD with a notification listener
-                // has changed
-                final String[] enabledComponents;
-                if (enabledNotifListeners == null) {
-                    enabledComponents = null;
-                } else {
-                    enabledComponents = enabledNotifListeners.split(":");
-                }
-                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-                while (displayIterator.hasNext()) {
-                    final DisplayInfoForServer di =
-                            displayIterator.next();
-                    if (di.mClientNotifListComp != null) {
-                        boolean wasEnabled = di.mEnabled;
-                        di.mEnabled = isComponentInStringArray(di.mClientNotifListComp,
-                                enabledComponents);
-                        if (wasEnabled != di.mEnabled){
-                            try {
-                                // tell the RCD whether it's enabled
-                                di.mRcDisplay.setEnabled(di.mEnabled);
-                                // tell the RCCs about the change for this RCD
-                                enableRemoteControlDisplayForClient_syncRcStack(
-                                        di.mRcDisplay, di.mEnabled);
-                                // when enabling, refresh the information on the display
-                                if (di.mEnabled) {
-                                    sendMsg(mEventHandler, MSG_RCDISPLAY_INIT_INFO, SENDMSG_QUEUE,
-                                            di.mArtworkExpectedWidth /*arg1*/,
-                                            di.mArtworkExpectedHeight/*arg2*/,
-                                            di.mRcDisplay /*obj*/, 0/*delay*/);
-                                }
-                            } catch (RemoteException e) {
-                                Log.e(TAG, "Error en/disabling RCD: ", e);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * @param comp a non-null ComponentName
-     * @param enabledArray may be null
-     * @return
-     */
-    private boolean isComponentInStringArray(ComponentName comp, String[] enabledArray) {
-        if (enabledArray == null || enabledArray.length == 0) {
-            if (DEBUG_RC) { Log.d(TAG, " > " + comp + " is NOT enabled"); }
-            return false;
-        }
-        final String compString = comp.flattenToString();
-        for (int i=0; i<enabledArray.length; i++) {
-            if (compString.equals(enabledArray[i])) {
-                if (DEBUG_RC) { Log.d(TAG, " > " + compString + " is enabled"); }
-                return true;
-            }
-        }
-        if (DEBUG_RC) { Log.d(TAG, " > " + compString + " is NOT enabled"); }
-        return false;
-    }
-
-    //==========================================================================================
-    // Internal event handling
-    //==========================================================================================
-
-    // event handler messages
-    private static final int MSG_RCDISPLAY_CLEAR = 1;
-    private static final int MSG_RCDISPLAY_UPDATE = 2;
-    private static final int MSG_REEVALUATE_REMOTE = 3;
-    private static final int MSG_RCC_NEW_PLAYBACK_INFO = 4;
-    private static final int MSG_RCC_NEW_VOLUME_OBS = 5;
-    private static final int MSG_RCC_NEW_PLAYBACK_STATE = 6;
-    private static final int MSG_RCC_SEEK_REQUEST = 7;
-    private static final int MSG_RCC_UPDATE_METADATA = 8;
-    private static final int MSG_RCDISPLAY_INIT_INFO = 9;
-    private static final int MSG_REEVALUATE_RCD = 10;
-    private static final int MSG_UNREGISTER_MEDIABUTTONINTENT = 11;
-
-    // sendMsg() flags
-    /** If the msg is already queued, replace it with this one. */
-    private static final int SENDMSG_REPLACE = 0;
-    /** If the msg is already queued, ignore this one and leave the old. */
-    private static final int SENDMSG_NOOP = 1;
-    /** If the msg is already queued, queue this one and leave the old. */
-    private static final int SENDMSG_QUEUE = 2;
-
-    private static void sendMsg(Handler handler, int msg,
-            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
-
-        if (existingMsgPolicy == SENDMSG_REPLACE) {
-            handler.removeMessages(msg);
-        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
-            return;
-        }
-
-        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
-    }
-
-    private class MediaEventHandler extends Handler {
-        MediaEventHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-                case MSG_RCDISPLAY_CLEAR:
-                    onRcDisplayClear();
-                    break;
-
-                case MSG_RCDISPLAY_UPDATE:
-                    // msg.obj is guaranteed to be non null
-                    onRcDisplayUpdate( (PlayerRecord) msg.obj, msg.arg1);
-                    break;
-
-                case MSG_REEVALUATE_REMOTE:
-                    onReevaluateRemote();
-                    break;
-
-                case MSG_RCC_NEW_VOLUME_OBS:
-                    onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
-                            (IRemoteVolumeObserver)msg.obj /* rvo */);
-                    break;
-
-                case MSG_RCDISPLAY_INIT_INFO:
-                    // msg.obj is guaranteed to be non null
-                    onRcDisplayInitInfo((IRemoteControlDisplay)msg.obj /*newRcd*/,
-                            msg.arg1/*w*/, msg.arg2/*h*/);
-                    break;
-
-                case MSG_REEVALUATE_RCD:
-                    onReevaluateRemoteControlDisplays();
-                    break;
-
-                case MSG_UNREGISTER_MEDIABUTTONINTENT:
-                    unregisterMediaButtonIntent( (PendingIntent) msg.obj );
-                    break;
-            }
-        }
     }
 
 
@@ -406,25 +65,6 @@ public class MediaFocusControl implements OnFinished {
 
     private final static Object mAudioFocusLock = new Object();
 
-    private final static Object mRingingLock = new Object();
-
-    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
-            if (state == TelephonyManager.CALL_STATE_RINGING) {
-                //Log.v(TAG, " CALL_STATE_RINGING");
-                synchronized(mRingingLock) {
-                    mIsRinging = true;
-                }
-            } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK)
-                    || (state == TelephonyManager.CALL_STATE_IDLE)) {
-                synchronized(mRingingLock) {
-                    mIsRinging = false;
-                }
-            }
-        }
-    };
-
     /**
      * Discard the current audio focus owner.
      * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
@@ -865,1374 +505,4 @@ public class MediaFocusControl implements OnFinished {
         }
     }
 
-
-    //==========================================================================================
-    // RemoteControl
-    //==========================================================================================
-    /**
-     * No-op if the key code for keyEvent is not a valid media key
-     * (see {@link #isValidMediaKeyEvent(KeyEvent)})
-     * @param keyEvent the key event to send
-     */
-    protected void dispatchMediaKeyEvent(KeyEvent keyEvent) {
-        filterMediaKeyEvent(keyEvent, false /*needWakeLock*/);
-    }
-
-    /**
-     * No-op if the key code for keyEvent is not a valid media key
-     * (see {@link #isValidMediaKeyEvent(KeyEvent)})
-     * @param keyEvent the key event to send
-     */
-    protected void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
-        filterMediaKeyEvent(keyEvent, true /*needWakeLock*/);
-    }
-
-    private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        // sanity check on the incoming key event
-        if (!isValidMediaKeyEvent(keyEvent)) {
-            Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
-            return;
-        }
-        // event filtering for telephony
-        synchronized(mRingingLock) {
-            synchronized(mPRStack) {
-                if ((mMediaReceiverForCalls != null) &&
-                        (mIsRinging || (mAudioService.getMode() == AudioSystem.MODE_IN_CALL))) {
-                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
-                    return;
-                }
-            }
-        }
-        // event filtering based on voice-based interactions
-        if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
-            filterVoiceInputKeyEvent(keyEvent, needWakeLock);
-        } else {
-            dispatchMediaKeyEvent(keyEvent, needWakeLock);
-        }
-    }
-
-    /**
-     * Handles the dispatching of the media button events to the telephony package.
-     * Precondition: mMediaReceiverForCalls != null
-     * @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.
-     */
-    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
-        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
-        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
-        }
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
-                    null, mKeyEventDone, mEventHandler, Activity.RESULT_OK, null, null);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    /**
-     * 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.
-     */
-    private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-        }
-        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
-        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        synchronized(mPRStack) {
-            if (!mPRStack.empty()) {
-                // send the intent that was registered by the client
-                try {
-                    mPRStack.peek().getMediaButtonIntent().send(mContext,
-                            needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
-                            keyIntent, this, mEventHandler);
-                } catch (CanceledException e) {
-                    Log.e(TAG, "Error sending pending intent " + mPRStack.peek());
-                    e.printStackTrace();
-                }
-            } else {
-                // legacy behavior when nobody registered their media button event receiver
-                //    through AudioManager
-                if (needWakeLock) {
-                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
-                }
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
-                            null, mKeyEventDone,
-                            mEventHandler, Activity.RESULT_OK, null, null);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-            }
-        }
-    }
-
-    /**
-     * The different actions performed in response to a voice button key event.
-     */
-    private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
-    private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
-    private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
-
-    private final Object mVoiceEventLock = new Object();
-    private boolean mVoiceButtonDown;
-    private boolean mVoiceButtonHandled;
-
-    /**
-     * Filter key events that may be used for voice-based interactions
-     * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported
-     *    media buttons that can be used to trigger voice-based interactions.
-     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
-     *     is dispatched.
-     */
-    private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        if (DEBUG_RC) {
-            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
-        }
-
-        int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
-        int keyAction = keyEvent.getAction();
-        synchronized (mVoiceEventLock) {
-            if (keyAction == KeyEvent.ACTION_DOWN) {
-                if (keyEvent.getRepeatCount() == 0) {
-                    // initial down
-                    mVoiceButtonDown = true;
-                    mVoiceButtonHandled = false;
-                } else if (mVoiceButtonDown && !mVoiceButtonHandled
-                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
-                    // long-press, start voice-based interactions
-                    mVoiceButtonHandled = true;
-                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
-                }
-            } else if (keyAction == KeyEvent.ACTION_UP) {
-                if (mVoiceButtonDown) {
-                    // voice button up
-                    mVoiceButtonDown = false;
-                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
-                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
-                    }
-                }
-            }
-        }//synchronized (mVoiceEventLock)
-
-        // take action after media button event filtering for voice-based interactions
-        switch (voiceButtonAction) {
-            case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS:
-                if (DEBUG_RC) Log.v(TAG, "   ignore key event");
-                break;
-            case VOICEBUTTON_ACTION_START_VOICE_INPUT:
-                if (DEBUG_RC) Log.v(TAG, "   start voice-based interactions");
-                // then start the voice-based interactions
-                startVoiceBasedInteractions(needWakeLock);
-                break;
-            case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS:
-                if (DEBUG_RC) Log.v(TAG, "   send simulated key event, wakelock=" + needWakeLock);
-                sendSimulatedMediaButtonEvent(keyEvent, needWakeLock);
-                break;
-        }
-    }
-
-    private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) {
-        // send DOWN event
-        KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN);
-        dispatchMediaKeyEvent(keyEvent, needWakeLock);
-        // send UP event
-        keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP);
-        dispatchMediaKeyEvent(keyEvent, needWakeLock);
-
-    }
-
-    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
-        if (keyEvent == null) {
-            return false;
-        }
-        return KeyEvent.isMediaKey(keyEvent.getKeyCode());
-    }
-
-    /**
-     * Checks whether the given key code is one that can trigger the launch of voice-based
-     *   interactions.
-     * @param keyCode the key code associated with the key event
-     * @return true if the key is one of the supported voice-based interaction triggers
-     */
-    private static boolean isValidVoiceInputKeyCode(int keyCode) {
-        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Tell the system to start voice-based interactions / voice commands
-     */
-    private void startVoiceBasedInteractions(boolean needWakeLock) {
-        Intent voiceIntent = null;
-        // select which type of search to launch:
-        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
-        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
-        //    with EXTRA_SECURE set to true if the device is securely locked
-        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
-        if (!isLocked && pm.isScreenOn()) {
-            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
-            Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
-        } else {
-            IDeviceIdleController dic = IDeviceIdleController.Stub.asInterface(
-                    ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
-            if (dic != null) {
-                try {
-                    dic.exitIdle("voice-search");
-                } catch (RemoteException e) {
-                }
-            }
-            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
-                    isLocked && mKeyguardManager.isKeyguardSecure());
-            Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
-        }
-        // start the search activity
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            if (voiceIntent != null) {
-                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT);
-            }
-        } catch (ActivityNotFoundException e) {
-            Log.w(TAG, "No activity for search: " + e);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-            if (needWakeLock) {
-                mMediaEventWakeLock.release();
-            }
-        }
-    }
-
-    private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
-
-    // only set when wakelock was acquired, no need to check value when received
-    private static final String EXTRA_WAKELOCK_ACQUIRED =
-            "android.media.AudioService.WAKELOCK_ACQUIRED";
-
-    public void onSendFinished(PendingIntent pendingIntent, Intent intent,
-            int resultCode, String resultData, Bundle resultExtras) {
-        if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
-            mMediaEventWakeLock.release();
-        }
-    }
-
-    BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            if (intent == null) {
-                return;
-            }
-            Bundle extras = intent.getExtras();
-            if (extras == null) {
-                return;
-            }
-            if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
-                mMediaEventWakeLock.release();
-            }
-        }
-    };
-
-    /**
-     * Synchronization on mCurrentRcLock always inside a block synchronized on mPRStack
-     */
-    private final Object mCurrentRcLock = new Object();
-    /**
-     * The one remote control client which will receive a request for display information.
-     * This object may be null.
-     * Access protected by mCurrentRcLock.
-     */
-    private IRemoteControlClient mCurrentRcClient = null;
-    /**
-     * The PendingIntent associated with mCurrentRcClient. Its value is irrelevant
-     * if mCurrentRcClient is null
-     */
-    private PendingIntent mCurrentRcClientIntent = null;
-
-    private final static int RC_INFO_NONE = 0;
-    private final static int RC_INFO_ALL =
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
-
-    /**
-     * A monotonically increasing generation counter for mCurrentRcClient.
-     * Only accessed with a lock on mCurrentRcLock.
-     * No value wrap-around issues as we only act on equal values.
-     */
-    private int mCurrentRcClientGen = 0;
-
-
-    /**
-     * Internal cache for the playback information of the RemoteControlClient whose volume gets to
-     * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack
-     * every time we need this info.
-     */
-    private RemotePlaybackState mMainRemote;
-    /**
-     * Indicates whether the "main" RemoteControlClient is considered active.
-     * Use synchronized on mMainRemote.
-     */
-    private boolean mMainRemoteIsActive;
-    /**
-     * Indicates whether there is remote playback going on. True even if there is no "active"
-     * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it
-     * handles remote playback.
-     * Use synchronized on mMainRemote.
-     */
-    private boolean mHasRemotePlayback;
-
-    /**
-     * The stack of remote control event receivers.
-     * All read and write operations on mPRStack are synchronized.
-     */
-    private final Stack<PlayerRecord> mPRStack = new Stack<PlayerRecord>();
-
-    /**
-     * The component the telephony package can register so telephony calls have priority to
-     * handle media button events
-     */
-    private ComponentName mMediaReceiverForCalls = null;
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the remote control focus stack
-     */
-    private void dumpRCStack(PrintWriter pw) {
-        pw.println("\nRemote Control stack entries (last is top of stack):");
-        synchronized(mPRStack) {
-            Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-            while(stackIterator.hasNext()) {
-                stackIterator.next().dump(pw, true);
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the remote control stack, focusing
-     * on RemoteControlClient data
-     */
-    private void dumpRCCStack(PrintWriter pw) {
-        pw.println("\nRemote Control Client stack entries (last is top of stack):");
-        synchronized(mPRStack) {
-            Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-            while(stackIterator.hasNext()) {
-                stackIterator.next().dump(pw, false);
-            }
-            synchronized(mCurrentRcLock) {
-                pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen);
-            }
-        }
-        synchronized (mMainRemote) {
-            pw.println("\nRemote Volume State:");
-            pw.println("  has remote: " + mHasRemotePlayback);
-            pw.println("  is remote active: " + mMainRemoteIsActive);
-            pw.println("  rccId: " + mMainRemote.mRccId);
-            pw.println("  volume handling: "
-                    + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ?
-                            "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)"));
-            pw.println("  volume: " + mMainRemote.mVolume);
-            pw.println("  volume steps: " + mMainRemote.mVolumeMax);
-        }
-    }
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the list of remote control displays
-     */
-    private void dumpRCDList(PrintWriter pw) {
-        pw.println("\nRemote Control Display list entries:");
-        synchronized(mPRStack) {
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForServer di = displayIterator.next();
-                pw.println("  IRCD: " + di.mRcDisplay +
-                        "  -- w:" + di.mArtworkExpectedWidth +
-                        "  -- h:" + di.mArtworkExpectedHeight +
-                        "  -- wantsPosSync:" + di.mWantsPositionSync +
-                        "  -- " + (di.mEnabled ? "enabled" : "disabled"));
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Push the new media button receiver "near" the top of the PlayerRecord stack.
-     * "Near the top" is defined as:
-     *   - at the top if the current PlayerRecord at the top is not playing
-     *   - below the entries at the top of the stack that correspond to the playing PlayerRecord
-     *     otherwise
-     * Called synchronized on mPRStack
-     * precondition: mediaIntent != null
-     * @return true if the top of mPRStack was changed, false otherwise
-     */
-    private boolean pushMediaButtonReceiver_syncPrs(PendingIntent mediaIntent,
-            ComponentName target, IBinder token) {
-        if (mPRStack.empty()) {
-            mPRStack.push(new PlayerRecord(mediaIntent, target, token));
-            return true;
-        } else if (mPRStack.peek().hasMatchingMediaButtonIntent(mediaIntent)) {
-            // already at top of stack
-            return false;
-        }
-        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(),
-                mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) {
-            return false;
-        }
-        PlayerRecord oldTopPrse = mPRStack.lastElement(); // top of the stack before any changes
-        boolean topChanged = false;
-        PlayerRecord prse = null;
-        int lastPlayingIndex = mPRStack.size();
-        int inStackIndex = -1;
-        try {
-            // go through the stack from the top to figure out who's playing, and the position
-            // of this media button receiver (note that it may not be in the stack)
-            for (int index = mPRStack.size()-1; index >= 0; index--) {
-                prse = mPRStack.elementAt(index);
-                if (prse.isPlaybackActive()) {
-                    lastPlayingIndex = index;
-                }
-                if (prse.hasMatchingMediaButtonIntent(mediaIntent)) {
-                    inStackIndex = index;
-                }
-            }
-
-            if (inStackIndex == -1) {
-                // is not in stack
-                prse = new PlayerRecord(mediaIntent, target, token);
-                // it's new so it's not playing (no RemoteControlClient to give a playstate),
-                // therefore it goes after the ones with active playback
-                mPRStack.add(lastPlayingIndex, prse);
-            } else {
-                // is in the stack
-                if (mPRStack.size() > 1) { // no need to remove and add if stack contains only 1
-                    prse = mPRStack.elementAt(inStackIndex);
-                    // remove it from its old location in the stack
-                    mPRStack.removeElementAt(inStackIndex);
-                    if (prse.isPlaybackActive()) {
-                        // and put it at the top
-                        mPRStack.push(prse);
-                    } else {
-                        // and put it after the ones with active playback
-                        if (inStackIndex > lastPlayingIndex) {
-                            mPRStack.add(lastPlayingIndex, prse);
-                        } else {
-                            mPRStack.add(lastPlayingIndex - 1, prse);
-                        }
-                    }
-                }
-            }
-
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // not expected to happen, indicates improper concurrent modification or bad index
-            Log.e(TAG, "Wrong index (inStack=" + inStackIndex + " lastPlaying=" + lastPlayingIndex
-                    + " size=" + mPRStack.size()
-                    + " accessing media button stack", e);
-        }
-
-        return (topChanged);
-    }
-
-    /**
-     * Helper function:
-     * Remove the remote control receiver from the RC focus stack.
-     * Called synchronized on mPRStack
-     * precondition: pi != null
-     */
-    private void removeMediaButtonReceiver_syncPrs(PendingIntent pi) {
-        try {
-            for (int index = mPRStack.size()-1; index >= 0; index--) {
-                final PlayerRecord prse = mPRStack.elementAt(index);
-                if (prse.hasMatchingMediaButtonIntent(pi)) {
-                    prse.destroy();
-                    // ok to remove element while traversing the stack since we're leaving the loop
-                    mPRStack.removeElementAt(index);
-                    break;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // not expected to happen, indicates improper concurrent modification
-            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-        }
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mPRStack
-     */
-    private boolean isCurrentRcController(PendingIntent pi) {
-        if (!mPRStack.empty() && mPRStack.peek().hasMatchingMediaButtonIntent(pi)) {
-            return true;
-        }
-        return false;
-    }
-
-    //==========================================================================================
-    // Remote control display / client
-    //==========================================================================================
-    /**
-     * Update the remote control displays with the new "focused" client generation
-     */
-    private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
-            PendingIntent newMediaIntent, boolean clearing) {
-        synchronized(mPRStack) {
-            if (mRcDisplays.size() > 0) {
-                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-                while (displayIterator.hasNext()) {
-                    final DisplayInfoForServer di = displayIterator.next();
-                    try {
-                        di.mRcDisplay.setCurrentClientId(
-                                newClientGeneration, newMediaIntent, clearing);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e);
-                        di.release();
-                        displayIterator.remove();
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Update the remote control clients with the new "focused" client generation
-     */
-    private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
-        // (using an iterator on the stack so we can safely remove an entry if needed,
-        //  traversal order doesn't matter here as we update all entries)
-        Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-        while(stackIterator.hasNext()) {
-            PlayerRecord se = stackIterator.next();
-            if ((se != null) && (se.getRcc() != null)) {
-                try {
-                    se.getRcc().setCurrentClientGenerationId(newClientGeneration);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e);
-                    stackIterator.remove();
-                    se.unlinkToRcClientDeath();
-                }
-            }
-        }
-    }
-
-    /**
-     * Update the displays and clients with the new "focused" client generation and name
-     * @param newClientGeneration the new generation value matching a client update
-     * @param newMediaIntent the media button event receiver associated with the client.
-     *    May be null, which implies there is no registered media button event receiver.
-     * @param clearing true if the new client generation value maps to a remote control update
-     *    where the display should be cleared.
-     */
-    private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
-            PendingIntent newMediaIntent, boolean clearing) {
-        // send the new valid client generation ID to all displays
-        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
-        // send the new valid client generation ID to all clients
-        setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
-    }
-
-    /**
-     * Called when processing MSG_RCDISPLAY_CLEAR event
-     */
-    private void onRcDisplayClear() {
-        if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
-
-        synchronized(mPRStack) {
-            synchronized(mCurrentRcLock) {
-                mCurrentRcClientGen++;
-                // synchronously update the displays and clients with the new client generation
-                setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
-                        null /*newMediaIntent*/, true /*clearing*/);
-            }
-        }
-    }
-
-    /**
-     * Called when processing MSG_RCDISPLAY_UPDATE event
-     */
-    private void onRcDisplayUpdate(PlayerRecord prse, int flags /* USED ?*/) {
-        synchronized(mPRStack) {
-            synchronized(mCurrentRcLock) {
-                if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(prse.getRcc()))) {
-                    if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
-
-                    mCurrentRcClientGen++;
-                    // synchronously update the displays and clients with
-                    //      the new client generation
-                    setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
-                            prse.getMediaButtonIntent() /*newMediaIntent*/,
-                            false /*clearing*/);
-
-                    // tell the current client that it needs to send info
-                    try {
-                        //TODO change name to informationRequestForAllDisplays()
-                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Current valid remote client is dead: "+e);
-                        mCurrentRcClient = null;
-                    }
-                } else {
-                    // the remote control display owner has changed between the
-                    // the message to update the display was sent, and the time it
-                    // gets to be processed (now)
-                }
-            }
-        }
-    }
-
-    /**
-     * Called when processing MSG_RCDISPLAY_INIT_INFO event
-     * Causes the current RemoteControlClient to send its info (metadata, playstate...) to
-     *   a single RemoteControlDisplay, NOT all of them, as with MSG_RCDISPLAY_UPDATE.
-     */
-    private void onRcDisplayInitInfo(IRemoteControlDisplay newRcd, int w, int h) {
-        synchronized(mPRStack) {
-            synchronized(mCurrentRcLock) {
-                if (mCurrentRcClient != null) {
-                    if (DEBUG_RC) { Log.i(TAG, "Init RCD with current info"); }
-                    try {
-                        // synchronously update the new RCD with the current client generation
-                        // and matching PendingIntent
-                        newRcd.setCurrentClientId(mCurrentRcClientGen, mCurrentRcClientIntent,
-                                false);
-
-                        // tell the current RCC that it needs to send info, but only to the new RCD
-                        try {
-                            mCurrentRcClient.informationRequestForDisplay(newRcd, w, h);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Current valid remote client is dead: ", e);
-                            mCurrentRcClient = null;
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Dead display in onRcDisplayInitInfo()", e);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mPRStack
-     */
-    private void clearRemoteControlDisplay_syncPrs() {
-        synchronized(mCurrentRcLock) {
-            mCurrentRcClient = null;
-        }
-        // will cause onRcDisplayClear() to be called in AudioService's handler thread
-        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
-    }
-
-    /**
-     * Helper function for code readability: only to be called from
-     *    checkUpdateRemoteControlDisplay_syncPrs() which checks the preconditions for
-     *    this method.
-     * Preconditions:
-     *    - called synchronized on mPRStack
-     *    - mPRStack.isEmpty() is false
-     */
-    private void updateRemoteControlDisplay_syncPrs(int infoChangedFlags) {
-        PlayerRecord prse = mPRStack.peek();
-        int infoFlagsAboutToBeUsed = infoChangedFlags;
-        // this is where we enforce opt-in for information display on the remote controls
-        //   with the new AudioManager.registerRemoteControlClient() API
-        if (prse.getRcc() == null) {
-            //Log.w(TAG, "Can't update remote control display with null remote control client");
-            clearRemoteControlDisplay_syncPrs();
-            return;
-        }
-        synchronized(mCurrentRcLock) {
-            if (!prse.getRcc().equals(mCurrentRcClient)) {
-                // new RC client, assume every type of information shall be queried
-                infoFlagsAboutToBeUsed = RC_INFO_ALL;
-            }
-            mCurrentRcClient = prse.getRcc();
-            mCurrentRcClientIntent = prse.getMediaButtonIntent();
-        }
-        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
-        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
-                infoFlagsAboutToBeUsed /* arg1 */, 0, prse /* obj, != null */) );
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mPRStack
-     * Check whether the remote control display should be updated, triggers the update if required
-     * @param infoChangedFlags the flags corresponding to the remote control client information
-     *     that has changed, if applicable (checking for the update conditions might trigger a
-     *     clear, rather than an update event).
-     */
-    private void checkUpdateRemoteControlDisplay_syncPrs(int infoChangedFlags) {
-        // determine whether the remote control display should be refreshed
-        // if the player record stack is empty, there is nothing to display, so clear the RC display
-        if (mPRStack.isEmpty()) {
-            clearRemoteControlDisplay_syncPrs();
-            return;
-        }
-
-        // this is where more rules for refresh go
-
-        // refresh conditions were verified: update the remote controls
-        // ok to call: synchronized on mPRStack, mPRStack is not empty
-        updateRemoteControlDisplay_syncPrs(infoChangedFlags);
-    }
-
-    /**
-     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
-     * precondition: mediaIntent != null
-     */
-    protected void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver,
-            IBinder token) {
-        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
-
-        synchronized(mPRStack) {
-            if (pushMediaButtonReceiver_syncPrs(mediaIntent, eventReceiver, token)) {
-                // new RC client, assume every type of information shall be queried
-                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
-            }
-        }
-    }
-
-    /**
-     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
-     * precondition: mediaIntent != null, eventReceiver != null
-     */
-    protected void unregisterMediaButtonIntent(PendingIntent mediaIntent)
-    {
-        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
-
-        synchronized(mPRStack) {
-            boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
-            removeMediaButtonReceiver_syncPrs(mediaIntent);
-            if (topOfStackWillChange) {
-                // current RC client will change, assume every type of info needs to be queried
-                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
-            }
-        }
-    }
-
-    protected void unregisterMediaButtonIntentAsync(final PendingIntent mediaIntent) {
-        mEventHandler.sendMessage(
-                mEventHandler.obtainMessage(MSG_UNREGISTER_MEDIABUTTONINTENT, 0, 0,
-                        mediaIntent));
-    }
-
-    /**
-     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
-     * precondition: c != null
-     */
-    protected void registerMediaButtonEventReceiverForCalls(ComponentName c) {
-        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
-                != PackageManager.PERMISSION_GRANTED) {
-            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
-            return;
-        }
-        synchronized(mPRStack) {
-            mMediaReceiverForCalls = c;
-        }
-    }
-
-    /**
-     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
-     */
-    protected void unregisterMediaButtonEventReceiverForCalls() {
-        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
-                != PackageManager.PERMISSION_GRANTED) {
-            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
-            return;
-        }
-        synchronized(mPRStack) {
-            mMediaReceiverForCalls = null;
-        }
-    }
-
-    /**
-     * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
-     * @return the unique ID of the PlayerRecord associated with the RemoteControlClient
-     * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
-     *     without modifying the RC stack, but while still causing the display to refresh (will
-     *     become blank as a result of this)
-     */
-    protected int registerRemoteControlClient(PendingIntent mediaIntent,
-            IRemoteControlClient rcClient, String callingPackageName) {
-        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
-        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        synchronized(mPRStack) {
-            // store the new display information
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    if(prse.hasMatchingMediaButtonIntent(mediaIntent)) {
-                        prse.resetControllerInfoForRcc(rcClient, callingPackageName,
-                                Binder.getCallingUid());
-
-                        if (rcClient == null) {
-                            break;
-                        }
-
-                        rccId = prse.getRccId();
-
-                        // there is a new (non-null) client:
-                        //     give the new client the displays (if any)
-                        if (mRcDisplays.size() > 0) {
-                            plugRemoteControlDisplaysIntoClient_syncPrs(prse.getRcc());
-                        }
-                        break;
-                    }
-                }//for
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-            }
-
-            // if the eventReceiver is at the top of the stack
-            // then check for potential refresh of the remote controls
-            if (isCurrentRcController(mediaIntent)) {
-                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
-            }
-        }//synchronized(mPRStack)
-        return rccId;
-    }
-
-    /**
-     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
-     * rcClient is guaranteed non-null
-     */
-    protected void unregisterRemoteControlClient(PendingIntent mediaIntent,
-            IRemoteControlClient rcClient) {
-        if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient);
-        synchronized(mPRStack) {
-            boolean topRccChange = false;
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    if ((prse.hasMatchingMediaButtonIntent(mediaIntent))
-                            && rcClient.equals(prse.getRcc())) {
-                        // we found the IRemoteControlClient to unregister
-                        prse.resetControllerInfoForNoRcc();
-                        topRccChange = (index == mPRStack.size()-1);
-                        // there can only be one matching RCC in the RC stack, we're done
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-            }
-            if (topRccChange) {
-                // no more RCC for the RCD, check for potential refresh of the remote controls
-                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
-            }
-        }
-    }
-
-
-    /**
-     * A class to encapsulate all the information about a remote control display.
-     * After instanciation, init() must always be called before the object is added in the list
-     * of displays.
-     * Before being removed from the list of displays, release() must always be called (otherwise
-     * it will leak death handlers).
-     */
-    private class DisplayInfoForServer implements IBinder.DeathRecipient {
-        /** may never be null */
-        private final IRemoteControlDisplay mRcDisplay;
-        private final IBinder mRcDisplayBinder;
-        private int mArtworkExpectedWidth = -1;
-        private int mArtworkExpectedHeight = -1;
-        private boolean mWantsPositionSync = false;
-        private ComponentName mClientNotifListComp;
-        private boolean mEnabled = true;
-
-        public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) {
-            if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h);
-            mRcDisplay = rcd;
-            mRcDisplayBinder = rcd.asBinder();
-            mArtworkExpectedWidth = w;
-            mArtworkExpectedHeight = h;
-        }
-
-        public boolean init() {
-            try {
-                mRcDisplayBinder.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                // remote control display is DOA, disqualify it
-                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder);
-                return false;
-            }
-            return true;
-        }
-
-        public void release() {
-            try {
-                mRcDisplayBinder.unlinkToDeath(this, 0);
-            } catch (java.util.NoSuchElementException e) {
-                // not much we can do here, the display should have been unregistered anyway
-                Log.e(TAG, "Error in DisplaInfoForServer.relase()", e);
-            }
-        }
-
-        public void binderDied() {
-            synchronized(mPRStack) {
-                Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died");
-                // remove the display from the list
-                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-                while (displayIterator.hasNext()) {
-                    final DisplayInfoForServer di = displayIterator.next();
-                    if (di.mRcDisplay == mRcDisplay) {
-                        if (DEBUG_RC) Log.w(TAG, " RCD removed from list");
-                        displayIterator.remove();
-                        return;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * The remote control displays.
-     * Access synchronized on mPRStack
-     */
-    private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1);
-
-    /**
-     * Plug each registered display into the specified client
-     * @param rcc, guaranteed non null
-     */
-    private void plugRemoteControlDisplaysIntoClient_syncPrs(IRemoteControlClient rcc) {
-        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-        while (displayIterator.hasNext()) {
-            final DisplayInfoForServer di = displayIterator.next();
-            try {
-                rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth,
-                        di.mArtworkExpectedHeight);
-                if (di.mWantsPositionSync) {
-                    rcc.setWantsSyncForDisplay(di.mRcDisplay, true);
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
-            }
-        }
-    }
-
-    private void enableRemoteControlDisplayForClient_syncRcStack(IRemoteControlDisplay rcd,
-            boolean enabled) {
-        // let all the remote control clients know whether the given display is enabled
-        //   (so the remote control stack traversal order doesn't matter).
-        final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-        while(stackIterator.hasNext()) {
-            PlayerRecord prse = stackIterator.next();
-            if(prse.getRcc() != null) {
-                try {
-                    prse.getRcc().enableRemoteControlDisplay(rcd, enabled);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error connecting RCD to client: ", e);
-                }
-            }
-        }
-    }
-
-    /**
-     * Is the remote control display interface already registered
-     * @param rcd
-     * @return true if the IRemoteControlDisplay is already in the list of displays
-     */
-    private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) {
-        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-        while (displayIterator.hasNext()) {
-            final DisplayInfoForServer di = displayIterator.next();
-            if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Register an IRemoteControlDisplay.
-     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
-     * at the top of the stack to update the new display with its information.
-     * @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int)
-     * @param rcd the IRemoteControlDisplay to register. No effect if null.
-     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param listenerComp the component for the listener interface, may be null if it's not needed
-     *   to verify it belongs to one of the enabled notification listeners
-     */
-    private void registerRemoteControlDisplay_int(IRemoteControlDisplay rcd, int w, int h,
-            ComponentName listenerComp) {
-        if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
-        synchronized(mAudioFocusLock) {
-            synchronized(mPRStack) {
-                if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) {
-                    return;
-                }
-                DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h);
-                di.mEnabled = true;
-                di.mClientNotifListComp = listenerComp;
-                if (!di.init()) {
-                    if (DEBUG_RC) Log.e(TAG, " error registering RCD");
-                    return;
-                }
-                // add RCD to list of displays
-                mRcDisplays.add(di);
-
-                // let all the remote control clients know there is a new display (so the remote
-                //   control stack traversal order doesn't matter).
-                Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-                while(stackIterator.hasNext()) {
-                    PlayerRecord prse = stackIterator.next();
-                    if(prse.getRcc() != null) {
-                        try {
-                            prse.getRcc().plugRemoteControlDisplay(rcd, w, h);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error connecting RCD to client: ", e);
-                        }
-                    }
-                }
-
-                // we have a new display, of which all the clients are now aware: have it be
-                // initialized wih the current gen ID and the current client info, do not
-                // reset the information for the other (existing) displays
-                sendMsg(mEventHandler, MSG_RCDISPLAY_INIT_INFO, SENDMSG_QUEUE,
-                        w /*arg1*/, h /*arg2*/,
-                        rcd /*obj*/, 0/*delay*/);
-            }
-        }
-    }
-
-    /**
-     * Unregister an IRemoteControlDisplay.
-     * No effect if the IRemoteControlDisplay hasn't been successfully registered.
-     * @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay)
-     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
-     */
-    protected void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
-        if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
-        synchronized(mPRStack) {
-            if (rcd == null) {
-                return;
-            }
-
-            boolean displayWasPluggedIn = false;
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext() && !displayWasPluggedIn) {
-                final DisplayInfoForServer di = displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    displayWasPluggedIn = true;
-                    di.release();
-                    displayIterator.remove();
-                }
-            }
-
-            if (displayWasPluggedIn) {
-                // disconnect this remote control display from all the clients, so the remote
-                //   control stack traversal order doesn't matter
-                final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-                while(stackIterator.hasNext()) {
-                    final PlayerRecord prse = stackIterator.next();
-                    if(prse.getRcc() != null) {
-                        try {
-                            prse.getRcc().unplugRemoteControlDisplay(rcd);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error disconnecting remote control display to client: ", e);
-                        }
-                    }
-                }
-            } else {
-                if (DEBUG_RC) Log.w(TAG, "  trying to unregister unregistered RCD");
-            }
-        }
-    }
-
-    /**
-     * Update the size of the artwork used by an IRemoteControlDisplay.
-     * @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int)
-     * @param rcd the IRemoteControlDisplay with the new artwork size requirement
-     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     */
-    protected void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
-        synchronized(mPRStack) {
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            boolean artworkSizeUpdate = false;
-            while (displayIterator.hasNext() && !artworkSizeUpdate) {
-                final DisplayInfoForServer di = displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
-                        di.mArtworkExpectedWidth = w;
-                        di.mArtworkExpectedHeight = h;
-                        artworkSizeUpdate = true;
-                    }
-                }
-            }
-            if (artworkSizeUpdate) {
-                // RCD is currently plugged in and its artwork size has changed, notify all RCCs,
-                // stack traversal order doesn't matter
-                final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-                while(stackIterator.hasNext()) {
-                    final PlayerRecord prse = stackIterator.next();
-                    if(prse.getRcc() != null) {
-                        try {
-                            prse.getRcc().setBitmapSizeForDisplay(rcd, w, h);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Controls whether a remote control display needs periodic checks of the RemoteControlClient
-     * playback position to verify that the estimated position has not drifted from the actual
-     * position. By default the check is not performed.
-     * The IRemoteControlDisplay must have been previously registered for this to have any effect.
-     * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled
-     *     or disabled. Not null.
-     * @param wantsSync if true, RemoteControlClient instances which expose their playback position
-     *     to the framework will regularly compare the estimated playback position with the actual
-     *     position, and will update the IRemoteControlDisplay implementation whenever a drift is
-     *     detected.
-     */
-    protected void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
-            boolean wantsSync) {
-        synchronized(mPRStack) {
-            boolean rcdRegistered = false;
-            // store the information about this display
-            // (display stack traversal order doesn't matter).
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForServer di = displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    di.mWantsPositionSync = wantsSync;
-                    rcdRegistered = true;
-                    break;
-                }
-            }
-            if (!rcdRegistered) {
-                return;
-            }
-            // notify all current RemoteControlClients
-            // (stack traversal order doesn't matter as we notify all RCCs)
-            final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-            while (stackIterator.hasNext()) {
-                final PlayerRecord prse = stackIterator.next();
-                if (prse.getRcc() != null) {
-                    try {
-                        prse.getRcc().setWantsSyncForDisplay(rcd, wantsSync);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error setting position sync flag for RCD on RCC: ", e);
-                    }
-                }
-            }
-        }
-    }
-
-    // handler for MSG_RCC_NEW_VOLUME_OBS
-    private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
-        synchronized(mPRStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    if (prse.getRccId() == rccId) {
-                        prse.mRemoteVolumeObs = rvo;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-    }
-
-    /**
-     * Checks if a remote client is active on the supplied stream type. Update the remote stream
-     * volume state if found and playing
-     * @param streamType
-     * @return false if no remote playing is currently playing
-     */
-    protected boolean checkUpdateRemoteStateIfActive(int streamType) {
-        synchronized(mPRStack) {
-            // iterating from top of stack as active playback is more likely on entries at the top
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    if ((prse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
-                            && isPlaystateActive(prse.mPlaybackState.mState)
-                            && (prse.mPlaybackStream == streamType)) {
-                        if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
-                                + ", vol =" + prse.mPlaybackVolume);
-                        synchronized (mMainRemote) {
-                            mMainRemote.mRccId = prse.getRccId();
-                            mMainRemote.mVolume = prse.mPlaybackVolume;
-                            mMainRemote.mVolumeMax = prse.mPlaybackVolumeMax;
-                            mMainRemote.mVolumeHandling = prse.mPlaybackVolumeHandling;
-                            mMainRemoteIsActive = true;
-                        }
-                        return true;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-            }
-        }
-        synchronized (mMainRemote) {
-            mMainRemoteIsActive = false;
-        }
-        return false;
-    }
-
-    /**
-     * Returns true if the given playback state is considered "active", i.e. it describes a state
-     * where playback is happening, or about to
-     * @param playState the playback state to evaluate
-     * @return true if active, false otherwise (inactive or unknown)
-     */
-    protected static boolean isPlaystateActive(int playState) {
-        switch (playState) {
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    private void sendVolumeUpdateToRemote(int rccId, int direction) {
-        if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); }
-        if (direction == 0) {
-            // only handling discrete events
-            return;
-        }
-        IRemoteVolumeObserver rvo = null;
-        synchronized (mPRStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
-                    if (prse.getRccId() == rccId) {
-                        rvo = prse.mRemoteVolumeObs;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-        if (rvo != null) {
-            try {
-                rvo.dispatchRemoteVolumeUpdate(direction, -1);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error dispatching relative volume update", e);
-            }
-        }
-    }
-
-    protected int getRemoteStreamMaxVolume() {
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return 0;
-            }
-            return mMainRemote.mVolumeMax;
-        }
-    }
-
-    protected int getRemoteStreamVolume() {
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return 0;
-            }
-            return mMainRemote.mVolume;
-        }
-    }
-
-    protected void setRemoteStreamVolume(int vol) {
-        if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); }
-        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return;
-            }
-            rccId = mMainRemote.mRccId;
-        }
-        IRemoteVolumeObserver rvo = null;
-        synchronized (mPRStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
-                    if (prse.getRccId() == rccId) {
-                        rvo = prse.mRemoteVolumeObs;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-        if (rvo != null) {
-            try {
-                rvo.dispatchRemoteVolumeUpdate(0, vol);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error dispatching absolute volume update", e);
-            }
-        }
-    }
-
-    /**
-     * Call to make AudioService reevaluate whether it's in a mode where remote players should
-     * have their volume controlled. In this implementation this is only to reset whether
-     * VolumePanel should display remote volumes
-     */
-    protected void postReevaluateRemote() {
-        sendMsg(mEventHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0);
-    }
-
-    private void onReevaluateRemote() {
-        // TODO This was used to notify VolumePanel if there was remote playback
-        // in the stack. This is now in MediaSessionService. More code should be
-        // removed.
-    }
-
 }
diff --git a/services/core/java/com/android/server/audio/PlayerRecord.java b/services/core/java/com/android/server/audio/PlayerRecord.java
deleted file mode 100644 (file)
index e98f12e..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.audio;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.media.AudioManager;
-import android.media.IRemoteControlClient;
-import android.media.IRemoteVolumeObserver;
-import android.media.RemoteControlClient;
-import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.PrintWriter;
-
-/**
- * @hide
- * Class to handle all the information about a media player, encapsulating information
- * about its use RemoteControlClient, playback type and volume... The lifecycle of each
- * instance is managed by android.media.MediaFocusControl, from its addition to the player stack
- * stack to its release.
- */
-class PlayerRecord implements DeathRecipient {
-
-    // on purpose not using this classe's name, as it will only be used from MediaFocusControl
-    private static final String TAG = "MediaFocusControl";
-    private static final boolean DEBUG = false;
-
-    /**
-     * A global counter for RemoteControlClient identifiers
-     */
-    private static int sLastRccId = 0;
-
-    public static MediaFocusControl sController;
-
-    /**
-     * The target for the ACTION_MEDIA_BUTTON events.
-     * Always non null. //FIXME verify
-     */
-    final private PendingIntent mMediaIntent;
-    /**
-     * The registered media button event receiver.
-     */
-    final private ComponentName mReceiverComponent;
-
-    private int mRccId = -1;
-
-    /**
-     * A non-null token implies this record tracks a "live" player whose death is being monitored.
-     */
-    private IBinder mToken;
-    private String mCallingPackageName;
-    private int mCallingUid;
-    /**
-     * Provides access to the information to display on the remote control.
-     * May be null (when a media button event receiver is registered,
-     *     but no remote control client has been registered) */
-    private IRemoteControlClient mRcClient;
-    private RcClientDeathHandler mRcClientDeathHandler;
-    /**
-     * Information only used for non-local playback
-     */
-    //FIXME private?
-    public int mPlaybackType;
-    public int mPlaybackVolume;
-    public int mPlaybackVolumeMax;
-    public int mPlaybackVolumeHandling;
-    public int mPlaybackStream;
-    public RccPlaybackState mPlaybackState;
-    public IRemoteVolumeObserver mRemoteVolumeObs;
-
-
-    protected static class RccPlaybackState {
-        public int mState;
-        public long mPositionMs;
-        public float mSpeed;
-
-        public RccPlaybackState(int state, long positionMs, float speed) {
-            mState = state;
-            mPositionMs = positionMs;
-            mSpeed = speed;
-        }
-
-        public void reset() {
-            mState = RemoteControlClient.PLAYSTATE_STOPPED;
-            mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID;
-            mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X;
-        }
-
-        @Override
-        public String toString() {
-            return stateToString() + ", " + posToString() + ", " + mSpeed + "X";
-        }
-
-        private String posToString() {
-            if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) {
-                return "PLAYBACK_POSITION_INVALID";
-            } else if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
-                return "PLAYBACK_POSITION_ALWAYS_UNKNOWN";
-            } else {
-                return (String.valueOf(mPositionMs) + "ms");
-            }
-        }
-
-        private String stateToString() {
-            switch (mState) {
-                case RemoteControlClient.PLAYSTATE_NONE:
-                    return "PLAYSTATE_NONE";
-                case RemoteControlClient.PLAYSTATE_STOPPED:
-                    return "PLAYSTATE_STOPPED";
-                case RemoteControlClient.PLAYSTATE_PAUSED:
-                    return "PLAYSTATE_PAUSED";
-                case RemoteControlClient.PLAYSTATE_PLAYING:
-                    return "PLAYSTATE_PLAYING";
-                case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-                    return "PLAYSTATE_FAST_FORWARDING";
-                case RemoteControlClient.PLAYSTATE_REWINDING:
-                    return "PLAYSTATE_REWINDING";
-                case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                    return "PLAYSTATE_SKIPPING_FORWARDS";
-                case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-                    return "PLAYSTATE_SKIPPING_BACKWARDS";
-                case RemoteControlClient.PLAYSTATE_BUFFERING:
-                    return "PLAYSTATE_BUFFERING";
-                case RemoteControlClient.PLAYSTATE_ERROR:
-                    return "PLAYSTATE_ERROR";
-                default:
-                    return "[invalid playstate]";
-            }
-        }
-    }
-
-
-    /**
-     * Inner class to monitor remote control client deaths, and remove the client for the
-     * remote control stack if necessary.
-     */
-    private class RcClientDeathHandler implements IBinder.DeathRecipient {
-        final private IBinder mCb; // To be notified of client's death
-        //FIXME needed?
-        final private PendingIntent mMediaIntent;
-
-        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
-            mCb = cb;
-            mMediaIntent = pi;
-        }
-
-        public void binderDied() {
-            Log.w(TAG, "  RemoteControlClient died");
-            // remote control client died, make sure the displays don't use it anymore
-            //  by setting its remote control client to null
-            sController.registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/);
-            // the dead client was maybe handling remote playback, the controller should reevaluate
-            sController.postReevaluateRemote();
-        }
-
-        public IBinder getBinder() {
-            return mCb;
-        }
-    }
-
-
-    protected static class RemotePlaybackState {
-        int mRccId;
-        int mVolume;
-        int mVolumeMax;
-        int mVolumeHandling;
-
-        protected RemotePlaybackState(int id, int vol, int volMax) {
-            mRccId = id;
-            mVolume = vol;
-            mVolumeMax = volMax;
-            mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
-        }
-    }
-
-
-    void dump(PrintWriter pw, boolean registrationInfo) {
-        if (registrationInfo) {
-            pw.println("  pi: " + mMediaIntent +
-                    " -- pack: " + mCallingPackageName +
-                    "  -- ercvr: " + mReceiverComponent +
-                    "  -- client: " + mRcClient +
-                    "  -- uid: " + mCallingUid +
-                    "  -- type: " + mPlaybackType +
-                    "  state: " + mPlaybackState);
-        } else {
-            // emphasis on state
-            pw.println("  uid: " + mCallingUid +
-                    "  -- id: " + mRccId +
-                    "  -- type: " + mPlaybackType +
-                    "  -- state: " + mPlaybackState +
-                    "  -- vol handling: " + mPlaybackVolumeHandling +
-                    "  -- vol: " + mPlaybackVolume +
-                    "  -- volMax: " + mPlaybackVolumeMax +
-                    "  -- volObs: " + mRemoteVolumeObs);
-        }
-    }
-
-
-    static protected void setMediaFocusControl(MediaFocusControl mfc) {
-        sController = mfc;
-    }
-
-    /** precondition: mediaIntent != null */
-    protected PlayerRecord(PendingIntent mediaIntent, ComponentName eventReceiver, IBinder token)
-    {
-        mMediaIntent = mediaIntent;
-        mReceiverComponent = eventReceiver;
-        mToken = token;
-        mCallingUid = -1;
-        mRcClient = null;
-        mRccId = ++sLastRccId;
-        mPlaybackState = new RccPlaybackState(
-                RemoteControlClient.PLAYSTATE_STOPPED,
-                RemoteControlClient.PLAYBACK_POSITION_INVALID,
-                RemoteControlClient.PLAYBACK_SPEED_1X);
-
-        resetPlaybackInfo();
-        if (mToken != null) {
-            try {
-                mToken.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                sController.unregisterMediaButtonIntentAsync(mMediaIntent);
-            }
-        }
-    }
-
-    //---------------------------------------------
-    // Accessors
-    protected int getRccId() {
-        return mRccId;
-    }
-
-    protected IRemoteControlClient getRcc() {
-        return mRcClient;
-    }
-
-    protected ComponentName getMediaButtonReceiver() {
-        return mReceiverComponent;
-    }
-
-    protected PendingIntent getMediaButtonIntent() {
-        return mMediaIntent;
-    }
-
-    protected boolean hasMatchingMediaButtonIntent(PendingIntent pi) {
-        if (mToken != null) {
-            return mMediaIntent.equals(pi);
-        } else {
-            if (mReceiverComponent != null) {
-                return mReceiverComponent.equals(pi.getIntent().getComponent());
-            } else {
-                return false;
-            }
-        }
-    }
-
-    protected boolean isPlaybackActive() {
-        return MediaFocusControl.isPlaystateActive(mPlaybackState.mState);
-    }
-
-    //---------------------------------------------
-    // Modify the records stored in the instance
-    protected void resetControllerInfoForRcc(IRemoteControlClient rcClient,
-            String callingPackageName, int uid) {
-        // already had a remote control client?
-        if (mRcClientDeathHandler != null) {
-            // stop monitoring the old client's death
-            unlinkToRcClientDeath();
-        }
-        // save the new remote control client
-        mRcClient = rcClient;
-        mCallingPackageName = callingPackageName;
-        mCallingUid = uid;
-        if (rcClient == null) {
-            // here mcse.mRcClientDeathHandler is null;
-            resetPlaybackInfo();
-        } else {
-            IBinder b = mRcClient.asBinder();
-            RcClientDeathHandler rcdh =
-                    new RcClientDeathHandler(b, mMediaIntent);
-            try {
-                b.linkToDeath(rcdh, 0);
-            } catch (RemoteException e) {
-                // remote control client is DOA, disqualify it
-                Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
-                mRcClient = null;
-            }
-            mRcClientDeathHandler = rcdh;
-        }
-    }
-
-    protected void resetControllerInfoForNoRcc() {
-        // stop monitoring the RCC death
-        unlinkToRcClientDeath();
-        // reset the RCC-related fields
-        mRcClient = null;
-        mCallingPackageName = null;
-    }
-
-    public void resetPlaybackInfo() {
-        mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
-        mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
-        mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
-        mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
-        mPlaybackStream = AudioManager.STREAM_MUSIC;
-        mPlaybackState.reset();
-        mRemoteVolumeObs = null;
-    }
-
-    //---------------------------------------------
-    public void unlinkToRcClientDeath() {
-        if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
-            try {
-                mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
-                mRcClientDeathHandler = null;
-            } catch (java.util.NoSuchElementException e) {
-                // not much we can do here
-                Log.e(TAG, "Error in unlinkToRcClientDeath()", e);
-            }
-        }
-    }
-
-    // FIXME rename to "release"? (as in FocusRequester class)
-    public void destroy() {
-        unlinkToRcClientDeath();
-        if (mToken != null) {
-            mToken.unlinkToDeath(this, 0);
-            mToken = null;
-        }
-    }
-
-    @Override
-    public void binderDied() {
-        sController.unregisterMediaButtonIntentAsync(mMediaIntent);
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        destroy(); // unlink exception handled inside method
-        super.finalize();
-    }
-}