AudioService: remove dead code

Remove dead code related to media button event receiver and
  remote control display, now handled by MediaSession*

Change-Id: I4bd621240ddddf4df079df8d551c72b232c3301d
This commit is contained in:
Jean-Michel Trivi
2015-11-04 14:45:54 -08:00
parent df94885e47
commit d4de20df2a
11 changed files with 24 additions and 2953 deletions

View 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 \

View 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

View 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

View 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);

View File

@@ -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);
}

View File

@@ -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);
}

View 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

View 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;
@@ -77,16 +69,10 @@ import java.util.List;
private MediaSessionManager.OnActiveSessionsChangedListener mSessionListener;
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,38 +208,13 @@ 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();
}
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;
}
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
}
@@ -1067,38 +684,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

View 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

View File

@@ -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();
}
}