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:
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user