diff options
| -rw-r--r-- | api/current.txt | 19 | ||||
| -rw-r--r-- | core/java/android/net/ConnectivityManager.java | 16 | ||||
| -rw-r--r-- | core/java/android/net/NetworkCapabilities.java | 88 | ||||
| -rw-r--r-- | core/java/android/net/NetworkRequest.java | 104 | ||||
| -rw-r--r-- | media/java/android/media/AudioManager.java | 47 | ||||
| -rw-r--r-- | media/java/android/media/RemoteController.java | 343 | ||||
| -rw-r--r-- | media/java/android/media/session/ISessionController.aidl | 1 | ||||
| -rw-r--r-- | media/java/android/media/session/MediaController.java | 28 | ||||
| -rw-r--r-- | media/java/android/media/session/MediaSessionLegacyHelper.java | 86 | ||||
| -rw-r--r-- | media/java/android/media/session/MediaSessionManager.java | 14 | ||||
| -rw-r--r-- | media/java/android/media/session/PlaybackState.java | 81 | ||||
| -rw-r--r-- | services/core/java/com/android/server/ConnectivityService.java | 4 | ||||
| -rw-r--r-- | services/core/java/com/android/server/media/MediaSessionRecord.java | 5 |
13 files changed, 686 insertions, 150 deletions
diff --git a/api/current.txt b/api/current.txt index 1973da583552..76c3e812a77d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -16270,21 +16270,12 @@ package android.net { } public final class NetworkCapabilities implements android.os.Parcelable { - ctor public NetworkCapabilities(); ctor public NetworkCapabilities(android.net.NetworkCapabilities); - method public void addNetworkCapability(int); - method public void addTransportType(int); method public int describeContents(); method public int getLinkDownstreamBandwidthKbps(); method public int getLinkUpstreamBandwidthKbps(); - method public java.util.Collection<java.lang.Integer> getNetworkCapabilities(); - method public java.util.Collection<java.lang.Integer> getTransportTypes(); method public boolean hasCapability(int); method public boolean hasTransport(int); - method public void removeNetworkCapability(int); - method public void removeTransportType(int); - method public void setLinkDownstreamBandwidthKbps(int); - method public void setLinkUpstreamBandwidthKbps(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final int NET_CAPABILITY_CBS = 5; // 0x5 @@ -16358,7 +16349,15 @@ package android.net { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; - field public final android.net.NetworkCapabilities networkCapabilities; + } + + public static class NetworkRequest.Builder { + ctor public NetworkRequest.Builder(); + method public android.net.NetworkRequest.Builder addCapability(int); + method public android.net.NetworkRequest.Builder addTransportType(int); + method public android.net.NetworkRequest build(); + method public android.net.NetworkRequest.Builder removeCapability(int); + method public android.net.NetworkRequest.Builder removeTransportType(int); } public class ParseException extends java.lang.RuntimeException { diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2740266897c4..ff90e789a4d6 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -429,6 +429,11 @@ public class ConnectivityManager { */ public final static int INVALID_NET_ID = 0; + /** + * @hide + */ + public final static int REQUEST_ID_UNSET = 0; + private final IConnectivityManager mService; private final String mPackageName; @@ -883,8 +888,8 @@ public class ConnectivityManager { * @hide */ public static void maybeMarkCapabilitiesRestricted(NetworkCapabilities nc) { - for (Integer capability : nc.getNetworkCapabilities()) { - switch (capability.intValue()) { + for (int capability : nc.getCapabilities()) { + switch (capability) { case NetworkCapabilities.NET_CAPABILITY_CBS: case NetworkCapabilities.NET_CAPABILITY_DUN: case NetworkCapabilities.NET_CAPABILITY_EIMS: @@ -903,7 +908,7 @@ public class ConnectivityManager { } // All the capabilities are typically provided by restricted networks. // Conclude that this network is restricted. - nc.removeNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) { @@ -927,15 +932,14 @@ public class ConnectivityManager { return null; } NetworkCapabilities netCap = new NetworkCapabilities(); - netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); - netCap.addNetworkCapability(cap); + netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addCapability(cap); maybeMarkCapabilitiesRestricted(netCap); return netCap; } else if (networkType == TYPE_WIFI) { if ("p2p".equals(feature)) { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); - netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P); + netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P); maybeMarkCapabilitiesRestricted(netCap); return netCap; } diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 35274f1e7e9c..fe96287c83e6 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -44,6 +44,9 @@ public final class NetworkCapabilities implements Parcelable { private static final String TAG = "NetworkCapabilities"; private static final boolean DBG = false; + /** + * @hide + */ public NetworkCapabilities() { } @@ -154,58 +157,64 @@ public final class NetworkCapabilities implements Parcelable { * Multiple capabilities may be applied sequentially. Note that when searching * for a network to satisfy a request, all capabilities requested must be satisfied. * - * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added. + * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added. + * @return This NetworkCapability to facilitate chaining. + * @hide */ - public void addNetworkCapability(int networkCapability) { - if (networkCapability < MIN_NET_CAPABILITY || - networkCapability > MAX_NET_CAPABILITY) { + public NetworkCapabilities addCapability(int capability) { + if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { throw new IllegalArgumentException("NetworkCapability out of range"); } - mNetworkCapabilities |= 1 << networkCapability; + mNetworkCapabilities |= 1 << capability; + return this; } /** * Removes (if found) the given capability from this {@code NetworkCapability} instance. * - * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed. + * @param capability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed. + * @return This NetworkCapability to facilitate chaining. + * @hide */ - public void removeNetworkCapability(int networkCapability) { - if (networkCapability < MIN_NET_CAPABILITY || - networkCapability > MAX_NET_CAPABILITY) { + public NetworkCapabilities removeCapability(int capability) { + if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { throw new IllegalArgumentException("NetworkCapability out of range"); } - mNetworkCapabilities &= ~(1 << networkCapability); + mNetworkCapabilities &= ~(1 << capability); + return this; } /** * Gets all the capabilities set on this {@code NetworkCapability} instance. * - * @return a {@link Collection} of {@code NetworkCapabilities.NET_CAPABILITY_*} values + * @return an array of {@code NetworkCapabilities.NET_CAPABILITY_*} values * for this instance. + * @hide */ - public Collection<Integer> getNetworkCapabilities() { + public int[] getCapabilities() { return enumerateBits(mNetworkCapabilities); } /** * Tests for the presence of a capabilitity on this instance. * - * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for. + * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for. * @return {@code true} if set on this instance. */ - public boolean hasCapability(int networkCapability) { - if (networkCapability < MIN_NET_CAPABILITY || - networkCapability > MAX_NET_CAPABILITY) { + public boolean hasCapability(int capability) { + if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { return false; } - return ((mNetworkCapabilities & (1 << networkCapability)) != 0); + return ((mNetworkCapabilities & (1 << capability)) != 0); } - private Collection<Integer> enumerateBits(long val) { - ArrayList<Integer> result = new ArrayList<Integer>(); + private int[] enumerateBits(long val) { + int size = Long.bitCount(val); + int[] result = new int[size]; + int index = 0; int resource = 0; while (val > 0) { - if ((val & 1) == 1) result.add(resource); + if ((val & 1) == 1) result[index++] = resource; val = val >> 1; resource++; } @@ -265,33 +274,40 @@ public final class NetworkCapabilities implements Parcelable { * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above. * * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added. + * @return This NetworkCapability to facilitate chaining. + * @hide */ - public void addTransportType(int transportType) { + public NetworkCapabilities addTransportType(int transportType) { if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { throw new IllegalArgumentException("TransportType out of range"); } mTransportTypes |= 1 << transportType; + return this; } /** * Removes (if found) the given transport from this {@code NetworkCapability} instance. * * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed. + * @return This NetworkCapability to facilitate chaining. + * @hide */ - public void removeTransportType(int transportType) { + public NetworkCapabilities removeTransportType(int transportType) { if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { throw new IllegalArgumentException("TransportType out of range"); } mTransportTypes &= ~(1 << transportType); + return this; } /** * Gets all the transports set on this {@code NetworkCapability} instance. * - * @return a {@link Collection} of {@code NetworkCapabilities.TRANSPORT_*} values + * @return an array of {@code NetworkCapabilities.TRANSPORT_*} values * for this instance. + * @hide */ - public Collection<Integer> getTransportTypes() { + public int[] getTransportTypes() { return enumerateBits(mTransportTypes); } @@ -340,6 +356,7 @@ public final class NetworkCapabilities implements Parcelable { * fast backhauls and slow backhauls. * * @param upKbps the estimated first hop upstream (device to network) bandwidth. + * @hide */ public void setLinkUpstreamBandwidthKbps(int upKbps) { mLinkUpBandwidthKbps = upKbps; @@ -368,6 +385,7 @@ public final class NetworkCapabilities implements Parcelable { * fast backhauls and slow backhauls. * * @param downKbps the estimated first hop downstream (network to device) bandwidth. + * @hide */ public void setLinkDownstreamBandwidthKbps(int downKbps) { mLinkDownBandwidthKbps = downKbps; @@ -464,24 +482,22 @@ public final class NetworkCapabilities implements Parcelable { }; public String toString() { - Collection<Integer> types = getTransportTypes(); - String transports = (types.size() > 0 ? " Transports: " : ""); - Iterator<Integer> i = types.iterator(); - while (i.hasNext()) { - switch (i.next()) { + int[] types = getTransportTypes(); + String transports = (types.length > 0 ? " Transports: " : ""); + for (int i = 0; i < types.length;) { + switch (types[i]) { case TRANSPORT_CELLULAR: transports += "CELLULAR"; break; case TRANSPORT_WIFI: transports += "WIFI"; break; case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break; case TRANSPORT_ETHERNET: transports += "ETHERNET"; break; } - if (i.hasNext()) transports += "|"; + if (++i < types.length) transports += "|"; } - types = getNetworkCapabilities(); - String capabilities = (types.size() > 0 ? " Capabilities: " : ""); - i = types.iterator(); - while (i.hasNext()) { - switch (i.next().intValue()) { + types = getCapabilities(); + String capabilities = (types.length > 0 ? " Capabilities: " : ""); + for (int i = 0; i < types.length; ) { + switch (types[i]) { case NET_CAPABILITY_MMS: capabilities += "MMS"; break; case NET_CAPABILITY_SUPL: capabilities += "SUPL"; break; case NET_CAPABILITY_DUN: capabilities += "DUN"; break; @@ -497,7 +513,7 @@ public final class NetworkCapabilities implements Parcelable { case NET_CAPABILITY_INTERNET: capabilities += "INTERNET"; break; case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break; } - if (i.hasNext()) capabilities += "&"; + if (++i < types.length) capabilities += "&"; } String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" + diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 47377e97be43..7911c729d338 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -22,19 +22,14 @@ import android.os.Parcelable; import java.util.concurrent.atomic.AtomicInteger; /** - * Defines a request for a network, made by calling {@link ConnectivityManager#requestNetwork} - * or {@link ConnectivityManager#listenForNetwork}. - * - * This token records the {@link NetworkCapabilities} used to make the request and identifies - * the request. It should be used to release the request via - * {@link ConnectivityManager#releaseNetworkRequest} when the network is no longer desired. + * Defines a request for a network, made through {@link NetworkRequest.Builder} and used + * to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes + * via {@link ConnectivityManager#listenForNetwork}. */ public class NetworkRequest implements Parcelable { /** - * The {@link NetworkCapabilities} that define this request. This should not be modified. - * The networkCapabilities of the request are set when - * {@link ConnectivityManager#requestNetwork} is called and the value is presented here - * as a convenient reminder of what was requested. + * The {@link NetworkCapabilities} that define this request. + * @hide */ public final NetworkCapabilities networkCapabilities; @@ -71,6 +66,95 @@ public class NetworkRequest implements Parcelable { this.legacyType = that.legacyType; } + /** + * Builder used to create {@link NetworkRequest} objects. Specify the Network features + * needed in terms of {@link NetworkCapabilities} features + */ + public static class Builder { + private final NetworkCapabilities mNetworkCapabilities = new NetworkCapabilities(); + + /** + * Default constructor for Builder. + */ + public Builder() {} + + /** + * Build {@link NetworkRequest} give the current set of capabilities. + */ + public NetworkRequest build() { + return new NetworkRequest(mNetworkCapabilities, ConnectivityManager.TYPE_NONE, + ConnectivityManager.REQUEST_ID_UNSET); + } + + /** + * Add the given capability requirement to this builder. These represent + * the requested network's required capabilities. Note that when searching + * for a network to satisfy a request, all capabilities requested must be + * satisfied. See {@link NetworkCapabilities} for {@code NET_CAPABILITIY_*} + * definitions. + * + * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add. + * @return The builder to facilitate chaining + * {@code builder.addCapability(...).addCapability();}. + */ + public Builder addCapability(int capability) { + mNetworkCapabilities.addCapability(capability); + return this; + } + + /** + * Removes (if found) the given capability from this builder instance. + * + * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to remove. + * @return The builder to facilitate chaining. + */ + public Builder removeCapability(int capability) { + mNetworkCapabilities.removeCapability(capability); + return this; + } + + /** + * Adds the given transport requirement to this builder. These represent + * the set of allowed transports for the request. Only networks using one + * of these transports will satisfy the request. If no particular transports + * are required, none should be specified here. See {@link NetworkCapabilities} + * for {@code TRANSPORT_*} definitions. + * + * @param transportType The {@code NetworkCapabilities.TRANSPORT_*} to add. + * @return The builder to facilitate chaining. + */ + public Builder addTransportType(int transportType) { + mNetworkCapabilities.addTransportType(transportType); + return this; + } + + /** + * Removes (if found) the given transport from this builder instance. + * + * @param transportType The {@code NetworkCapabilities.TRANSPORT_*} to remove. + * @return The builder to facilitate chaining. + */ + public Builder removeTransportType(int transportType) { + mNetworkCapabilities.removeTransportType(transportType); + return this; + } + + /** + * @hide + */ + public Builder setLinkUpstreamBandwidthKbps(int upKbps) { + mNetworkCapabilities.setLinkUpstreamBandwidthKbps(upKbps); + return this; + } + /** + * @hide + */ + public Builder setLinkDownstreamBandwidthKbps(int downKbps) { + mNetworkCapabilities.setLinkDownstreamBandwidthKbps(downKbps); + return this; + } + } + // implement the Parcelable interface public int describeContents() { return 0; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index ba6b21418113..6280fdeca01f 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -2363,19 +2363,24 @@ public class AudioManager { if (rctlr == null) { return false; } - IAudioService service = getService(); - final RemoteController.OnClientUpdateListener l = rctlr.getUpdateListener(); - final ComponentName listenerComponent = new ComponentName(mContext, l.getClass()); - try { - int[] artworkDimensions = rctlr.getArtworkSize(); - boolean reg = service.registerRemoteController(rctlr.getRcDisplay(), - artworkDimensions[0]/*w*/, artworkDimensions[1]/*h*/, - listenerComponent); - rctlr.setIsRegistered(reg); - return reg; - } catch (RemoteException e) { - Log.e(TAG, "Dead object in registerRemoteController " + e); - return false; + if (USE_SESSIONS) { + rctlr.startListeningToSessions(); + return true; + } else { + IAudioService service = getService(); + final RemoteController.OnClientUpdateListener l = rctlr.getUpdateListener(); + final ComponentName listenerComponent = new ComponentName(mContext, l.getClass()); + try { + int[] artworkDimensions = rctlr.getArtworkSize(); + boolean reg = service.registerRemoteController(rctlr.getRcDisplay(), + artworkDimensions[0]/* w */, artworkDimensions[1]/* h */, + listenerComponent); + rctlr.setIsRegistered(reg); + return reg; + } catch (RemoteException e) { + Log.e(TAG, "Dead object in registerRemoteController " + e); + return false; + } } } @@ -2388,12 +2393,16 @@ public class AudioManager { if (rctlr == null) { return; } - IAudioService service = getService(); - try { - service.unregisterRemoteControlDisplay(rctlr.getRcDisplay()); - rctlr.setIsRegistered(false); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e); + if (USE_SESSIONS) { + rctlr.stopListeningToSessions(); + } else { + IAudioService service = getService(); + try { + service.unregisterRemoteControlDisplay(rctlr.getRcDisplay()); + rctlr.setIsRegistered(false); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e); + } } } diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java index 37115850539b..76c72999e24f 100644 --- a/media/java/android/media/RemoteController.java +++ b/media/java/android/media/RemoteController.java @@ -19,11 +19,17 @@ 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; import android.graphics.Bitmap; import android.media.IRemoteControlDisplay; import android.media.MediaMetadataEditor; +import android.media.session.MediaController; +import android.media.session.MediaSession; +import android.media.session.MediaSessionLegacyHelper; +import android.media.session.MediaSessionManager; +import android.media.session.PlaybackState; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -34,6 +40,7 @@ import android.util.Log; import android.view.KeyEvent; import java.lang.ref.WeakReference; +import java.util.List; /** * The RemoteController class is used to control media playback, display and update media metadata @@ -56,6 +63,7 @@ public final class RemoteController 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; @@ -64,6 +72,11 @@ public final class RemoteController private final int mMaxBitmapDimension; private MetadataEditor mMetadataEditor; + private MediaSessionManager mSessionManager; + private MediaSessionManager.SessionListener mSessionListener + = new TopTransportSessionListener(); + private MediaController.Callback mSessionCb = new MediaControllerCallback(); + /** * Synchronized on mGenLock */ @@ -79,6 +92,8 @@ public final class RemoteController private int mArtworkWidth = -1; private int mArtworkHeight = -1; private boolean mEnabled = true; + // synchronized on mInfoLock, for USE_SESSION apis. + private MediaController mCurrentSession; /** * Class constructor. @@ -123,6 +138,8 @@ public final class RemoteController mContext = context; mRcd = new RcDisplay(this); mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + mSessionManager = (MediaSessionManager) context + .getSystemService(Context.MEDIA_SESSION_SERVICE); if (ActivityManager.isLowRamDeviceStatic()) { mMaxBitmapDimension = MAX_BITMAP_DIMENSION; @@ -194,8 +211,15 @@ public final class RemoteController * @hide */ public String getRemoteControlClientPackageName() { - return mClientPendingIntentCurrent != null ? - mClientPendingIntentCurrent.getCreatorPackage() : null; + if (USE_SESSIONS) { + synchronized (mInfoLock) { + return mCurrentSession != null ? mCurrentSession.getSessionInfo().getPackageName() + : null; + } + } else { + return mClientPendingIntentCurrent != null ? + mClientPendingIntentCurrent.getCreatorPackage() : null; + } } /** @@ -215,22 +239,38 @@ public final class RemoteController * @see OnClientUpdateListener#onClientPlaybackStateUpdate(int, long, long, float) */ public long getEstimatedMediaPosition() { - if (mLastPlaybackInfo != null) { - if (!RemoteControlClient.playbackPositionShouldMove(mLastPlaybackInfo.mState)) { - return mLastPlaybackInfo.mCurrentPosMs; + if (USE_SESSIONS) { + synchronized (mInfoLock) { + if (mCurrentSession != null) { + PlaybackState state = mCurrentSession.getPlaybackState(); + if (state != null) { + return state.getPosition(); + } + } } - - // Take the current position at the time of state change and estimate. - final long thenPos = mLastPlaybackInfo.mCurrentPosMs; - if (thenPos < 0) { - return -1; + } 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 = mLastPlaybackInfo.mStateChangeTimeMs; - final long sinceThen = now - then; - final long scaledSinceThen = (long) (sinceThen * mLastPlaybackInfo.mSpeed); - return thenPos + scaledSinceThen; + 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; } @@ -267,30 +307,40 @@ public final class RemoteController if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) { throw new IllegalArgumentException("not a media key event"); } - final PendingIntent pi; - synchronized(mInfoLock) { - if (!mIsRegistered) { - Log.e(TAG, "Cannot use sendMediaKeyEvent() from an unregistered RemoteController"); + if (USE_SESSIONS) { + synchronized (mInfoLock) { + if (mCurrentSession != null) { + return mCurrentSession.dispatchMediaButtonEvent(keyEvent); + } return false; } - if (!mEnabled) { - Log.e(TAG, "Cannot use sendMediaKeyEvent() from a disabled RemoteController"); - 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; } - 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); + 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; } - } else { - Log.i(TAG, "No-op when sending key click, no receiver right now"); - return false; } return true; } @@ -311,11 +361,19 @@ public final class RemoteController if (timeMs < 0) { throw new IllegalArgumentException("illegal negative time value"); } - final int genId; - synchronized (mGenLock) { - genId = mClientGenerationIdCurrent; + if (USE_SESSIONS) { + synchronized (mInfoLock) { + if (mCurrentSession != null) { + mCurrentSession.getTransportControls().seekTo(timeMs); + } + } + } else { + final int genId; + synchronized (mGenLock) { + genId = mClientGenerationIdCurrent; + } + mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs); } - mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs); return true; } @@ -430,7 +488,6 @@ public final class RemoteController return editor; } - /** * A class to read the metadata published by a {@link RemoteControlClient}, or send a * {@link RemoteControlClient} new values for keys that can be edited. @@ -477,26 +534,41 @@ public final class RemoteController if (!mMetadataChanged) { return; } - final int genId; - synchronized(mGenLock) { - genId = mClientGenerationIdCurrent; - } - synchronized(mInfoLock) { - if (mEditorMetadata.containsKey( - String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) { - Rating rating = (Rating) getObject( - MediaMetadataEditor.RATING_KEY_BY_USER, null); - mAudioManager.updateRemoteControlClientMetadata(genId, - MediaMetadataEditor.RATING_KEY_BY_USER, - rating); - } else { - Log.e(TAG, "no metadata to apply"); + if (USE_SESSIONS) { + synchronized (mInfoLock) { + if (mCurrentSession != null) { + if (mEditorMetadata.containsKey( + String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) { + Rating rating = (Rating) getObject( + MediaMetadataEditor.RATING_KEY_BY_USER, null); + if (rating != null) { + mCurrentSession.getTransportControls().setRating(rating); + } + } + } + } + } else { + final int genId; + synchronized(mGenLock) { + genId = mClientGenerationIdCurrent; + } + synchronized(mInfoLock) { + if (mEditorMetadata.containsKey( + String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) { + Rating rating = (Rating) getObject( + MediaMetadataEditor.RATING_KEY_BY_USER, null); + mAudioManager.updateRemoteControlClientMetadata(genId, + MediaMetadataEditor.RATING_KEY_BY_USER, + rating); + } else { + Log.e(TAG, "no metadata to apply"); + } } - // NOT setting mApplied to true as this type of MetadataEditor will be applied - // multiple times, whenever the user of a RemoteController needs to change the - // metadata (e.g. user changes the rating of a song more than once during playback) - mApplied = false; } + // NOT setting mApplied to true as this type of MetadataEditor will be applied + // multiple times, whenever the user of a RemoteController needs to change the + // metadata (e.g. user changes the rating of a song more than once during playback) + mApplied = false; } } @@ -649,6 +721,46 @@ public final class RemoteController } } + /** + * This receives updates when the current session changes. This is + * registered to receive the updates on the handler thread so it can call + * directly into the appropriate methods. + */ + private class MediaControllerCallback extends MediaController.Callback { + @Override + public void onPlaybackStateChanged(PlaybackState state) { + onNewPlaybackState(state); + } + + @Override + public void onMetadataChanged(MediaMetadata metadata) { + onNewMediaMetadata(metadata); + } + } + + /** + * Listens for changes to the active session stack and replaces the + * currently tracked session if it has changed. + */ + private class TopTransportSessionListener extends MediaSessionManager.SessionListener { + @Override + public void onActiveSessionsChanged(List<MediaController> controllers) { + int size = controllers.size(); + for (int i = 0; i < size; i++) { + MediaController controller = controllers.get(i); + long flags = controller.getFlags(); + // We only care about sessions that handle transport controls, + // which will be true for apps using RCC + if ((flags & MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS) != 0) { + updateController(controller); + return; + } + } + updateController(null); + } + + } + //================================================== // Event handling private final EventHandler mEventHandler; @@ -658,6 +770,8 @@ public final class RemoteController 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 class EventHandler extends Handler { @@ -686,12 +800,46 @@ public final class RemoteController case MSG_DISPLAY_ENABLE: onDisplayEnable(msg.arg1 == 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: + onNewMediaMetadata((MediaMetadata) msg.obj); + break; default: Log.e(TAG, "unknown event " + msg.what); } } } + /** + * @hide + */ + void startListeningToSessions() { + final ComponentName listenerComponent = new ComponentName(mContext, + mOnClientUpdateListener.getClass()); + mSessionManager.addActiveSessionsListener(mSessionListener, listenerComponent, + ActivityManager.getCurrentUser()); + mSessionListener.onActiveSessionsChanged(mSessionManager + .getActiveSessions(listenerComponent)); + if (DEBUG) { + Log.d(TAG, "Registered session listener with component " + listenerComponent + + " for user " + ActivityManager.getCurrentUser()); + } + } + + /** + * @hide + */ + void stopListeningToSessions() { + mSessionManager.removeActiveSessionsListener(mSessionListener); + if (DEBUG) { + Log.d(TAG, "Unregistered session listener for user " + + ActivityManager.getCurrentUser()); + } + } + /** If the msg is already queued, replace it with this one. */ private static final int SENDMSG_REPLACE = 0; /** If the msg is already queued, ignore this one and leave the old. */ @@ -713,6 +861,7 @@ public final class RemoteController 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) { @@ -848,6 +997,86 @@ public final class RemoteController } } + ///////////// 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 " + + mCurrentSession); + } + synchronized (mInfoLock) { + if (controller == null) { + if (mCurrentSession != null) { + mCurrentSession.removeCallback(mSessionCb); + mCurrentSession = null; + sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE, + 0 /* genId */, 1 /* clearing */, null /* obj */, 0 /* delay */); + } + } else if (mCurrentSession == null + || !controller.getSessionInfo().getId() + .equals(mCurrentSession.getSessionInfo().getId())) { + if (mCurrentSession != null) { + mCurrentSession.removeCallback(mSessionCb); + } + sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE, + 0 /* genId */, 0 /* clearing */, null /* obj */, 0 /* delay */); + mCurrentSession = controller; + mCurrentSession.addCallback(mSessionCb, mEventHandler); + + PlaybackState state = controller.getPlaybackState(); + sendMsg(mEventHandler, MSG_NEW_PLAYBACK_STATE, SENDMSG_REPLACE, + 0 /* genId */, 0, state /* obj */, 0 /* delay */); + + MediaMetadata metadata = controller.getMetadata(); + sendMsg(mEventHandler, MSG_NEW_MEDIA_METADATA, SENDMSG_REPLACE, + 0 /* arg1 */, 0 /* arg2 */, metadata /* obj */, 0 /* delay */); + } + // else same controller, no need to update + } + } + + private void onNewPlaybackState(PlaybackState state) { + final OnClientUpdateListener l; + synchronized (mInfoLock) { + l = this.mOnClientUpdateListener; + } + if (l != null) { + int playstate = state == null ? RemoteControlClient.PLAYSTATE_NONE : PlaybackState + .getRccStateFromState(state.getState()); + if (state == null || state.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN) { + l.onClientPlaybackStateUpdate(playstate); + } else { + l.onClientPlaybackStateUpdate(playstate, state.getLastPositionUpdateTime(), + state.getPosition(), state.getPlaybackRate()); + } + if (state != null) { + l.onClientTransportControlUpdate(PlaybackState.getRccControlFlagsFromActions(state + .getActions())); + } + } + } + + private void onNewMediaMetadata(MediaMetadata metadata) { + if (metadata == null) { + // RemoteController only handles non-null metadata + return; + } + final OnClientUpdateListener l; + final MetadataEditor metadataEditor; + // prepare the received Bundle to be used inside a MetadataEditor + synchronized(mInfoLock) { + l = mOnClientUpdateListener; + boolean canRate = mCurrentSession != null + && mCurrentSession.getRatingType() != Rating.RATING_NONE; + long editableKeys = canRate ? MediaMetadataEditor.RATING_KEY_BY_USER : 0; + Bundle legacyMetadata = MediaSessionLegacyHelper.getOldMetadata(metadata); + mMetadataEditor = new MetadataEditor(legacyMetadata, editableKeys); + metadataEditor = mMetadataEditor; + } + if (l != null) { + l.onClientMetadataUpdate(metadataEditor); + } + } + //================================================== private static class PlaybackInfo { int mState; diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl index 7c039079796a..f0cd7856ece7 100644 --- a/media/java/android/media/session/ISessionController.aidl +++ b/media/java/android/media/session/ISessionController.aidl @@ -37,6 +37,7 @@ interface ISessionController { boolean isTransportControlEnabled(); void showRoutePicker(); MediaSessionInfo getSessionInfo(); + long getFlags(); // These commands are for the TransportController void play(); diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index 57a0a540c781..5ca7daa6560f 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -57,6 +57,7 @@ public final class MediaController { private final Object mLock = new Object(); private boolean mCbRegistered = false; + private MediaSessionInfo mInfo; private TransportControls mTransportController; @@ -174,6 +175,21 @@ public final class MediaController { } /** + * Get the flags for this session. + * + * @return The current set of flags for the session. + * @hide + */ + public long getFlags() { + try { + return mSessionBinder.getFlags(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling getFlags.", e); + } + return 0; + } + + /** * Adds a callback to receive updates from the Session. Updates will be * posted on the caller's thread. * @@ -253,12 +269,14 @@ public final class MediaController { * @hide */ public MediaSessionInfo getSessionInfo() { - try { - return mSessionBinder.getSessionInfo(); - } catch (RemoteException e) { - Log.e(TAG, "Error in getSessionInfo.", e); + if (mInfo == null) { + try { + mInfo = mSessionBinder.getSessionInfo(); + } catch (RemoteException e) { + Log.e(TAG, "Error in getSessionInfo.", e); + } } - return null; + return mInfo; } /* diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java index 099f60152c65..801844fd9b01 100644 --- a/media/java/android/media/session/MediaSessionLegacyHelper.java +++ b/media/java/android/media/session/MediaSessionLegacyHelper.java @@ -20,6 +20,10 @@ import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.content.Context; import android.content.Intent; +import android.media.MediaMetadata; +import android.media.MediaMetadataEditor; +import android.media.MediaMetadataRetriever; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.ArrayMap; @@ -64,6 +68,88 @@ public class MediaSessionLegacyHelper { return sInstance; } + public static Bundle getOldMetadata(MediaMetadata metadata) { + Bundle oldMetadata = new Bundle(); + if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM)) { + oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUM), + metadata.getString(MediaMetadata.METADATA_KEY_ALBUM)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_ART)) { + oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), + metadata.getBitmap(MediaMetadata.METADATA_KEY_ART)); + } else if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART)) { + // Fall back to album art if the track art wasn't available + oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), + metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ARTIST)) { + oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST), + metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ARTIST)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_ARTIST)) { + oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ARTIST), + metadata.getString(MediaMetadata.METADATA_KEY_ARTIST)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_AUTHOR)) { + oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_AUTHOR), + metadata.getString(MediaMetadata.METADATA_KEY_AUTHOR)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_COMPILATION)) { + oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_COMPILATION), + metadata.getString(MediaMetadata.METADATA_KEY_COMPILATION)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_COMPOSER)) { + oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_COMPOSER), + metadata.getString(MediaMetadata.METADATA_KEY_COMPOSER)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_DATE)) { + oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DATE), + metadata.getString(MediaMetadata.METADATA_KEY_DATE)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_DISC_NUMBER)) { + oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER), + metadata.getLong(MediaMetadata.METADATA_KEY_DISC_NUMBER)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) { + oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DURATION), + metadata.getLong(MediaMetadata.METADATA_KEY_DURATION)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_GENRE)) { + oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_GENRE), + metadata.getString(MediaMetadata.METADATA_KEY_GENRE)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_NUM_TRACKS)) { + oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS), + metadata.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_RATING)) { + oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.RATING_KEY_BY_OTHERS), + metadata.getRating(MediaMetadata.METADATA_KEY_RATING)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_USER_RATING)) { + oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER), + metadata.getRating(MediaMetadata.METADATA_KEY_USER_RATING)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_TITLE)) { + oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_TITLE), + metadata.getString(MediaMetadata.METADATA_KEY_TITLE)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER)) { + oldMetadata.putLong( + String.valueOf(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER), + metadata.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_WRITER)) { + oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_WRITER), + metadata.getString(MediaMetadata.METADATA_KEY_WRITER)); + } + if (metadata.containsKey(MediaMetadata.METADATA_KEY_YEAR)) { + oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_YEAR), + metadata.getString(MediaMetadata.METADATA_KEY_YEAR)); + } + return oldMetadata; + } + public MediaSession getSession(PendingIntent pi) { SessionHolder holder = mSessions.get(pi); return holder == null ? null : holder.mSession; diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java index 291bfc8f9de3..8eceee887bfa 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -96,10 +96,13 @@ public final class MediaSessionManager { } /** - * Get a list of controllers for all ongoing sessions. This requires the - * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by - * the calling app. You may also retrieve this list if your app is an - * enabled notification listener using the + * Get a list of controllers for all ongoing sessions. The controllers will + * be provided in priority order with the most important controller at index + * 0. + * <p> + * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL + * permission be held by the calling app. You may also retrieve this list if + * your app is an enabled notification listener using the * {@link NotificationListenerService} APIs, in which case you must pass the * {@link ComponentName} of your enabled listener. * @@ -239,7 +242,8 @@ public final class MediaSessionManager { /** * Called when the list of active sessions has changed. This can be due * to a session being added or removed or the order of sessions - * changing. + * changing. The controllers will be provided in priority order with the + * most important controller at index 0. * * @param controllers The updated list of controllers for the user that * changed. diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java index e09ac3f136ce..3b3f24960a39 100644 --- a/media/java/android/media/session/PlaybackState.java +++ b/media/java/android/media/session/PlaybackState.java @@ -432,6 +432,8 @@ public final class PlaybackState implements Parcelable { return STATE_REWINDING; case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: return STATE_SKIPPING_TO_PREVIOUS; + case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: + return STATE_SKIPPING_TO_NEXT; case RemoteControlClient.PLAYSTATE_STOPPED: return STATE_STOPPED; default: @@ -440,6 +442,41 @@ public final class PlaybackState implements Parcelable { } /** + * Get the {@link RemoteControlClient} state for the given + * {@link PlaybackState} state. + * + * @param state The state used by {@link PlaybackState}. + * @return The equivalent state used by {@link RemoteControlClient}. + * @hide + */ + public static int getRccStateFromState(int state) { + switch (state) { + case STATE_BUFFERING: + return RemoteControlClient.PLAYSTATE_BUFFERING; + case STATE_ERROR: + return RemoteControlClient.PLAYSTATE_ERROR; + case STATE_FAST_FORWARDING: + return RemoteControlClient.PLAYSTATE_FAST_FORWARDING; + case STATE_NONE: + return RemoteControlClient.PLAYSTATE_NONE; + case STATE_PAUSED: + return RemoteControlClient.PLAYSTATE_PAUSED; + case STATE_PLAYING: + return RemoteControlClient.PLAYSTATE_PLAYING; + case STATE_REWINDING: + return RemoteControlClient.PLAYSTATE_REWINDING; + case STATE_SKIPPING_TO_PREVIOUS: + return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS; + case STATE_SKIPPING_TO_NEXT: + return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS; + case STATE_STOPPED: + return RemoteControlClient.PLAYSTATE_STOPPED; + default: + return -1; + } + } + + /** * @hide */ public static long getActionsFromRccControlFlags(int rccFlags) { @@ -454,6 +491,21 @@ public final class PlaybackState implements Parcelable { return actions; } + /** + * @hide + */ + public static int getRccControlFlagsFromActions(long actions) { + int rccFlags = 0; + long action = 1; + while (action <= actions && action < Integer.MAX_VALUE) { + if ((action & actions) != 0) { + rccFlags |= getRccFlagForAction(action); + } + action = action << 1; + } + return rccFlags; + } + private static long getActionForRccFlag(int flag) { switch (flag) { case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS: @@ -480,6 +532,35 @@ public final class PlaybackState implements Parcelable { return 0; } + private static int getRccFlagForAction(long action) { + // We only care about the lower set of actions that can map to rcc + // flags. + int testAction = action < Integer.MAX_VALUE ? (int) action : 0; + switch (testAction) { + case (int) ACTION_SKIP_TO_PREVIOUS: + return RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS; + case (int) ACTION_REWIND: + return RemoteControlClient.FLAG_KEY_MEDIA_REWIND; + case (int) ACTION_PLAY: + return RemoteControlClient.FLAG_KEY_MEDIA_PLAY; + case (int) ACTION_PLAY_PAUSE: + return RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE; + case (int) ACTION_PAUSE: + return RemoteControlClient.FLAG_KEY_MEDIA_PAUSE; + case (int) ACTION_STOP: + return RemoteControlClient.FLAG_KEY_MEDIA_STOP; + case (int) ACTION_FAST_FORWARD: + return RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD; + case (int) ACTION_SKIP_TO_NEXT: + return RemoteControlClient.FLAG_KEY_MEDIA_NEXT; + case (int) ACTION_SEEK_TO: + return RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE; + case (int) ACTION_SET_RATING: + return RemoteControlClient.FLAG_KEY_MEDIA_RATING; + } + return 0; + } + public static final Parcelable.Creator<PlaybackState> CREATOR = new Parcelable.Creator<PlaybackState>() { @Override diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 9087726a3ecc..657d5eca5aa4 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -630,8 +630,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) log("ConnectivityService starting up"); NetworkCapabilities netCap = new NetworkCapabilities(); - netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); mDefaultRequest = new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId()); NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(), NetworkRequestInfo.REQUEST); diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 835b0941abc2..9ae8aed08784 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -949,6 +949,11 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override + public long getFlags() { + return mFlags; + } + + @Override public void play() throws RemoteException { mSessionCb.play(); } |