Merge "Per-app media directories on external storage." into lmp-preview-dev
diff --git a/api/current.txt b/api/current.txt
index c34cd24..265c682 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12661,6 +12661,9 @@
     method public int getWidth();
     method public int getX();
     method public int getY();
+    field public static final int METERING_WEIGHT_DONT_CARE = 0; // 0x0
+    field public static final int METERING_WEIGHT_MAX = 1000; // 0x3e8
+    field public static final int METERING_WEIGHT_MIN = 0; // 0x0
   }
 
   public final class RggbChannelVector {
@@ -14194,7 +14197,6 @@
     method public final void release();
     method public final void releaseOutputBuffer(int, boolean);
     method public final void releaseOutputBuffer(int, long);
-    method public void setNotificationCallback(android.media.MediaCodec.NotificationCallback);
     method public final void setParameters(android.os.Bundle);
     method public final void setVideoScalingMode(int);
     method public final void signalEndOfInputStream();
@@ -14244,10 +14246,6 @@
     field public int numSubSamples;
   }
 
-  public static abstract interface MediaCodec.NotificationCallback {
-    method public abstract void onCodecNotify(android.media.MediaCodec);
-  }
-
   public final class MediaCodecInfo {
     method public final android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(java.lang.String);
     method public final java.lang.String getName();
@@ -14576,6 +14574,7 @@
     method public long getLong(java.lang.String);
     method public android.media.Rating getRating(java.lang.String);
     method public java.lang.String getString(java.lang.String);
+    method public java.util.Set<java.lang.String> keySet();
     method public int size();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
@@ -15713,56 +15712,81 @@
   public final class MediaController {
     method public void addCallback(android.media.session.MediaController.Callback);
     method public void addCallback(android.media.session.MediaController.Callback, android.os.Handler);
+    method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
     method public static android.media.session.MediaController fromToken(android.media.session.MediaSessionToken);
-    method public android.media.session.TransportController getTransportController();
+    method public android.media.MediaMetadata getMetadata();
+    method public android.media.session.PlaybackState getPlaybackState();
+    method public int getRatingType();
+    method public android.media.session.MediaController.TransportControls getTransportControls();
     method public void removeCallback(android.media.session.MediaController.Callback);
-    method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-    method public void sendMediaButton(int);
+    method public void sendControlCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
   }
 
   public static abstract class MediaController.Callback {
     ctor public MediaController.Callback();
-    method public void onEvent(java.lang.String, android.os.Bundle);
+    method public void onMetadataChanged(android.media.MediaMetadata);
+    method public void onPlaybackStateChanged(android.media.session.PlaybackState);
+    method public void onSessionEvent(java.lang.String, android.os.Bundle);
+  }
+
+  public final class MediaController.TransportControls {
+    method public void fastForward();
+    method public void pause();
+    method public void play();
+    method public void rewind();
+    method public void seekTo(long);
+    method public void setRating(android.media.Rating);
+    method public void skipToNext();
+    method public void skipToPrevious();
+    method public void stop();
   }
 
   public final class MediaSession {
     method public void addCallback(android.media.session.MediaSession.Callback);
     method public void addCallback(android.media.session.MediaSession.Callback, android.os.Handler);
+    method public void addTransportControlsCallback(android.media.session.MediaSession.TransportControlsCallback);
+    method public void addTransportControlsCallback(android.media.session.MediaSession.TransportControlsCallback, android.os.Handler);
     method public android.media.session.MediaSessionToken getSessionToken();
-    method public android.media.session.TransportPerformer getTransportPerformer();
     method public boolean isActive();
     method public void release();
     method public void removeCallback(android.media.session.MediaSession.Callback);
-    method public void sendEvent(java.lang.String, android.os.Bundle);
+    method public void removeTransportControlsCallback(android.media.session.MediaSession.TransportControlsCallback);
+    method public void sendSessionEvent(java.lang.String, android.os.Bundle);
     method public void setActive(boolean);
     method public void setFlags(int);
     method public void setLaunchPendingIntent(android.app.PendingIntent);
-    method public void useLocalPlayback(int);
-    method public void useRemotePlayback(android.media.session.RemoteVolumeProvider);
+    method public void setMetadata(android.media.MediaMetadata);
+    method public void setPlaybackState(android.media.session.PlaybackState);
+    method public void setPlaybackToLocal(int);
+    method public void setPlaybackToRemote(android.media.session.RemoteVolumeProvider);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
   public static abstract class MediaSession.Callback {
     ctor public MediaSession.Callback();
-    method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-    method public void onMediaButton(android.content.Intent);
+    method public void onControlCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+    method public void onMediaButtonEvent(android.content.Intent);
   }
 
-  public final class MediaSessionInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.lang.String getId();
-    method public java.lang.String getPackageName();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
+  public static abstract class MediaSession.TransportControlsCallback {
+    ctor public MediaSession.TransportControlsCallback();
+    method public void onFastForward();
+    method public void onPause();
+    method public void onPlay();
+    method public void onRewind();
+    method public void onSeekTo(long);
+    method public void onSetRating(android.media.Rating);
+    method public void onSkipToNext();
+    method public void onSkipToPrevious();
+    method public void onStop();
   }
 
   public final class MediaSessionManager {
     method public android.media.session.MediaSession createSession(java.lang.String);
-    method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName);
   }
 
-  public class MediaSessionToken implements android.os.Parcelable {
+  public final class MediaSessionToken implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
@@ -15774,95 +15798,50 @@
     method public int describeContents();
     method public long getActions();
     method public long getBufferPosition();
-    method public java.lang.String getErrorMessage();
+    method public java.lang.CharSequence getErrorMessage();
+    method public float getPlaybackRate();
     method public long getPosition();
-    method public float getRate();
     method public int getState();
     method public void setActions(long);
     method public void setBufferPosition(long);
-    method public void setErrorMessage(java.lang.String);
+    method public void setErrorMessage(java.lang.CharSequence);
     method public void setState(int, long, float);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final long ACTION_FASTFORWARD = 64L; // 0x40L
-    field public static final long ACTION_NEXT_ITEM = 32L; // 0x20L
+    field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
     field public static final long ACTION_PAUSE = 2L; // 0x2L
     field public static final long ACTION_PLAY = 4L; // 0x4L
     field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
-    field public static final long ACTION_PREVIOUS_ITEM = 16L; // 0x10L
-    field public static final long ACTION_RATING = 128L; // 0x80L
     field public static final long ACTION_REWIND = 8L; // 0x8L
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
+    field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
+    field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
-    field public static final int PLAYSTATE_BUFFERING = 6; // 0x6
-    field public static final int PLAYSTATE_ERROR = 7; // 0x7
-    field public static final int PLAYSTATE_FAST_FORWARDING = 4; // 0x4
-    field public static final int PLAYSTATE_NONE = 0; // 0x0
-    field public static final int PLAYSTATE_PAUSED = 2; // 0x2
-    field public static final int PLAYSTATE_PLAYING = 3; // 0x3
-    field public static final int PLAYSTATE_REWINDING = 5; // 0x5
-    field public static final int PLAYSTATE_SKIPPING_BACKWARDS = 9; // 0x9
-    field public static final int PLAYSTATE_SKIPPING_FORWARDS = 10; // 0xa
-    field public static final int PLAYSTATE_STOPPED = 1; // 0x1
+    field public static final int STATE_BUFFERING = 6; // 0x6
+    field public static final int STATE_ERROR = 7; // 0x7
+    field public static final int STATE_FAST_FORWARDING = 4; // 0x4
+    field public static final int STATE_NONE = 0; // 0x0
+    field public static final int STATE_PAUSED = 2; // 0x2
+    field public static final int STATE_PLAYING = 3; // 0x3
+    field public static final int STATE_REWINDING = 5; // 0x5
+    field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
+    field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
+    field public static final int STATE_STOPPED = 1; // 0x1
   }
 
   public abstract class RemoteVolumeProvider {
     ctor public RemoteVolumeProvider(int, int);
-    method public abstract int getCurrentVolume();
-    method public final int getFlags();
     method public final int getMaxVolume();
+    method public final int getVolumeControl();
     method public final void notifyVolumeChanged();
-    method public void onAdjustVolume(int);
-    method public void onSetVolume(int);
-    field public static final int FLAG_VOLUME_ABSOLUTE = 2; // 0x2
-    field public static final int FLAG_VOLUME_RELATIVE = 1; // 0x1
-  }
-
-  public final class TransportController {
-    method public void addStateListener(android.media.session.TransportController.TransportStateListener);
-    method public void addStateListener(android.media.session.TransportController.TransportStateListener, android.os.Handler);
-    method public void fastForward();
-    method public android.media.MediaMetadata getMetadata();
-    method public android.media.session.PlaybackState getPlaybackState();
-    method public int getRatingType();
-    method public void next();
-    method public void pause();
-    method public void play();
-    method public void previous();
-    method public void rate(android.media.Rating);
-    method public void removeStateListener(android.media.session.TransportController.TransportStateListener);
-    method public void rewind();
-    method public void seekTo(long);
-    method public void stop();
-  }
-
-  public static abstract class TransportController.TransportStateListener {
-    ctor public TransportController.TransportStateListener();
-    method public void onMetadataChanged(android.media.MediaMetadata);
-    method public void onPlaybackStateChanged(android.media.session.PlaybackState);
-  }
-
-  public final class TransportPerformer {
-    method public void addListener(android.media.session.TransportPerformer.Listener);
-    method public void addListener(android.media.session.TransportPerformer.Listener, android.os.Handler);
-    method public void removeListener(android.media.session.TransportPerformer.Listener);
-    method public final void setMetadata(android.media.MediaMetadata);
-    method public final void setPlaybackState(android.media.session.PlaybackState);
-  }
-
-  public static abstract class TransportPerformer.Listener {
-    ctor public TransportPerformer.Listener();
-    method public void onFastForward();
-    method public void onNext();
-    method public void onPause();
-    method public void onPlay();
-    method public void onPrevious();
-    method public void onRate(android.media.Rating);
-    method public void onRewind();
-    method public void onRouteFocusChange(int);
-    method public void onSeekTo(long);
-    method public void onStop();
+    method public void onAdjustVolumeBy(int);
+    method public abstract int onGetCurrentVolume();
+    method public void onSetVolumeTo(int);
+    field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+    field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+    field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
   }
 
 }
@@ -20443,6 +20422,37 @@
     ctor public BadParcelableException(java.lang.Exception);
   }
 
+  public class BaseBundle {
+    method public void clear();
+    method public boolean containsKey(java.lang.String);
+    method public java.lang.Object get(java.lang.String);
+    method public double getDouble(java.lang.String);
+    method public double getDouble(java.lang.String, double);
+    method public double[] getDoubleArray(java.lang.String);
+    method public int getInt(java.lang.String);
+    method public int getInt(java.lang.String, int);
+    method public int[] getIntArray(java.lang.String);
+    method public long getLong(java.lang.String);
+    method public long getLong(java.lang.String, long);
+    method public long[] getLongArray(java.lang.String);
+    method public java.lang.String getString(java.lang.String);
+    method public java.lang.String getString(java.lang.String, java.lang.String);
+    method public java.lang.String[] getStringArray(java.lang.String);
+    method public boolean isEmpty();
+    method public java.util.Set<java.lang.String> keySet();
+    method public void putAll(android.os.PersistableBundle);
+    method public void putDouble(java.lang.String, double);
+    method public void putDoubleArray(java.lang.String, double[]);
+    method public void putInt(java.lang.String, int);
+    method public void putIntArray(java.lang.String, int[]);
+    method public void putLong(java.lang.String, long);
+    method public void putLongArray(java.lang.String, long[]);
+    method public void putString(java.lang.String, java.lang.String);
+    method public void putStringArray(java.lang.String, java.lang.String[]);
+    method public void remove(java.lang.String);
+    method public int size();
+  }
+
   public class BatteryManager {
     ctor public BatteryManager();
     method public android.os.BatteryProperty getProperty(int) throws android.os.RemoteException;
@@ -20571,17 +20581,14 @@
     field public static final int L = 10000; // 0x2710
   }
 
-  public final class Bundle extends android.os.CommonBundle {
+  public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
     ctor public Bundle();
     ctor public Bundle(java.lang.ClassLoader);
     ctor public Bundle(int);
     ctor public Bundle(android.os.Bundle);
     ctor public Bundle(android.os.PersistableBundle);
-    method public void clear();
     method public java.lang.Object clone();
-    method public boolean containsKey(java.lang.String);
     method public int describeContents();
-    method public java.lang.Object get(java.lang.String);
     method public android.os.IBinder getBinder(java.lang.String);
     method public boolean getBoolean(java.lang.String);
     method public boolean getBoolean(java.lang.String, boolean);
@@ -20598,37 +20605,21 @@
     method public java.lang.CharSequence[] getCharSequenceArray(java.lang.String);
     method public java.util.ArrayList<java.lang.CharSequence> getCharSequenceArrayList(java.lang.String);
     method public java.lang.ClassLoader getClassLoader();
-    method public double getDouble(java.lang.String);
-    method public double getDouble(java.lang.String, double);
-    method public double[] getDoubleArray(java.lang.String);
     method public float getFloat(java.lang.String);
     method public float getFloat(java.lang.String, float);
     method public float[] getFloatArray(java.lang.String);
-    method public int getInt(java.lang.String);
-    method public int getInt(java.lang.String, int);
-    method public int[] getIntArray(java.lang.String);
     method public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(java.lang.String);
-    method public long getLong(java.lang.String);
-    method public long getLong(java.lang.String, long);
-    method public long[] getLongArray(java.lang.String);
     method public T getParcelable(java.lang.String);
     method public android.os.Parcelable[] getParcelableArray(java.lang.String);
     method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
-    method public android.os.PersistableBundle getPersistableBundle(java.lang.String);
     method public java.io.Serializable getSerializable(java.lang.String);
     method public short getShort(java.lang.String);
     method public short getShort(java.lang.String, short);
     method public short[] getShortArray(java.lang.String);
     method public android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
-    method public java.lang.String getString(java.lang.String);
-    method public java.lang.String getString(java.lang.String, java.lang.String);
-    method public java.lang.String[] getStringArray(java.lang.String);
     method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
     method public boolean hasFileDescriptors();
-    method public boolean isEmpty();
-    method public java.util.Set<java.lang.String> keySet();
     method public void putAll(android.os.Bundle);
-    method public void putAll(android.os.PersistableBundle);
     method public void putBinder(java.lang.String, android.os.IBinder);
     method public void putBoolean(java.lang.String, boolean);
     method public void putBooleanArray(java.lang.String, boolean[]);
@@ -20640,30 +20631,19 @@
     method public void putCharSequence(java.lang.String, java.lang.CharSequence);
     method public void putCharSequenceArray(java.lang.String, java.lang.CharSequence[]);
     method public void putCharSequenceArrayList(java.lang.String, java.util.ArrayList<java.lang.CharSequence>);
-    method public void putDouble(java.lang.String, double);
-    method public void putDoubleArray(java.lang.String, double[]);
     method public void putFloat(java.lang.String, float);
     method public void putFloatArray(java.lang.String, float[]);
-    method public void putInt(java.lang.String, int);
-    method public void putIntArray(java.lang.String, int[]);
     method public void putIntegerArrayList(java.lang.String, java.util.ArrayList<java.lang.Integer>);
-    method public void putLong(java.lang.String, long);
-    method public void putLongArray(java.lang.String, long[]);
     method public void putParcelable(java.lang.String, android.os.Parcelable);
     method public void putParcelableArray(java.lang.String, android.os.Parcelable[]);
     method public void putParcelableArrayList(java.lang.String, java.util.ArrayList<? extends android.os.Parcelable>);
-    method public void putPersistableBundle(java.lang.String, android.os.PersistableBundle);
     method public void putSerializable(java.lang.String, java.io.Serializable);
     method public void putShort(java.lang.String, short);
     method public void putShortArray(java.lang.String, short[]);
     method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>);
-    method public void putString(java.lang.String, java.lang.String);
-    method public void putStringArray(java.lang.String, java.lang.String[]);
     method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>);
     method public void readFromParcel(android.os.Parcel);
-    method public void remove(java.lang.String);
     method public void setClassLoader(java.lang.ClassLoader);
-    method public int size();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final android.os.Bundle EMPTY;
@@ -20681,9 +20661,6 @@
     method public abstract void onCancel();
   }
 
-   abstract class CommonBundle implements java.lang.Cloneable android.os.Parcelable {
-  }
-
   public class ConditionVariable {
     ctor public ConditionVariable();
     ctor public ConditionVariable(boolean);
@@ -21263,46 +21240,14 @@
     field public static final int PATTERN_SIMPLE_GLOB = 2; // 0x2
   }
 
-  public final class PersistableBundle extends android.os.CommonBundle {
+  public final class PersistableBundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
     ctor public PersistableBundle();
-    ctor public PersistableBundle(java.lang.ClassLoader);
     ctor public PersistableBundle(int);
     ctor public PersistableBundle(android.os.PersistableBundle);
-    method public void clear();
     method public java.lang.Object clone();
-    method public boolean containsKey(java.lang.String);
     method public int describeContents();
-    method public java.lang.Object get(java.lang.String);
-    method public java.lang.ClassLoader getClassLoader();
-    method public double getDouble(java.lang.String);
-    method public double getDouble(java.lang.String, double);
-    method public double[] getDoubleArray(java.lang.String);
-    method public int getInt(java.lang.String);
-    method public int getInt(java.lang.String, int);
-    method public int[] getIntArray(java.lang.String);
-    method public long getLong(java.lang.String);
-    method public long getLong(java.lang.String, long);
-    method public long[] getLongArray(java.lang.String);
     method public android.os.PersistableBundle getPersistableBundle(java.lang.String);
-    method public java.lang.String getString(java.lang.String);
-    method public java.lang.String getString(java.lang.String, java.lang.String);
-    method public java.lang.String[] getStringArray(java.lang.String);
-    method public boolean isEmpty();
-    method public java.util.Set<java.lang.String> keySet();
-    method public void putAll(android.os.PersistableBundle);
-    method public void putDouble(java.lang.String, double);
-    method public void putDoubleArray(java.lang.String, double[]);
-    method public void putInt(java.lang.String, int);
-    method public void putIntArray(java.lang.String, int[]);
-    method public void putLong(java.lang.String, long);
-    method public void putLongArray(java.lang.String, long[]);
     method public void putPersistableBundle(java.lang.String, android.os.PersistableBundle);
-    method public void putString(java.lang.String, java.lang.String);
-    method public void putStringArray(java.lang.String, java.lang.String[]);
-    method public void readFromParcel(android.os.Parcel);
-    method public void remove(java.lang.String);
-    method public void setClassLoader(java.lang.ClassLoader);
-    method public int size();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final android.os.PersistableBundle EMPTY;
@@ -37700,8 +37645,10 @@
     method public void setOnMenuItemClickListener(android.widget.Toolbar.OnMenuItemClickListener);
     method public void setSubtitle(int);
     method public void setSubtitle(java.lang.CharSequence);
+    method public void setSubtitleTextAppearance(android.content.Context, int);
     method public void setTitle(int);
     method public void setTitle(java.lang.CharSequence);
+    method public void setTitleTextAppearance(android.content.Context, int);
     method public boolean showOverflowMenu();
   }
 
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 6aa24e6..d4dfdd5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -691,8 +691,12 @@
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array. The weight
-     * should be nonnegative.</p>
+     * bottom-right pixel in the active pixel array.</p>
+     * <p>The weight must range from 0 to 1000, and represents a weight
+     * for every pixel in the area. This means that a large metering area
+     * with the same weight as a smaller area will have more effect in
+     * the metering result. Metering areas can partially overlap and the
+     * camera device will add the weights in the overlap region.</p>
      * <p>If all regions have 0 weight, then no specific metering area
      * needs to be used by the camera device. If the metering region is
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
@@ -763,8 +767,12 @@
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array. The weight
-     * should be nonnegative.</p>
+     * bottom-right pixel in the active pixel array.</p>
+     * <p>The weight must range from 0 to 1000, and represents a weight
+     * for every pixel in the area. This means that a large metering area
+     * with the same weight as a smaller area will have more effect in
+     * the metering result. Metering areas can partially overlap and the
+     * camera device will add the weights in the overlap region.</p>
      * <p>If all regions have 0 weight, then no specific metering area
      * needs to be used by the camera device. If the metering region is
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
@@ -846,8 +854,12 @@
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array. The weight
-     * should be nonnegative.</p>
+     * bottom-right pixel in the active pixel array.</p>
+     * <p>The weight must range from 0 to 1000, and represents a weight
+     * for every pixel in the area. This means that a large metering area
+     * with the same weight as a smaller area will have more effect in
+     * the metering result. Metering areas can partially overlap and the
+     * camera device will add the weights in the overlap region.</p>
      * <p>If all regions have 0 weight, then no specific metering area
      * needs to be used by the camera device. If the metering region is
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 2da3625..7d07c92 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -537,8 +537,12 @@
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array. The weight
-     * should be nonnegative.</p>
+     * bottom-right pixel in the active pixel array.</p>
+     * <p>The weight must range from 0 to 1000, and represents a weight
+     * for every pixel in the area. This means that a large metering area
+     * with the same weight as a smaller area will have more effect in
+     * the metering result. Metering areas can partially overlap and the
+     * camera device will add the weights in the overlap region.</p>
      * <p>If all regions have 0 weight, then no specific metering area
      * needs to be used by the camera device. If the metering region is
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
@@ -807,8 +811,12 @@
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array. The weight
-     * should be nonnegative.</p>
+     * bottom-right pixel in the active pixel array.</p>
+     * <p>The weight must range from 0 to 1000, and represents a weight
+     * for every pixel in the area. This means that a large metering area
+     * with the same weight as a smaller area will have more effect in
+     * the metering result. Metering areas can partially overlap and the
+     * camera device will add the weights in the overlap region.</p>
      * <p>If all regions have 0 weight, then no specific metering area
      * needs to be used by the camera device. If the metering region is
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
@@ -1287,8 +1295,12 @@
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
-     * bottom-right pixel in the active pixel array. The weight
-     * should be nonnegative.</p>
+     * bottom-right pixel in the active pixel array.</p>
+     * <p>The weight must range from 0 to 1000, and represents a weight
+     * for every pixel in the area. This means that a large metering area
+     * with the same weight as a smaller area will have more effect in
+     * the metering result. Metering areas can partially overlap and the
+     * camera device will add the weights in the overlap region.</p>
      * <p>If all regions have 0 weight, then no specific metering area
      * needs to be used by the camera device. If the metering region is
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
diff --git a/core/java/android/hardware/camera2/params/MeteringRectangle.java b/core/java/android/hardware/camera2/params/MeteringRectangle.java
index a7a3b59..93fd053 100644
--- a/core/java/android/hardware/camera2/params/MeteringRectangle.java
+++ b/core/java/android/hardware/camera2/params/MeteringRectangle.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.hardware.camera2.params;
 
 import android.util.Size;
@@ -25,22 +26,50 @@
 import android.hardware.camera2.utils.HashCodeHelpers;
 
 /**
- * An immutable class to represent a rectangle {@code (x,y, width, height)} with an
- * additional weight component.
- *
- * </p>The rectangle is defined to be inclusive of the specified coordinates.</p>
- *
- * <p>When used with a {@link CaptureRequest}, the coordinate system is based on the active pixel
+ * An immutable class to represent a rectangle {@code (x, y, width, height)} with an additional
+ * weight component.
+ * <p>
+ * The rectangle is defined to be inclusive of the specified coordinates.
+ * </p>
+ * <p>
+ * When used with a {@link CaptureRequest}, the coordinate system is based on the active pixel
  * array, with {@code (0,0)} being the top-left pixel in the
  * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE active pixel array}, and
  * {@code (android.sensor.info.activeArraySize.width - 1,
- * android.sensor.info.activeArraySize.height - 1)}
- * being the bottom-right pixel in the active pixel array.
+ * android.sensor.info.activeArraySize.height - 1)} being the bottom-right pixel in the active pixel
+ * array.
  * </p>
- *
- * <p>The metering weight is nonnegative.</p>
+ * <p>
+ * The weight must range from {@value #METERING_WEIGHT_MIN} to {@value #METERING_WEIGHT_MAX}
+ * inclusively, and represents a weight for every pixel in the area. This means that a large
+ * metering area with the same weight as a smaller area will have more effect in the metering
+ * result. Metering areas can partially overlap and the camera device will add the weights in the
+ * overlap rectangle.
+ * </p>
+ * <p>
+ * If all rectangles have 0 weight, then no specific metering area needs to be used by the camera
+ * device. If the metering rectangle is outside the used android.scaler.cropRegion returned in
+ * capture result metadata, the camera device will ignore the sections outside the rectangle and
+ * output the used sections in the result metadata.
+ * </p>
  */
 public final class MeteringRectangle {
+    /**
+     * The minimum value of valid metering weight.
+     */
+    public static final int METERING_WEIGHT_MIN = 0;
+
+    /**
+     * The maximum value of valid metering weight.
+     */
+    public static final int METERING_WEIGHT_MAX = 1000;
+
+    /**
+     * Weights set to this value will cause the camera device to ignore this rectangle.
+     * If all metering rectangles are weighed with 0, the camera device will choose its own metering
+     * rectangles.
+     */
+    public static final int METERING_WEIGHT_DONT_CARE = 0;
 
     private final int mX;
     private final int mY;
@@ -55,8 +84,8 @@
      * @param y coordinate >= 0
      * @param width width >= 0
      * @param height height >= 0
-     * @param meteringWeight weight >= 0
-     *
+     * @param meteringWeight weight between {@value #METERING_WEIGHT_MIN} and
+     *        {@value #METERING_WEIGHT_MAX} inclusively
      * @throws IllegalArgumentException if any of the parameters were negative
      */
     public MeteringRectangle(int x, int y, int width, int height, int meteringWeight) {
@@ -64,7 +93,8 @@
         mY = checkArgumentNonnegative(y, "y must be nonnegative");
         mWidth = checkArgumentNonnegative(width, "width must be nonnegative");
         mHeight = checkArgumentNonnegative(height, "height must be nonnegative");
-        mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
+        mWeight = checkArgumentInRange(
+                meteringWeight, METERING_WEIGHT_MIN, METERING_WEIGHT_MAX, "meteringWeight");
     }
 
     /**
diff --git a/core/java/android/os/CommonBundle.java b/core/java/android/os/BaseBundle.java
similarity index 93%
rename from core/java/android/os/CommonBundle.java
rename to core/java/android/os/BaseBundle.java
index c1b202c..c2a45ba 100644
--- a/core/java/android/os/CommonBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -27,7 +27,7 @@
 /**
  * A mapping from String values to various types.
  */
-abstract class CommonBundle implements Parcelable, Cloneable {
+public class BaseBundle {
     private static final String TAG = "Bundle";
     static final boolean DEBUG = false;
 
@@ -63,7 +63,7 @@
      * inside of the Bundle.
      * @param capacity Initial size of the ArrayMap.
      */
-    CommonBundle(ClassLoader loader, int capacity) {
+    BaseBundle(ClassLoader loader, int capacity) {
         mMap = capacity > 0 ?
                 new ArrayMap<String, Object>(capacity) : new ArrayMap<String, Object>();
         mClassLoader = loader == null ? getClass().getClassLoader() : loader;
@@ -72,7 +72,7 @@
     /**
      * Constructs a new, empty Bundle.
      */
-    CommonBundle() {
+    BaseBundle() {
         this((ClassLoader) null, 0);
     }
 
@@ -82,11 +82,11 @@
      *
      * @param parcelledData a Parcel containing a Bundle
      */
-    CommonBundle(Parcel parcelledData) {
+    BaseBundle(Parcel parcelledData) {
         readFromParcelInner(parcelledData);
     }
 
-    CommonBundle(Parcel parcelledData, int length) {
+    BaseBundle(Parcel parcelledData, int length) {
         readFromParcelInner(parcelledData, length);
     }
 
@@ -97,7 +97,7 @@
      * @param loader An explicit ClassLoader to use when instantiating objects
      * inside of the Bundle.
      */
-    CommonBundle(ClassLoader loader) {
+    BaseBundle(ClassLoader loader) {
         this(loader, 0);
     }
 
@@ -107,7 +107,7 @@
      *
      * @param capacity the initial capacity of the Bundle
      */
-    CommonBundle(int capacity) {
+    BaseBundle(int capacity) {
         this((ClassLoader) null, capacity);
     }
 
@@ -117,7 +117,7 @@
      *
      * @param b a Bundle to be copied.
      */
-    CommonBundle(CommonBundle b) {
+    BaseBundle(BaseBundle b) {
         if (b.mParcelledData != null) {
             if (b.mParcelledData == EMPTY_PARCEL) {
                 mParcelledData = EMPTY_PARCEL;
@@ -148,7 +148,7 @@
      *
      * @hide
      */
-    String getPairValue() {
+    public String getPairValue() {
         unparcel();
         int size = mMap.size();
         if (size > 1) {
@@ -228,7 +228,7 @@
     /**
      * @hide
      */
-    boolean isParcelled() {
+    public boolean isParcelled() {
         return mParcelledData != null;
     }
 
@@ -237,7 +237,7 @@
      *
      * @return the number of mappings as an int.
      */
-    int size() {
+    public int size() {
         unparcel();
         return mMap.size();
     }
@@ -245,7 +245,7 @@
     /**
      * Returns true if the mapping of this Bundle is empty, false otherwise.
      */
-    boolean isEmpty() {
+    public boolean isEmpty() {
         unparcel();
         return mMap.isEmpty();
     }
@@ -253,7 +253,7 @@
     /**
      * Removes all elements from the mapping of this Bundle.
      */
-    void clear() {
+    public void clear() {
         unparcel();
         mMap.clear();
     }
@@ -265,7 +265,7 @@
      * @param key a String key
      * @return true if the key is part of the mapping, false otherwise
      */
-    boolean containsKey(String key) {
+    public boolean containsKey(String key) {
         unparcel();
         return mMap.containsKey(key);
     }
@@ -276,7 +276,7 @@
      * @param key a String key
      * @return an Object, or null
      */
-    Object get(String key) {
+    public Object get(String key) {
         unparcel();
         return mMap.get(key);
     }
@@ -286,24 +286,24 @@
      *
      * @param key a String key
      */
-    void remove(String key) {
+    public void remove(String key) {
         unparcel();
         mMap.remove(key);
     }
 
     /**
-     * Inserts all mappings from the given PersistableBundle into this CommonBundle.
+     * Inserts all mappings from the given PersistableBundle into this BaseBundle.
      *
      * @param bundle a PersistableBundle
      */
-    void putAll(PersistableBundle bundle) {
+    public void putAll(PersistableBundle bundle) {
         unparcel();
         bundle.unparcel();
         mMap.putAll(bundle.mMap);
     }
 
     /**
-     * Inserts all mappings from the given Map into this CommonBundle.
+     * Inserts all mappings from the given Map into this BaseBundle.
      *
      * @param map a Map
      */
@@ -317,7 +317,7 @@
      *
      * @return a Set of String keys
      */
-    Set<String> keySet() {
+    public Set<String> keySet() {
         unparcel();
         return mMap.keySet();
     }
@@ -377,7 +377,7 @@
      * @param key a String, or null
      * @param value an int, or null
      */
-    void putInt(String key, int value) {
+    public void putInt(String key, int value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -389,7 +389,7 @@
      * @param key a String, or null
      * @param value a long
      */
-    void putLong(String key, long value) {
+    public void putLong(String key, long value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -413,7 +413,7 @@
      * @param key a String, or null
      * @param value a double
      */
-    void putDouble(String key, double value) {
+    public void putDouble(String key, double value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -425,7 +425,7 @@
      * @param key a String, or null
      * @param value a String, or null
      */
-    void putString(String key, String value) {
+    public void putString(String key, String value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -545,7 +545,7 @@
      * @param key a String, or null
      * @param value an int array object, or null
      */
-    void putIntArray(String key, int[] value) {
+    public void putIntArray(String key, int[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -557,7 +557,7 @@
      * @param key a String, or null
      * @param value a long array object, or null
      */
-    void putLongArray(String key, long[] value) {
+    public void putLongArray(String key, long[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -581,7 +581,7 @@
      * @param key a String, or null
      * @param value a double array object, or null
      */
-    void putDoubleArray(String key, double[] value) {
+    public void putDoubleArray(String key, double[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -593,7 +593,7 @@
      * @param key a String, or null
      * @param value a String array object, or null
      */
-    void putStringArray(String key, String[] value) {
+    public void putStringArray(String key, String[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -611,18 +611,6 @@
     }
 
     /**
-     * Inserts a PersistableBundle value into the mapping of this Bundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a Bundle object, or null
-     */
-    void putPersistableBundle(String key, PersistableBundle value) {
-        unparcel();
-        mMap.put(key, value);
-    }
-
-    /**
      * Returns the value associated with the given key, or false if
      * no mapping of the desired type exists for the given key.
      *
@@ -789,7 +777,7 @@
      * @param key a String
      * @return an int value
      */
-    int getInt(String key) {
+    public int getInt(String key) {
         unparcel();
         return getInt(key, 0);
     }
@@ -802,7 +790,7 @@
      * @param defaultValue Value to return if key does not exist
      * @return an int value
      */
-    int getInt(String key, int defaultValue) {
+   public int getInt(String key, int defaultValue) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -823,7 +811,7 @@
      * @param key a String
      * @return a long value
      */
-    long getLong(String key) {
+    public long getLong(String key) {
         unparcel();
         return getLong(key, 0L);
     }
@@ -836,7 +824,7 @@
      * @param defaultValue Value to return if key does not exist
      * @return a long value
      */
-    long getLong(String key, long defaultValue) {
+    public long getLong(String key, long defaultValue) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -891,7 +879,7 @@
      * @param key a String
      * @return a double value
      */
-    double getDouble(String key) {
+    public double getDouble(String key) {
         unparcel();
         return getDouble(key, 0.0);
     }
@@ -904,7 +892,7 @@
      * @param defaultValue Value to return if key does not exist
      * @return a double value
      */
-    double getDouble(String key, double defaultValue) {
+    public double getDouble(String key, double defaultValue) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -926,7 +914,7 @@
      * @param key a String, or null
      * @return a String value, or null
      */
-    String getString(String key) {
+    public String getString(String key) {
         unparcel();
         final Object o = mMap.get(key);
         try {
@@ -946,7 +934,7 @@
      * @return the String value associated with the given key, or defaultValue
      *     if no valid String object is currently mapped to that key.
      */
-    String getString(String key, String defaultValue) {
+    public String getString(String key, String defaultValue) {
         final String s = getString(key);
         return (s == null) ? defaultValue : s;
     }
@@ -990,28 +978,6 @@
      * value is explicitly associated with the key.
      *
      * @param key a String, or null
-     * @return a Bundle value, or null
-     */
-    PersistableBundle getPersistableBundle(String key) {
-        unparcel();
-        Object o = mMap.get(key);
-        if (o == null) {
-            return null;
-        }
-        try {
-            return (PersistableBundle) o;
-        } catch (ClassCastException e) {
-            typeWarning(key, o, "Bundle", e);
-            return null;
-        }
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
      * @return a Serializable value, or null
      */
     Serializable getSerializable(String key) {
@@ -1190,7 +1156,7 @@
      * @param key a String, or null
      * @return an int[] value, or null
      */
-    int[] getIntArray(String key) {
+    public int[] getIntArray(String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1212,7 +1178,7 @@
      * @param key a String, or null
      * @return a long[] value, or null
      */
-    long[] getLongArray(String key) {
+    public long[] getLongArray(String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1256,7 +1222,7 @@
      * @param key a String, or null
      * @return a double[] value, or null
      */
-    double[] getDoubleArray(String key) {
+    public double[] getDoubleArray(String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1278,7 +1244,7 @@
      * @param key a String, or null
      * @return a String[] value, or null
      */
-    String[] getStringArray(String key) {
+    public String[] getStringArray(String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index c85e418..e42c3fe 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -28,14 +28,14 @@
  * A mapping from String values to various Parcelable types.
  *
  */
-public final class Bundle extends CommonBundle {
+public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
     public static final Bundle EMPTY;
     static final Parcel EMPTY_PARCEL;
 
     static {
         EMPTY = new Bundle();
         EMPTY.mMap = ArrayMap.EMPTY;
-        EMPTY_PARCEL = CommonBundle.EMPTY_PARCEL;
+        EMPTY_PARCEL = BaseBundle.EMPTY_PARCEL;
     }
 
     private boolean mHasFds = false;
@@ -125,14 +125,6 @@
     }
 
     /**
-     * @hide
-     */
-    @Override
-    public String getPairValue() {
-        return super.getPairValue();
-    }
-
-    /**
      * Changes the ClassLoader this Bundle uses when instantiating objects.
      *
      * @param loader An explicit ClassLoader to use when instantiating objects
@@ -168,32 +160,6 @@
     }
 
     /**
-     * @hide
-     */
-    @Override
-    public boolean isParcelled() {
-        return super.isParcelled();
-    }
-
-    /**
-     * Returns the number of mappings contained in this Bundle.
-     *
-     * @return the number of mappings as an int.
-     */
-    @Override
-    public int size() {
-        return super.size();
-    }
-
-    /**
-     * Returns true if the mapping of this Bundle is empty, false otherwise.
-     */
-    @Override
-    public boolean isEmpty() {
-        return super.isEmpty();
-    }
-
-    /**
      * Removes all elements from the mapping of this Bundle.
      */
     @Override
@@ -205,39 +171,6 @@
     }
 
     /**
-     * Returns true if the given key is contained in the mapping
-     * of this Bundle.
-     *
-     * @param key a String key
-     * @return true if the key is part of the mapping, false otherwise
-     */
-    @Override
-    public boolean containsKey(String key) {
-        return super.containsKey(key);
-    }
-
-    /**
-     * Returns the entry with the given key as an object.
-     *
-     * @param key a String key
-     * @return an Object, or null
-     */
-    @Override
-    public Object get(String key) {
-        return super.get(key);
-    }
-
-    /**
-     * Removes any entry with the given key from the mapping of this Bundle.
-     *
-     * @param key a String key
-     */
-    @Override
-    public void remove(String key) {
-        super.remove(key);
-    }
-
-    /**
      * Inserts all mappings from the given Bundle into this Bundle.
      *
      * @param bundle a Bundle
@@ -253,25 +186,6 @@
     }
 
     /**
-     * Inserts all mappings from the given PersistableBundle into this Bundle.
-     *
-     * @param bundle a PersistableBundle
-     */
-    public void putAll(PersistableBundle bundle) {
-        super.putAll(bundle);
-    }
-
-    /**
-     * Returns a Set containing the Strings used as keys in this Bundle.
-     *
-     * @return a Set of String keys
-     */
-    @Override
-    public Set<String> keySet() {
-        return super.keySet();
-    }
-
-    /**
      * Reports whether the bundle contains any parcelled file descriptors.
      */
     public boolean hasFileDescriptors() {
@@ -384,30 +298,6 @@
     }
 
     /**
-     * Inserts an int value into the mapping of this Bundle, replacing
-     * any existing value for the given key.
-     *
-     * @param key a String, or null
-     * @param value an int, or null
-     */
-    @Override
-    public void putInt(String key, int value) {
-        super.putInt(key, value);
-    }
-
-    /**
-     * Inserts a long value into the mapping of this Bundle, replacing
-     * any existing value for the given key.
-     *
-     * @param key a String, or null
-     * @param value a long
-     */
-    @Override
-    public void putLong(String key, long value) {
-        super.putLong(key, value);
-    }
-
-    /**
      * Inserts a float value into the mapping of this Bundle, replacing
      * any existing value for the given key.
      *
@@ -420,30 +310,6 @@
     }
 
     /**
-     * Inserts a double value into the mapping of this Bundle, replacing
-     * any existing value for the given key.
-     *
-     * @param key a String, or null
-     * @param value a double
-     */
-    @Override
-    public void putDouble(String key, double value) {
-        super.putDouble(key, value);
-    }
-
-    /**
-     * Inserts a String value into the mapping of this Bundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a String, or null
-     */
-    @Override
-    public void putString(String key, String value) {
-        super.putString(key, value);
-    }
-
-    /**
      * Inserts a CharSequence value into the mapping of this Bundle, replacing
      * any existing value for the given key.  Either key or value may be null.
      *
@@ -616,30 +482,6 @@
     }
 
     /**
-     * Inserts an int array value into the mapping of this Bundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value an int array object, or null
-     */
-    @Override
-    public void putIntArray(String key, int[] value) {
-        super.putIntArray(key, value);
-    }
-
-    /**
-     * Inserts a long array value into the mapping of this Bundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a long array object, or null
-     */
-    @Override
-    public void putLongArray(String key, long[] value) {
-        super.putLongArray(key, value);
-    }
-
-    /**
      * Inserts a float array value into the mapping of this Bundle, replacing
      * any existing value for the given key.  Either key or value may be null.
      *
@@ -652,30 +494,6 @@
     }
 
     /**
-     * Inserts a double array value into the mapping of this Bundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a double array object, or null
-     */
-    @Override
-    public void putDoubleArray(String key, double[] value) {
-        super.putDoubleArray(key, value);
-    }
-
-    /**
-     * Inserts a String array value into the mapping of this Bundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a String array object, or null
-     */
-    @Override
-    public void putStringArray(String key, String[] value) {
-        super.putStringArray(key, value);
-    }
-
-    /**
      * Inserts a CharSequence array value into the mapping of this Bundle, replacing
      * any existing value for the given key.  Either key or value may be null.
      *
@@ -700,17 +518,6 @@
     }
 
     /**
-     * Inserts a PersistableBundle value into the mapping of this Bundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a Bundle object, or null
-     */
-    public void putPersistableBundle(String key, PersistableBundle value) {
-        super.putPersistableBundle(key, value);
-    }
-
-    /**
      * Inserts an {@link IBinder} value into the mapping of this Bundle, replacing
      * any existing value for the given key.  Either key or value may be null.
      *
@@ -846,56 +653,6 @@
     }
 
     /**
-     * Returns the value associated with the given key, or 0 if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @return an int value
-     */
-    @Override
-    public int getInt(String key) {
-        return super.getInt(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or defaultValue if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @param defaultValue Value to return if key does not exist
-     * @return an int value
-     */
-    @Override
-    public int getInt(String key, int defaultValue) {
-        return super.getInt(key, defaultValue);
-    }
-
-    /**
-     * Returns the value associated with the given key, or 0L if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @return a long value
-     */
-    @Override
-    public long getLong(String key) {
-        return super.getLong(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or defaultValue if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @param defaultValue Value to return if key does not exist
-     * @return a long value
-     */
-    @Override
-    public long getLong(String key, long defaultValue) {
-        return super.getLong(key, defaultValue);
-    }
-
-    /**
      * Returns the value associated with the given key, or 0.0f if
      * no mapping of the desired type exists for the given key.
      *
@@ -921,58 +678,6 @@
     }
 
     /**
-     * Returns the value associated with the given key, or 0.0 if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @return a double value
-     */
-    @Override
-    public double getDouble(String key) {
-        return super.getDouble(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or defaultValue if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @param defaultValue Value to return if key does not exist
-     * @return a double value
-     */
-    @Override
-    public double getDouble(String key, double defaultValue) {
-        return super.getDouble(key, defaultValue);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
-     * @return a String value, or null
-     */
-    @Override
-    public String getString(String key) {
-        return super.getString(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or defaultValue if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String, or null
-     * @param defaultValue Value to return if key does not exist
-     * @return the String value associated with the given key, or defaultValue
-     *     if no valid String object is currently mapped to that key.
-     */
-    @Override
-    public String getString(String key, String defaultValue) {
-        return super.getString(key, defaultValue);
-    }
-
-    /**
      * Returns the value associated with the given key, or null if
      * no mapping of the desired type exists for the given key or a null
      * value is explicitly associated with the key.
@@ -1027,18 +732,6 @@
      * value is explicitly associated with the key.
      *
      * @param key a String, or null
-     * @return a PersistableBundle value, or null
-     */
-    public PersistableBundle getPersistableBundle(String key) {
-        return super.getPersistableBundle(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
      * @return a Parcelable value, or null
      */
     public <T extends Parcelable> T getParcelable(String key) {
@@ -1232,32 +925,6 @@
      * value is explicitly associated with the key.
      *
      * @param key a String, or null
-     * @return an int[] value, or null
-     */
-    @Override
-    public int[] getIntArray(String key) {
-        return super.getIntArray(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
-     * @return a long[] value, or null
-     */
-    @Override
-    public long[] getLongArray(String key) {
-        return super.getLongArray(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
      * @return a float[] value, or null
      */
     @Override
@@ -1271,32 +938,6 @@
      * value is explicitly associated with the key.
      *
      * @param key a String, or null
-     * @return a double[] value, or null
-     */
-    @Override
-    public double[] getDoubleArray(String key) {
-        return super.getDoubleArray(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
-     * @return a String[] value, or null
-     */
-    @Override
-    public String[] getStringArray(String key) {
-        return super.getStringArray(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
      * @return a CharSequence[] value, or null
      */
     @Override
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index cd8d515..c01f688 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -32,7 +32,8 @@
  * restored.
  *
  */
-public final class PersistableBundle extends CommonBundle implements XmlUtils.WriteMapCallback {
+public final class PersistableBundle extends BaseBundle implements Cloneable, Parcelable,
+        XmlUtils.WriteMapCallback {
     private static final String TAG_PERSISTABLEMAP = "pbundle_as_map";
     public static final PersistableBundle EMPTY;
     static final Parcel EMPTY_PARCEL;
@@ -40,7 +41,7 @@
     static {
         EMPTY = new PersistableBundle();
         EMPTY.mMap = ArrayMap.EMPTY;
-        EMPTY_PARCEL = CommonBundle.EMPTY_PARCEL;
+        EMPTY_PARCEL = BaseBundle.EMPTY_PARCEL;
     }
 
     /**
@@ -51,31 +52,6 @@
     }
 
     /**
-     * Constructs a PersistableBundle whose data is stored as a Parcel.  The data
-     * will be unparcelled on first contact, using the assigned ClassLoader.
-     *
-     * @param parcelledData a Parcel containing a PersistableBundle
-     */
-    PersistableBundle(Parcel parcelledData) {
-        super(parcelledData);
-    }
-
-    /* package */ PersistableBundle(Parcel parcelledData, int length) {
-        super(parcelledData, length);
-    }
-
-    /**
-     * Constructs a new, empty PersistableBundle that uses a specific ClassLoader for
-     * instantiating Parcelable and Serializable objects.
-     *
-     * @param loader An explicit ClassLoader to use when instantiating objects
-     * inside of the PersistableBundle.
-     */
-    public PersistableBundle(ClassLoader loader) {
-        super(loader);
-    }
-
-    /**
      * Constructs a new, empty PersistableBundle sized to hold the given number of
      * elements. The PersistableBundle will grow as needed.
      *
@@ -127,6 +103,10 @@
         }
     }
 
+    /* package */ PersistableBundle(Parcel parcelledData, int length) {
+        super(parcelledData, length);
+    }
+
     /**
      * Make a PersistableBundle for a single key/value pair.
      *
@@ -139,33 +119,6 @@
     }
 
     /**
-     * @hide
-     */
-    @Override
-    public String getPairValue() {
-        return super.getPairValue();
-    }
-
-    /**
-     * Changes the ClassLoader this PersistableBundle uses when instantiating objects.
-     *
-     * @param loader An explicit ClassLoader to use when instantiating objects
-     * inside of the PersistableBundle.
-     */
-    @Override
-    public void setClassLoader(ClassLoader loader) {
-        super.setClassLoader(loader);
-    }
-
-    /**
-     * Return the ClassLoader currently associated with this PersistableBundle.
-     */
-    @Override
-    public ClassLoader getClassLoader() {
-        return super.getClassLoader();
-    }
-
-    /**
      * Clones the current PersistableBundle. The internal map is cloned, but the keys and
      * values to which it refers are copied by reference.
      */
@@ -175,300 +128,15 @@
     }
 
     /**
-     * @hide
-     */
-    @Override
-    public boolean isParcelled() {
-        return super.isParcelled();
-    }
-
-    /**
-     * Returns the number of mappings contained in this PersistableBundle.
-     *
-     * @return the number of mappings as an int.
-     */
-    @Override
-    public int size() {
-        return super.size();
-    }
-
-    /**
-     * Returns true if the mapping of this PersistableBundle is empty, false otherwise.
-     */
-    @Override
-    public boolean isEmpty() {
-        return super.isEmpty();
-    }
-
-    /**
-     * Removes all elements from the mapping of this PersistableBundle.
-     */
-    @Override
-    public void clear() {
-        super.clear();
-    }
-
-    /**
-     * Returns true if the given key is contained in the mapping
-     * of this PersistableBundle.
-     *
-     * @param key a String key
-     * @return true if the key is part of the mapping, false otherwise
-     */
-    @Override
-    public boolean containsKey(String key) {
-        return super.containsKey(key);
-    }
-
-    /**
-     * Returns the entry with the given key as an object.
-     *
-     * @param key a String key
-     * @return an Object, or null
-     */
-    @Override
-    public Object get(String key) {
-        return super.get(key);
-    }
-
-    /**
-     * Removes any entry with the given key from the mapping of this PersistableBundle.
-     *
-     * @param key a String key
-     */
-    @Override
-    public void remove(String key) {
-        super.remove(key);
-    }
-
-    /**
-     * Inserts all mappings from the given PersistableBundle into this Bundle.
-     *
-     * @param bundle a PersistableBundle
-     */
-    @Override
-    public void putAll(PersistableBundle bundle) {
-        super.putAll(bundle);
-    }
-
-    /**
-     * Returns a Set containing the Strings used as keys in this PersistableBundle.
-     *
-     * @return a Set of String keys
-     */
-    @Override
-    public Set<String> keySet() {
-        return super.keySet();
-    }
-
-    /**
-     * Inserts an int value into the mapping of this PersistableBundle, replacing
-     * any existing value for the given key.
-     *
-     * @param key a String, or null
-     * @param value an int, or null
-     */
-    @Override
-    public void putInt(String key, int value) {
-        super.putInt(key, value);
-    }
-
-    /**
-     * Inserts a long value into the mapping of this PersistableBundle, replacing
-     * any existing value for the given key.
-     *
-     * @param key a String, or null
-     * @param value a long
-     */
-    @Override
-    public void putLong(String key, long value) {
-        super.putLong(key, value);
-    }
-
-    /**
-     * Inserts a double value into the mapping of this PersistableBundle, replacing
-     * any existing value for the given key.
-     *
-     * @param key a String, or null
-     * @param value a double
-     */
-    @Override
-    public void putDouble(String key, double value) {
-        super.putDouble(key, value);
-    }
-
-    /**
-     * Inserts a String value into the mapping of this PersistableBundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a String, or null
-     */
-    @Override
-    public void putString(String key, String value) {
-        super.putString(key, value);
-    }
-
-    /**
-     * Inserts an int array value into the mapping of this PersistableBundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value an int array object, or null
-     */
-    @Override
-    public void putIntArray(String key, int[] value) {
-        super.putIntArray(key, value);
-    }
-
-    /**
-     * Inserts a long array value into the mapping of this PersistableBundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a long array object, or null
-     */
-    @Override
-    public void putLongArray(String key, long[] value) {
-        super.putLongArray(key, value);
-    }
-
-    /**
-     * Inserts a double array value into the mapping of this PersistableBundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a double array object, or null
-     */
-    @Override
-    public void putDoubleArray(String key, double[] value) {
-        super.putDoubleArray(key, value);
-    }
-
-    /**
-     * Inserts a String array value into the mapping of this PersistableBundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a String array object, or null
-     */
-    @Override
-    public void putStringArray(String key, String[] value) {
-        super.putStringArray(key, value);
-    }
-
-    /**
      * Inserts a PersistableBundle value into the mapping of this Bundle, replacing
      * any existing value for the given key.  Either key or value may be null.
      *
      * @param key a String, or null
      * @param value a Bundle object, or null
      */
-    @Override
     public void putPersistableBundle(String key, PersistableBundle value) {
-        super.putPersistableBundle(key, value);
-    }
-
-    /**
-     * Returns the value associated with the given key, or 0 if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @return an int value
-     */
-    @Override
-    public int getInt(String key) {
-        return super.getInt(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or defaultValue if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @param defaultValue Value to return if key does not exist
-     * @return an int value
-     */
-    @Override
-    public int getInt(String key, int defaultValue) {
-        return super.getInt(key, defaultValue);
-    }
-
-    /**
-     * Returns the value associated with the given key, or 0L if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @return a long value
-     */
-    @Override
-    public long getLong(String key) {
-        return super.getLong(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or defaultValue if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @param defaultValue Value to return if key does not exist
-     * @return a long value
-     */
-    @Override
-    public long getLong(String key, long defaultValue) {
-        return super.getLong(key, defaultValue);
-    }
-
-    /**
-     * Returns the value associated with the given key, or 0.0 if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @return a double value
-     */
-    @Override
-    public double getDouble(String key) {
-        return super.getDouble(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or defaultValue if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @param defaultValue Value to return if key does not exist
-     * @return a double value
-     */
-    @Override
-    public double getDouble(String key, double defaultValue) {
-        return super.getDouble(key, defaultValue);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
-     * @return a String value, or null
-     */
-    @Override
-    public String getString(String key) {
-        return super.getString(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or defaultValue if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String, or null
-     * @param defaultValue Value to return if key does not exist
-     * @return the String value associated with the given key, or defaultValue
-     *     if no valid String object is currently mapped to that key.
-     */
-    @Override
-    public String getString(String key, String defaultValue) {
-        return super.getString(key, defaultValue);
+        unparcel();
+        mMap.put(key, value);
     }
 
     /**
@@ -479,61 +147,18 @@
      * @param key a String, or null
      * @return a Bundle value, or null
      */
-    @Override
     public PersistableBundle getPersistableBundle(String key) {
-        return super.getPersistableBundle(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
-     * @return an int[] value, or null
-     */
-    @Override
-    public int[] getIntArray(String key) {
-        return super.getIntArray(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
-     * @return a long[] value, or null
-     */
-    @Override
-    public long[] getLongArray(String key) {
-        return super.getLongArray(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
-     * @return a double[] value, or null
-     */
-    @Override
-    public double[] getDoubleArray(String key) {
-        return super.getDoubleArray(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
-     * @return a String[] value, or null
-     */
-    @Override
-    public String[] getStringArray(String key) {
-        return super.getStringArray(key);
+        unparcel();
+        Object o = mMap.get(key);
+        if (o == null) {
+            return null;
+        }
+        try {
+            return (PersistableBundle) o;
+        } catch (ClassCastException e) {
+            typeWarning(key, o, "Bundle", e);
+            return null;
+        }
     }
 
     public static final Parcelable.Creator<PersistableBundle> CREATOR =
@@ -549,38 +174,6 @@
                 }
             };
 
-    /**
-     * Report the nature of this Parcelable's contents
-     */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * Writes the PersistableBundle contents to a Parcel, typically in order for
-     * it to be passed through an IBinder connection.
-     * @param parcel The parcel to copy this bundle to.
-     */
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        final boolean oldAllowFds = parcel.pushAllowFds(false);
-        try {
-            super.writeToParcelInner(parcel, flags);
-        } finally {
-            parcel.restoreAllowFds(oldAllowFds);
-        }
-    }
-
-    /**
-     * Reads the Parcel contents into this PersistableBundle, typically in order for
-     * it to be passed through an IBinder connection.
-     * @param parcel The parcel to overwrite this bundle from.
-     */
-    public void readFromParcel(Parcel parcel) {
-        super.readFromParcelInner(parcel);
-    }
-
     /** @hide */
     @Override
     public void writeUnknownObject(Object v, String name, XmlSerializer out)
@@ -614,8 +207,29 @@
     }
 
     /**
-     * @hide
+     * Report the nature of this Parcelable's contents
      */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Writes the PersistableBundle contents to a Parcel, typically in order for
+     * it to be passed through an IBinder connection.
+     * @param parcel The parcel to copy this bundle to.
+     */
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        final boolean oldAllowFds = parcel.pushAllowFds(false);
+        try {
+            writeToParcelInner(parcel, flags);
+        } finally {
+            parcel.restoreAllowFds(oldAllowFds);
+        }
+    }
+
+    /** @hide */
     public static PersistableBundle restoreFromXml(XmlPullParser in) throws IOException,
             XmlPullParserException {
         final int outerDepth = in.getDepth();
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 5033bee..f35ca27 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -557,6 +557,28 @@
     }
 
     /**
+     * Sets the text color, size, style, hint color, and highlight color
+     * from the specified TextAppearance resource.
+     */
+    public void setTitleTextAppearance(Context context, int resId) {
+        mTitleTextAppearance = resId;
+        if (mTitleTextView != null) {
+            mTitleTextView.setTextAppearance(context, resId);
+        }
+    }
+
+    /**
+     * Sets the text color, size, style, hint color, and highlight color
+     * from the specified TextAppearance resource.
+     */
+    public void setSubtitleTextAppearance(Context context, int resId) {
+        mSubtitleTextAppearance = resId;
+        if (mSubtitleTextView != null) {
+            mSubtitleTextView.setTextAppearance(context, resId);
+        }
+    }
+
+    /**
      * Set the icon to use for the toolbar's navigation button.
      *
      * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index f6722a6..c0d1e88 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -183,6 +183,33 @@
     }
 
     /**
+     * Ensures that the argument int value is within the inclusive range.
+     *
+     * @param value a int value
+     * @param lower the lower endpoint of the inclusive range
+     * @param upper the upper endpoint of the inclusive range
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated int value
+     *
+     * @throws IllegalArgumentException if {@code value} was not within the range
+     */
+    public static int checkArgumentInRange(int value, int lower, int upper,
+            String valueName) {
+        if (value < lower) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
+        } else if (value > upper) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
+        }
+
+        return value;
+    }
+
+    /**
      * Ensures that the array is not {@code null}, and none if its elements are {@code null}.
      *
      * @param value an array of boxed objects
diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
index f90aaea..b8dc307 100644
--- a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
+++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
@@ -132,6 +132,16 @@
             mToolbar.setContentInsetsRelative(contentInsetStart, contentInsetEnd);
         }
 
+        final int titleTextStyle = a.getResourceId(R.styleable.ActionBar_titleTextStyle, 0);
+        if (titleTextStyle != 0) {
+            mToolbar.setTitleTextAppearance(mToolbar.getContext(), titleTextStyle);
+        }
+
+        final int subtitleTextStyle = a.getResourceId(R.styleable.ActionBar_subtitleTextStyle, 0);
+        if (subtitleTextStyle != 0) {
+            mToolbar.setSubtitleTextAppearance(mToolbar.getContext(), subtitleTextStyle);
+        }
+
         a.recycle();
 
         mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index c7b3fc9..f258063 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -744,12 +744,40 @@
         setParameters(keys, values);
     }
 
+    /**
+     * Sets the codec listener for actionable MediaCodec events.
+     * <p>Call this method with a null listener to stop receiving event notifications.
+     *
+     * @param cb The listener that will run.
+     *
+     * @hide
+     */
     public void setNotificationCallback(NotificationCallback cb) {
         mNotificationCallback = cb;
     }
 
-    public interface NotificationCallback {
-        void onCodecNotify(MediaCodec codec);
+    /**
+     * MediaCodec listener interface.  Used to notify the user of MediaCodec
+     * when there are available input and/or output buffers, a change in
+     * configuration or when a codec error happened.
+     *
+     * @hide
+     */
+    public static abstract class NotificationCallback {
+        /**
+         * Called on the listener to notify that there is an actionable
+         * MediaCodec event.  The application should call {@link #dequeueOutputBuffer}
+         * to receive the configuration change event, codec error or an
+         * available output buffer.  It should also call  {@link #dequeueInputBuffer}
+         * to receive any available input buffer.  For best performance, it
+         * is recommended to exhaust both available input and output buffers in
+         * the handling of a single callback, by calling the dequeue methods
+         * repeatedly with a zero timeout until {@link #INFO_TRY_AGAIN_LATER} is returned.
+         *
+         * @param codec the MediaCodec instance that has an actionable event.
+         *
+         */
+        public abstract void onCodecNotify(MediaCodec codec);
     }
 
     private void postEventFromNative(
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index ff73a10..5dc8e1b 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -23,6 +23,8 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import java.util.Set;
+
 /**
  * Contains metadata about an item, such as the title, artist, etc.
  */
@@ -301,6 +303,15 @@
     }
 
     /**
+     * Returns a Set containing the Strings used as keys in this metadata.
+     *
+     * @return a Set of String keys
+     */
+    public Set<String> keySet() {
+        return mBundle.keySet();
+    }
+
+    /**
      * Helper for getting the String key used by {@link MediaMetadata} from the
      * integer key that {@link MediaMetadataEditor} uses.
      *
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 26ae3cc..0caea5f 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -27,7 +27,6 @@
 import android.media.session.MediaSessionLegacyHelper;
 import android.media.session.PlaybackState;
 import android.media.session.MediaSession;
-import android.media.session.TransportPerformer;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -584,7 +583,7 @@
 
                 // USE_SESSIONS
                 if (mSession != null && mMetadataBuilder != null) {
-                    mSession.getTransportPerformer().setMetadata(mMetadataBuilder.build());
+                    mSession.setMetadata(mMetadataBuilder.build());
                 }
                 mApplied = true;
             }
@@ -702,7 +701,7 @@
                     mSessionPlaybackState.setState(pbState, hasPosition ?
                             mPlaybackPositionMs : PlaybackState.PLAYBACK_POSITION_UNKNOWN,
                             playbackSpeed);
-                    mSession.getTransportPerformer().setPlaybackState(mSessionPlaybackState);
+                    mSession.setPlaybackState(mSessionPlaybackState);
                 }
             }
         }
@@ -789,7 +788,7 @@
             if (mSession != null) {
                 mSessionPlaybackState.setActions(PlaybackState
                         .getActionsFromRccControlFlags(transportControlFlags));
-                mSession.getTransportPerformer().setPlaybackState(mSessionPlaybackState);
+                mSession.setPlaybackState(mSessionPlaybackState);
             }
         }
     }
@@ -1317,7 +1316,8 @@
     }
 
     // USE_SESSIONS
-    private TransportPerformer.Listener mTransportListener = new TransportPerformer.Listener() {
+    private MediaSession.TransportControlsCallback mTransportListener
+            = new MediaSession.TransportControlsCallback() {
 
         @Override
         public void onSeekTo(long pos) {
@@ -1325,7 +1325,7 @@
         }
 
         @Override
-        public void onRate(Rating rating) {
+        public void onSetRating(Rating rating) {
             if ((mTransportControlFlags & FLAG_KEY_MEDIA_RATING) != 0) {
                 if (mEventHandler != null) {
                     mEventHandler.sendMessage(mEventHandler.obtainMessage(
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 5ddb6db..9ce0692 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -30,7 +30,7 @@
  */
 interface ISessionController {
     void sendCommand(String command, in Bundle extras, in ResultReceiver cb);
-    void sendMediaButton(in KeyEvent mediaButton);
+    boolean sendMediaButton(in KeyEvent mediaButton);
     void registerCallbackListener(in ISessionControllerCallback cb);
     void unregisterCallbackListener(in ISessionControllerCallback cb);
     boolean isTransportControlEnabled();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 642ac2f..caff1ad 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -17,6 +17,7 @@
 package android.media.session;
 
 import android.media.MediaMetadata;
+import android.media.Rating;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -45,8 +46,8 @@
     private static final String TAG = "SessionController";
 
     private static final int MSG_EVENT = 1;
-    private static final int MESSAGE_PLAYBACK_STATE = 2;
-    private static final int MESSAGE_METADATA = 3;
+    private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
+    private static final int MSG_UPDATE_METADATA = 3;
     private static final int MSG_ROUTE = 4;
 
     private final ISessionController mSessionBinder;
@@ -57,10 +58,11 @@
 
     private boolean mCbRegistered = false;
 
-    private TransportController mTransportController;
+    private TransportControls mTransportController;
 
     private MediaController(ISessionController sessionBinder) {
         mSessionBinder = sessionBinder;
+        mTransportController = new TransportControls();
     }
 
     /**
@@ -70,9 +72,6 @@
         MediaController controller = new MediaController(sessionBinder);
         try {
             controller.mSessionBinder.registerCallbackListener(controller.mCbStub);
-            if (controller.mSessionBinder.isTransportControlEnabled()) {
-                controller.mTransportController = new TransportController(sessionBinder);
-            }
         } catch (RemoteException e) {
             Log.wtf(TAG, "MediaController created with expired token", e);
             controller = null;
@@ -93,33 +92,84 @@
     }
 
     /**
-     * Get a TransportController if the session supports it. If it is not
-     * supported null will be returned.
+     * Get a {@link TransportControls} instance for this session.
      *
-     * @return A TransportController or null
+     * @return A controls instance
      */
-    public TransportController getTransportController() {
+    public TransportControls getTransportControls() {
         return mTransportController;
     }
 
     /**
-     * Send the specified media button to the session. Only media keys can be
-     * sent using this method.
+     * Send the specified media button event to the session. Only media keys can
+     * be sent by this method, other keys will be ignored.
      *
-     * @param keycode The media button keycode, such as
-     *            {@link KeyEvent#KEYCODE_MEDIA_PLAY}.
+     * @param keyEvent The media button event to dispatch.
+     * @return true if the event was sent to the session, false otherwise.
      */
-    public void sendMediaButton(int keycode) {
-        if (!KeyEvent.isMediaKey(keycode)) {
-            throw new IllegalArgumentException("May only send media buttons through "
-                    + "sendMediaButton");
+    public boolean dispatchMediaButtonEvent(KeyEvent keyEvent) {
+        if (keyEvent == null) {
+            throw new IllegalArgumentException("KeyEvent may not be null");
         }
-        // TODO do something better than key down/up events
-        KeyEvent event = new KeyEvent(KeyEvent.ACTION_UP, keycode);
+        if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) {
+            return false;
+        }
         try {
-            mSessionBinder.sendMediaButton(event);
+            return mSessionBinder.sendMediaButton(keyEvent);
         } catch (RemoteException e) {
-            Log.d(TAG, "Dead object in sendMediaButton", e);
+            // System is dead. =(
+        }
+        return false;
+    }
+
+    /**
+     * Get the current playback state for this session.
+     *
+     * @return The current PlaybackState or null
+     */
+    public PlaybackState getPlaybackState() {
+        try {
+            return mSessionBinder.getPlaybackState();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getPlaybackState.", e);
+            return null;
+        }
+    }
+
+    /**
+     * Get the current metadata for this session.
+     *
+     * @return The current MediaMetadata or null.
+     */
+    public MediaMetadata getMetadata() {
+        try {
+            return mSessionBinder.getMetadata();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getMetadata.", e);
+            return null;
+        }
+    }
+
+    /**
+     * Get the rating type supported by the session. One of:
+     * <ul>
+     * <li>{@link Rating#RATING_NONE}</li>
+     * <li>{@link Rating#RATING_HEART}</li>
+     * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
+     * <li>{@link Rating#RATING_3_STARS}</li>
+     * <li>{@link Rating#RATING_4_STARS}</li>
+     * <li>{@link Rating#RATING_5_STARS}</li>
+     * <li>{@link Rating#RATING_PERCENTAGE}</li>
+     * </ul>
+     *
+     * @return The supported rating type
+     */
+    public int getRatingType() {
+        try {
+            return mSessionBinder.getRatingType();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getRatingType.", e);
+            return Rating.RATING_NONE;
         }
     }
 
@@ -171,7 +221,7 @@
      * @param params Any parameters to include with the command
      * @param cb The callback to receive the result on
      */
-    public void sendCommand(String command, Bundle params, ResultReceiver cb) {
+    public void sendControlCommand(String command, Bundle params, ResultReceiver cb) {
         if (TextUtils.isEmpty(command)) {
             throw new IllegalArgumentException("command cannot be null or empty");
         }
@@ -254,18 +304,10 @@
         return null;
     }
 
-    private void postEvent(String event, Bundle extras) {
+    private final void postMessage(int what, Object obj, Bundle data) {
         synchronized (mLock) {
             for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-                mCallbacks.get(i).post(MSG_EVENT, event, extras);
-            }
-        }
-    }
-
-    private void postRouteChanged(RouteInfo route) {
-        synchronized (mLock) {
-            for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-                mCallbacks.get(i).post(MSG_ROUTE, route, null);
+                mCallbacks.get(i).post(what, obj, data);
             }
         }
     }
@@ -282,7 +324,7 @@
          *
          * @param event
          */
-        public void onEvent(String event, Bundle extras) {
+        public void onSessionEvent(String event, Bundle extras) {
         }
 
         /**
@@ -293,6 +335,143 @@
          */
         public void onRouteChanged(RouteInfo route) {
         }
+
+        /**
+         * Override to handle changes in playback state.
+         *
+         * @param state The new playback state of the session
+         */
+        public void onPlaybackStateChanged(PlaybackState state) {
+        }
+
+        /**
+         * Override to handle changes to the current metadata.
+         *
+         * @see MediaMetadata
+         * @param metadata The current metadata for the session or null
+         */
+        public void onMetadataChanged(MediaMetadata metadata) {
+        }
+    }
+
+    /**
+     * Interface for controlling media playback on a session. This allows an app
+     * to send media transport commands to the session.
+     */
+    public final class TransportControls {
+        private static final String TAG = "TransportController";
+
+        private TransportControls() {
+        }
+
+        /**
+         * Request that the player start its playback at its current position.
+         */
+        public void play() {
+            try {
+                mSessionBinder.play();
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling play.", e);
+            }
+        }
+
+        /**
+         * Request that the player pause its playback and stay at its current
+         * position.
+         */
+        public void pause() {
+            try {
+                mSessionBinder.pause();
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling pause.", e);
+            }
+        }
+
+        /**
+         * Request that the player stop its playback; it may clear its state in
+         * whatever way is appropriate.
+         */
+        public void stop() {
+            try {
+                mSessionBinder.stop();
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling stop.", e);
+            }
+        }
+
+        /**
+         * Move to a new location in the media stream.
+         *
+         * @param pos Position to move to, in milliseconds.
+         */
+        public void seekTo(long pos) {
+            try {
+                mSessionBinder.seekTo(pos);
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling seekTo.", e);
+            }
+        }
+
+        /**
+         * Start fast forwarding. If playback is already fast forwarding this
+         * may increase the rate.
+         */
+        public void fastForward() {
+            try {
+                mSessionBinder.fastForward();
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling fastForward.", e);
+            }
+        }
+
+        /**
+         * Skip to the next item.
+         */
+        public void skipToNext() {
+            try {
+                mSessionBinder.next();
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling next.", e);
+            }
+        }
+
+        /**
+         * Start rewinding. If playback is already rewinding this may increase
+         * the rate.
+         */
+        public void rewind() {
+            try {
+                mSessionBinder.rewind();
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling rewind.", e);
+            }
+        }
+
+        /**
+         * Skip to the previous item.
+         */
+        public void skipToPrevious() {
+            try {
+                mSessionBinder.previous();
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling previous.", e);
+            }
+        }
+
+        /**
+         * Rate the current content. This will cause the rating to be set for
+         * the current user. The Rating type must match the type returned by
+         * {@link #getRatingType()}.
+         *
+         * @param rating The rating to set for the current content
+         */
+        public void setRating(Rating rating) {
+            try {
+                mSessionBinder.rate(rating);
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling rate.", e);
+            }
+        }
     }
 
     private final static class CallbackStub extends ISessionControllerCallback.Stub {
@@ -306,7 +485,7 @@
         public void onEvent(String event, Bundle extras) {
             MediaController controller = mController.get();
             if (controller != null) {
-                controller.postEvent(event, extras);
+                controller.postMessage(MSG_EVENT, event, extras);
             }
         }
 
@@ -314,7 +493,7 @@
         public void onRouteChanged(RouteInfo route) {
             MediaController controller = mController.get();
             if (controller != null) {
-                controller.postRouteChanged(route);
+                controller.postMessage(MSG_ROUTE, route, null);
             }
         }
 
@@ -322,10 +501,7 @@
         public void onPlaybackStateChanged(PlaybackState state) {
             MediaController controller = mController.get();
             if (controller != null) {
-                TransportController tc = controller.getTransportController();
-                if (tc != null) {
-                    tc.postPlaybackStateChanged(state);
-                }
+                controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null);
             }
         }
 
@@ -333,10 +509,7 @@
         public void onMetadataChanged(MediaMetadata metadata) {
             MediaController controller = mController.get();
             if (controller != null) {
-                TransportController tc = controller.getTransportController();
-                if (tc != null) {
-                    tc.postMetadataChanged(metadata);
-                }
+                controller.postMessage(MSG_UPDATE_METADATA, metadata, null);
             }
         }
 
@@ -354,10 +527,17 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_EVENT:
-                    mCallback.onEvent((String) msg.obj, msg.getData());
+                    mCallback.onSessionEvent((String) msg.obj, msg.getData());
                     break;
                 case MSG_ROUTE:
                     mCallback.onRouteChanged((RouteInfo) msg.obj);
+                    break;
+                case MSG_UPDATE_PLAYBACK_STATE:
+                    mCallback.onPlaybackStateChanged((PlaybackState) msg.obj);
+                    break;
+                case MSG_UPDATE_METADATA:
+                    mCallback.onMetadataChanged((MediaMetadata) msg.obj);
+                    break;
             }
         }
 
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 539dc3c..90ccf68 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -16,10 +16,12 @@
 
 package android.media.session;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.Intent;
-import android.media.AudioAttributes;
 import android.media.AudioManager;
+import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.session.ISessionController;
 import android.media.session.ISession;
@@ -49,15 +51,13 @@
  * <p>
  * A MediaSession is created by calling
  * {@link MediaSessionManager#createSession(String)}. Once a session is created
- * apps that have the MEDIA_CONTENT_CONTROL permission can interact with the
- * session through
- * {@link MediaSessionManager#getActiveSessions(android.content.ComponentName)}.
- * The owner of the session may also use {@link #getSessionToken()} to allow
- * apps without this permission to create a {@link MediaController} to interact
- * with this session.
+ * the owner of the session may use {@link #getSessionToken()} to allow apps to
+ * create a {@link MediaController} to interact with this session.
  * <p>
- * To receive commands, media keys, and other events a Callback must be set with
- * {@link #addCallback(Callback)}.
+ * To receive commands, media keys, and other events a {@link Callback} must be
+ * set with {@link #addCallback(Callback)}. To receive transport control
+ * commands a {@link TransportControlsCallback} must be set with
+ * {@link #addTransportControlsCallback}.
  * <p>
  * When an app is finished performing playback it must call {@link #release()}
  * to clean up the session and notify any controllers.
@@ -74,9 +74,10 @@
     public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1 << 0;
 
     /**
-     * Set this flag on the session to indicate that it handles commands through
-     * the {@link TransportPerformer}. The performer can be retrieved by calling
-     * {@link #getTransportPerformer()}.
+     * Set this flag on the session to indicate that it handles transport
+     * control commands through a {@link TransportControlsCallback}. The
+     * callback can be retrieved by calling
+     * {@link #addTransportControlsCallback}.
      */
     public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
 
@@ -123,12 +124,6 @@
      */
     public static final int DISCONNECT_REASON_SESSION_DESTROYED = 5;
 
-    private static final int MSG_MEDIA_BUTTON = 1;
-    private static final int MSG_COMMAND = 2;
-    private static final int MSG_ROUTE_CHANGE = 3;
-    private static final int MSG_ROUTE_CONNECTED = 4;
-    private static final int MSG_ROUTE_DISCONNECTED = 5;
-
     private static final String KEY_COMMAND = "command";
     private static final String KEY_EXTRAS = "extras";
     private static final String KEY_CALLBACK = "callback";
@@ -139,12 +134,14 @@
     private final ISession mBinder;
     private final CallbackStub mCbStub;
 
-    private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
+    private final ArrayList<CallbackMessageHandler> mCallbacks
+            = new ArrayList<CallbackMessageHandler>();
+    private final ArrayList<TransportMessageHandler> mTransportCallbacks
+            = new ArrayList<TransportMessageHandler>();
     // TODO route interfaces
     private final ArrayMap<String, RouteInterface.EventListener> mInterfaceListeners
             = new ArrayMap<String, RouteInterface.EventListener>();
 
-    private TransportPerformer mPerformer;
     private Route mRoute;
 
     private boolean mActive = false;;
@@ -162,11 +159,12 @@
             throw new RuntimeException("Dead object in MediaSessionController constructor: ", e);
         }
         mSessionToken = new MediaSessionToken(controllerBinder);
-        mPerformer = new TransportPerformer(mBinder);
     }
 
     /**
-     * Set the callback to receive updates on.
+     * Add a callback to receive updates on for the MediaSession. This includes
+     * media button and volume events. The caller's thread will be used to post
+     * events.
      *
      * @param callback The callback object
      */
@@ -193,7 +191,8 @@
             if (handler == null) {
                 handler = new Handler();
             }
-            MessageHandler msgHandler = new MessageHandler(handler.getLooper(), callback);
+            CallbackMessageHandler msgHandler = new CallbackMessageHandler(handler.getLooper(),
+                    callback);
             mCallbacks.add(msgHandler);
         }
     }
@@ -210,18 +209,6 @@
     }
 
     /**
-     * Retrieves the {@link TransportPerformer} for this session. To receive
-     * commands through the performer you must also set the
-     * {@link #FLAG_HANDLES_TRANSPORT_CONTROLS} flag using
-     * {@link #setFlags(int)}.
-     *
-     * @return The performer associated with this session.
-     */
-    public TransportPerformer getTransportPerformer() {
-        return mPerformer;
-    }
-
-    /**
      * Set an intent for launching UI for this Session. This can be used as a
      * quick link to an ongoing media screen.
      *
@@ -246,7 +233,7 @@
 
     /**
      * Set the stream this session is playing on. This will affect the system's
-     * volume handling for this session. If {@link #useRemotePlayback} was
+     * volume handling for this session. If {@link #setPlaybackToRemote} was
      * previously called it will stop receiving volume commands and the system
      * will begin sending volume changes to the appropriate stream.
      * <p>
@@ -254,21 +241,21 @@
      *
      * @param stream The {@link AudioManager} stream this session is playing on.
      */
-    public void useLocalPlayback(int stream) {
+    public void setPlaybackToLocal(int stream) {
         // TODO
     }
 
     /**
      * Configure this session to use remote volume handling. This must be called
      * to receive volume button events, otherwise the system will adjust the
-     * current stream volume for this session. If {@link #useLocalPlayback} was
-     * previously called that stream will stop receiving volume changes for this
-     * session.
+     * current stream volume for this session. If {@link #setPlaybackToLocal}
+     * was previously called that stream will stop receiving volume changes for
+     * this session.
      *
      * @param volumeProvider The provider that will handle volume changes. May
      *            not be null.
      */
-    public void useRemotePlayback(RemoteVolumeProvider volumeProvider) {
+    public void setPlaybackToRemote(RemoteVolumeProvider volumeProvider) {
         if (volumeProvider == null) {
             throw new IllegalArgumentException("volumeProvider may not be null!");
         }
@@ -312,7 +299,7 @@
      * @param event The name of the event to send
      * @param extras Any extras included with the event
      */
-    public void sendEvent(String event, Bundle extras) {
+    public void sendSessionEvent(String event, Bundle extras) {
         if (TextUtils.isEmpty(event)) {
             throw new IllegalArgumentException("event cannot be null or empty");
         }
@@ -432,12 +419,160 @@
         return true;
     }
 
-    private MessageHandler getHandlerForCallbackLocked(Callback cb) {
+    /**
+     * Add a callback to receive transport controls on, such as play, rewind, or
+     * fast forward.
+     *
+     * @param callback The callback object
+     */
+    public void addTransportControlsCallback(@NonNull TransportControlsCallback callback) {
+        addTransportControlsCallback(callback, null);
+    }
+
+    /**
+     * Add a callback to receive transport controls on, such as play, rewind, or
+     * fast forward. The updates will be posted to the specified handler. If no
+     * handler is provided they will be posted to the caller's thread.
+     *
+     * @param callback The callback to receive updates on
+     * @param handler The handler to post the updates on
+     */
+    public void addTransportControlsCallback(@NonNull TransportControlsCallback callback,
+            @Nullable Handler handler) {
+        if (callback == null) {
+            throw new IllegalArgumentException("Callback cannot be null");
+        }
+        synchronized (mLock) {
+            if (getTransportControlsHandlerForCallbackLocked(callback) != null) {
+                Log.w(TAG, "Callback is already added, ignoring");
+                return;
+            }
+            if (handler == null) {
+                handler = new Handler();
+            }
+            TransportMessageHandler msgHandler = new TransportMessageHandler(handler.getLooper(),
+                    callback);
+            mTransportCallbacks.add(msgHandler);
+        }
+    }
+
+    /**
+     * Stop receiving transport controls on the specified callback. If an update
+     * has already been posted you may still receive it after this call returns.
+     *
+     * @param callback The callback to stop receiving updates on
+     */
+    public void removeTransportControlsCallback(@NonNull TransportControlsCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("Callback cannot be null");
+        }
+        synchronized (mLock) {
+            removeTransportControlsCallbackLocked(callback);
+        }
+    }
+
+    /**
+     * Update the current playback state.
+     *
+     * @param state The current state of playback
+     */
+    public void setPlaybackState(PlaybackState state) {
+        try {
+            mBinder.setPlaybackState(state);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
+        }
+    }
+
+    /**
+     * Update the current metadata. New metadata can be created using
+     * {@link android.media.MediaMetadata.Builder}.
+     *
+     * @param metadata The new metadata
+     */
+    public void setMetadata(MediaMetadata metadata) {
+        try {
+            mBinder.setMetadata(metadata);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
+        }
+    }
+
+    private void dispatchPlay() {
+        postToTransportCallbacks(TransportMessageHandler.MSG_PLAY);
+    }
+
+    private void dispatchPause() {
+        postToTransportCallbacks(TransportMessageHandler.MSG_PAUSE);
+    }
+
+    private void dispatchStop() {
+        postToTransportCallbacks(TransportMessageHandler.MSG_STOP);
+    }
+
+    private void dispatchNext() {
+        postToTransportCallbacks(TransportMessageHandler.MSG_NEXT);
+    }
+
+    private void dispatchPrevious() {
+        postToTransportCallbacks(TransportMessageHandler.MSG_PREVIOUS);
+    }
+
+    private void dispatchFastForward() {
+        postToTransportCallbacks(TransportMessageHandler.MSG_FAST_FORWARD);
+    }
+
+    private void dispatchRewind() {
+        postToTransportCallbacks(TransportMessageHandler.MSG_REWIND);
+    }
+
+    private void dispatchSeekTo(long pos) {
+        postToTransportCallbacks(TransportMessageHandler.MSG_SEEK_TO, pos);
+    }
+
+    private void dispatchRate(Rating rating) {
+        postToTransportCallbacks(TransportMessageHandler.MSG_RATE, rating);
+    }
+
+    private TransportMessageHandler getTransportControlsHandlerForCallbackLocked(
+            TransportControlsCallback callback) {
+        for (int i = mTransportCallbacks.size() - 1; i >= 0; i--) {
+            TransportMessageHandler handler = mTransportCallbacks.get(i);
+            if (callback == handler.mCallback) {
+                return handler;
+            }
+        }
+        return null;
+    }
+
+    private boolean removeTransportControlsCallbackLocked(TransportControlsCallback callback) {
+        for (int i = mTransportCallbacks.size() - 1; i >= 0; i--) {
+            if (callback == mTransportCallbacks.get(i).mCallback) {
+                mTransportCallbacks.remove(i);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void postToTransportCallbacks(int what, Object obj) {
+        synchronized (mLock) {
+            for (int i = mTransportCallbacks.size() - 1; i >= 0; i--) {
+                mTransportCallbacks.get(i).post(what, obj);
+            }
+        }
+    }
+
+    private void postToTransportCallbacks(int what) {
+        postToTransportCallbacks(what, null);
+    }
+
+    private CallbackMessageHandler getHandlerForCallbackLocked(Callback cb) {
         if (cb == null) {
             throw new IllegalArgumentException("Callback cannot be null");
         }
         for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-            MessageHandler handler = mCallbacks.get(i);
+            CallbackMessageHandler handler = mCallbacks.get(i);
             if (cb == handler.mCallback) {
                 return handler;
             }
@@ -450,7 +585,7 @@
             throw new IllegalArgumentException("Callback cannot be null");
         }
         for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-            MessageHandler handler = mCallbacks.get(i);
+            CallbackMessageHandler handler = mCallbacks.get(i);
             if (cb == handler.mCallback) {
                 mCallbacks.remove(i);
                 return true;
@@ -463,7 +598,7 @@
         Command cmd = new Command(command, extras, resultCb);
         synchronized (mLock) {
             for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-                mCallbacks.get(i).post(MSG_COMMAND, cmd);
+                mCallbacks.get(i).post(CallbackMessageHandler.MSG_COMMAND, cmd);
             }
         }
     }
@@ -471,7 +606,7 @@
     private void postMediaButton(Intent mediaButtonIntent) {
         synchronized (mLock) {
             for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-                mCallbacks.get(i).post(MSG_MEDIA_BUTTON, mediaButtonIntent);
+                mCallbacks.get(i).post(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent);
             }
         }
     }
@@ -479,7 +614,7 @@
     private void postRequestRouteChange(RouteInfo route) {
         synchronized (mLock) {
             for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-                mCallbacks.get(i).post(MSG_ROUTE_CHANGE, route);
+                mCallbacks.get(i).post(CallbackMessageHandler.MSG_ROUTE_CHANGE, route);
             }
         }
     }
@@ -488,7 +623,7 @@
         synchronized (mLock) {
             mRoute = new Route(route, options, this);
             for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-                mCallbacks.get(i).post(MSG_ROUTE_CONNECTED, mRoute);
+                mCallbacks.get(i).post(CallbackMessageHandler.MSG_ROUTE_CONNECTED, mRoute);
             }
         }
     }
@@ -497,16 +632,16 @@
         synchronized (mLock) {
             if (mRoute != null && TextUtils.equals(mRoute.getRouteInfo().getId(), route.getId())) {
                 for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-                    mCallbacks.get(i).post(MSG_ROUTE_DISCONNECTED, mRoute, reason);
+                    mCallbacks.get(i).post(CallbackMessageHandler.MSG_ROUTE_DISCONNECTED, mRoute,
+                            reason);
                 }
             }
         }
     }
 
     /**
-     * Receives commands or updates from controllers and routes. An app can
-     * specify what commands and buttons it supports by setting them on the
-     * MediaSession.
+     * Receives generic commands or updates from controllers and the system.
+     * Callbacks may be registered using {@link #addCallback}.
      */
     public abstract static class Callback {
 
@@ -525,7 +660,7 @@
          * @param mediaButtonIntent an intent containing the KeyEvent as an
          *            extra
          */
-        public void onMediaButton(Intent mediaButtonIntent) {
+        public void onMediaButtonEvent(Intent mediaButtonIntent) {
         }
 
         /**
@@ -536,7 +671,7 @@
          * @param command
          * @param extras optional
          */
-        public void onCommand(String command, Bundle extras, ResultReceiver cb) {
+        public void onControlCommand(String command, Bundle extras, ResultReceiver cb) {
         }
 
         /**
@@ -582,6 +717,82 @@
     }
 
     /**
+     * Receives transport control commands. Callbacks may be registered using
+     * {@link #addTransportControlsCallback}.
+     */
+    public static abstract class TransportControlsCallback {
+
+        /**
+         * Override to handle requests to begin playback.
+         */
+        public void onPlay() {
+        }
+
+        /**
+         * Override to handle requests to pause playback.
+         */
+        public void onPause() {
+        }
+
+        /**
+         * Override to handle requests to skip to the next media item.
+         */
+        public void onSkipToNext() {
+        }
+
+        /**
+         * Override to handle requests to skip to the previous media item.
+         */
+        public void onSkipToPrevious() {
+        }
+
+        /**
+         * Override to handle requests to fast forward.
+         */
+        public void onFastForward() {
+        }
+
+        /**
+         * Override to handle requests to rewind.
+         */
+        public void onRewind() {
+        }
+
+        /**
+         * Override to handle requests to stop playback.
+         */
+        public void onStop() {
+        }
+
+        /**
+         * Override to handle requests to seek to a specific position in ms.
+         *
+         * @param pos New position to move to, in milliseconds.
+         */
+        public void onSeekTo(long pos) {
+        }
+
+        /**
+         * Override to handle the item being rated.
+         *
+         * @param rating
+         */
+        public void onSetRating(Rating rating) {
+        }
+
+        /**
+         * Report that audio focus has changed on the app. This only happens if
+         * you have indicated you have started playing with
+         * {@link #setPlaybackState}.
+         *
+         * @param focusChange The type of focus change, TBD.
+         * @hide
+         */
+        public void onRouteFocusChange(int focusChange) {
+        }
+    }
+
+    /**
      * @hide
      */
     public static class CallbackStub extends ISessionCallback.Stub {
@@ -643,10 +854,7 @@
         public void onPlay() throws RemoteException {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                TransportPerformer tp = session.getTransportPerformer();
-                if (tp != null) {
-                    tp.onPlay();
-                }
+                session.dispatchPlay();
             }
         }
 
@@ -654,10 +862,7 @@
         public void onPause() throws RemoteException {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                TransportPerformer tp = session.getTransportPerformer();
-                if (tp != null) {
-                    tp.onPause();
-                }
+                session.dispatchPause();
             }
         }
 
@@ -665,10 +870,7 @@
         public void onStop() throws RemoteException {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                TransportPerformer tp = session.getTransportPerformer();
-                if (tp != null) {
-                    tp.onStop();
-                }
+                session.dispatchStop();
             }
         }
 
@@ -676,10 +878,7 @@
         public void onNext() throws RemoteException {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                TransportPerformer tp = session.getTransportPerformer();
-                if (tp != null) {
-                    tp.onNext();
-                }
+                session.dispatchNext();
             }
         }
 
@@ -687,10 +886,7 @@
         public void onPrevious() throws RemoteException {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                TransportPerformer tp = session.getTransportPerformer();
-                if (tp != null) {
-                    tp.onPrevious();
-                }
+                session.dispatchPrevious();
             }
         }
 
@@ -698,10 +894,7 @@
         public void onFastForward() throws RemoteException {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                TransportPerformer tp = session.getTransportPerformer();
-                if (tp != null) {
-                    tp.onFastForward();
-                }
+                session.dispatchFastForward();
             }
         }
 
@@ -709,10 +902,7 @@
         public void onRewind() throws RemoteException {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                TransportPerformer tp = session.getTransportPerformer();
-                if (tp != null) {
-                    tp.onRewind();
-                }
+                session.dispatchRewind();
             }
         }
 
@@ -720,10 +910,7 @@
         public void onSeekTo(long pos) throws RemoteException {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                TransportPerformer tp = session.getTransportPerformer();
-                if (tp != null) {
-                    tp.onSeekTo(pos);
-                }
+                session.dispatchSeekTo(pos);
             }
         }
 
@@ -731,10 +918,7 @@
         public void onRate(Rating rating) throws RemoteException {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                TransportPerformer tp = session.getTransportPerformer();
-                if (tp != null) {
-                    tp.onRate(rating);
-                }
+                session.dispatchRate(rating);
             }
         }
 
@@ -760,10 +944,16 @@
 
     }
 
-    private class MessageHandler extends Handler {
+    private class CallbackMessageHandler extends Handler {
+        private static final int MSG_MEDIA_BUTTON = 1;
+        private static final int MSG_COMMAND = 2;
+        private static final int MSG_ROUTE_CHANGE = 3;
+        private static final int MSG_ROUTE_CONNECTED = 4;
+        private static final int MSG_ROUTE_DISCONNECTED = 5;
+
         private MediaSession.Callback mCallback;
 
-        public MessageHandler(Looper looper, MediaSession.Callback callback) {
+        public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
             super(looper, null, true);
             mCallback = callback;
         }
@@ -776,11 +966,11 @@
                 }
                 switch (msg.what) {
                     case MSG_MEDIA_BUTTON:
-                        mCallback.onMediaButton((Intent) msg.obj);
+                        mCallback.onMediaButtonEvent((Intent) msg.obj);
                         break;
                     case MSG_COMMAND:
                         Command cmd = (Command) msg.obj;
-                        mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
+                        mCallback.onControlCommand(cmd.command, cmd.extras, cmd.stub);
                         break;
                     case MSG_ROUTE_CHANGE:
                         mCallback.onRequestRouteChange((RouteInfo) msg.obj);
@@ -815,4 +1005,64 @@
             this.stub = stub;
         }
     }
+
+    private class TransportMessageHandler extends Handler {
+        private static final int MSG_PLAY = 1;
+        private static final int MSG_PAUSE = 2;
+        private static final int MSG_STOP = 3;
+        private static final int MSG_NEXT = 4;
+        private static final int MSG_PREVIOUS = 5;
+        private static final int MSG_FAST_FORWARD = 6;
+        private static final int MSG_REWIND = 7;
+        private static final int MSG_SEEK_TO = 8;
+        private static final int MSG_RATE = 9;
+
+        private TransportControlsCallback mCallback;
+
+        public TransportMessageHandler(Looper looper, TransportControlsCallback cb) {
+            super(looper);
+            mCallback = cb;
+        }
+
+        public void post(int what, Object obj) {
+            obtainMessage(what, obj).sendToTarget();
+        }
+
+        public void post(int what) {
+            post(what, null);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_PLAY:
+                    mCallback.onPlay();
+                    break;
+                case MSG_PAUSE:
+                    mCallback.onPause();
+                    break;
+                case MSG_STOP:
+                    mCallback.onStop();
+                    break;
+                case MSG_NEXT:
+                    mCallback.onSkipToNext();
+                    break;
+                case MSG_PREVIOUS:
+                    mCallback.onSkipToPrevious();
+                    break;
+                case MSG_FAST_FORWARD:
+                    mCallback.onFastForward();
+                    break;
+                case MSG_REWIND:
+                    mCallback.onRewind();
+                    break;
+                case MSG_SEEK_TO:
+                    mCallback.onSeekTo((Long) msg.obj);
+                    break;
+                case MSG_RATE:
+                    mCallback.onSetRating((Rating) msg.obj);
+                    break;
+            }
+        }
+    }
 }
diff --git a/media/java/android/media/session/MediaSessionInfo.java b/media/java/android/media/session/MediaSessionInfo.java
index 3d8d33f..f701211 100644
--- a/media/java/android/media/session/MediaSessionInfo.java
+++ b/media/java/android/media/session/MediaSessionInfo.java
@@ -20,6 +20,8 @@
 
 /**
  * Information about a media session, including the owner's package name.
+ *
+ * @hide
  */
 public final class MediaSessionInfo implements Parcelable {
     private final String mId;
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 249b9c4..c303e77 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -76,13 +76,13 @@
         }
     }
 
-    public void addRccListener(PendingIntent pi, TransportPerformer.Listener listener) {
+    public void addRccListener(PendingIntent pi,
+            MediaSession.TransportControlsCallback listener) {
         if (pi == null) {
             Log.w(TAG, "Pending intent was null, can't add rcc listener.");
             return;
         }
         SessionHolder holder = getHolder(pi, true);
-        TransportPerformer performer = holder.mSession.getTransportPerformer();
         if (holder.mRccListener != null) {
             if (holder.mRccListener == listener) {
                 if (DEBUG) {
@@ -92,9 +92,9 @@
                 return;
             }
             // Otherwise it changed so we need to switch to the new one
-            performer.removeListener(holder.mRccListener);
+            holder.mSession.removeTransportControlsCallback(holder.mRccListener);
         }
-        performer.addListener(listener, mHandler);
+        holder.mSession.addTransportControlsCallback(listener, mHandler);
         holder.mRccListener = listener;
         holder.mFlags |= MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS;
         holder.mSession.setFlags(holder.mFlags);
@@ -110,7 +110,7 @@
         }
         SessionHolder holder = getHolder(pi, false);
         if (holder != null && holder.mRccListener != null) {
-            holder.mSession.getTransportPerformer().removeListener(holder.mRccListener);
+            holder.mSession.removeTransportControlsCallback(holder.mRccListener);
             holder.mRccListener = null;
             holder.mFlags &= ~MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS;
             holder.mSession.setFlags(holder.mFlags);
@@ -141,7 +141,7 @@
         // set this flag
         holder.mFlags |= MediaSession.FLAG_HANDLES_MEDIA_BUTTONS;
         holder.mSession.setFlags(holder.mFlags);
-        holder.mSession.getTransportPerformer().addListener(holder.mMediaButtonListener, mHandler);
+        holder.mSession.addTransportControlsCallback(holder.mMediaButtonListener, mHandler);
 
         holder.mMediaButtonReceiver = new MediaButtonReceiver(pi, context);
         holder.mSession.addCallback(holder.mMediaButtonReceiver, mHandler);
@@ -156,7 +156,7 @@
         }
         SessionHolder holder = getHolder(pi, false);
         if (holder != null && holder.mMediaButtonListener != null) {
-            holder.mSession.getTransportPerformer().removeListener(holder.mMediaButtonListener);
+            holder.mSession.removeTransportControlsCallback(holder.mMediaButtonListener);
             holder.mFlags &= ~MediaSession.FLAG_HANDLES_MEDIA_BUTTONS;
             holder.mSession.setFlags(holder.mFlags);
             holder.mMediaButtonListener = null;
@@ -201,12 +201,12 @@
         }
 
         @Override
-        public void onMediaButton(Intent mediaButtonIntent) {
+        public void onMediaButtonEvent(Intent mediaButtonIntent) {
             MediaSessionLegacyHelper.sendKeyEvent(mPendingIntent, mContext, mediaButtonIntent);
         }
     }
 
-    private static final class MediaButtonListener extends TransportPerformer.Listener {
+    private static final class MediaButtonListener extends MediaSession.TransportControlsCallback {
         private final PendingIntent mPendingIntent;
         private final Context mContext;
 
@@ -226,12 +226,12 @@
         }
 
         @Override
-        public void onNext() {
+        public void onSkipToNext() {
             sendKeyEvent(KeyEvent.KEYCODE_MEDIA_NEXT);
         }
 
         @Override
-        public void onPrevious() {
+        public void onSkipToPrevious() {
             sendKeyEvent(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
         }
 
@@ -272,7 +272,7 @@
         public final PendingIntent mPi;
         public MediaButtonListener mMediaButtonListener;
         public MediaButtonReceiver mMediaButtonReceiver;
-        public TransportPerformer.Listener mRccListener;
+        public MediaSession.TransportControlsCallback mRccListener;
         public int mFlags;
 
         public SessionHolder(MediaSession session, PendingIntent pi) {
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 0589a7d..8d5e338 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -106,6 +106,7 @@
      * @param notificationListener The enabled notification listener component.
      *            May be null.
      * @return A list of controllers for ongoing sessions
+     * @hide
      */
     public List<MediaController> getActiveSessions(ComponentName notificationListener) {
         return getActiveSessionsForUser(notificationListener, UserHandle.myUserId());
diff --git a/media/java/android/media/session/MediaSessionToken.java b/media/java/android/media/session/MediaSessionToken.java
index f5569a4..86f5662 100644
--- a/media/java/android/media/session/MediaSessionToken.java
+++ b/media/java/android/media/session/MediaSessionToken.java
@@ -20,7 +20,12 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-public class MediaSessionToken implements Parcelable {
+/**
+ * Represents an ongoing session. This may be passed to apps by the session
+ * owner to allow them to create a {@link MediaController} to communicate with
+ * the session.
+ */
+public final class MediaSessionToken implements Parcelable {
     private ISessionController mBinder;
 
     /**
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 7ef38eaa..e09ac3f 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -22,7 +22,7 @@
 
 /**
  * Playback state for a {@link MediaSession}. This includes a state like
- * {@link PlaybackState#PLAYSTATE_PLAYING}, the current playback position,
+ * {@link PlaybackState#STATE_PLAYING}, the current playback position,
  * and the current control capabilities.
  */
 public final class PlaybackState implements Parcelable {
@@ -59,28 +59,28 @@
      *
      * @see #setActions
      */
-    public static final long ACTION_PREVIOUS_ITEM = 1 << 4;
+    public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
 
     /**
      * Indicates this performer supports the next command.
      *
      * @see #setActions
      */
-    public static final long ACTION_NEXT_ITEM = 1 << 5;
+    public static final long ACTION_SKIP_TO_NEXT = 1 << 5;
 
     /**
      * Indicates this performer supports the fast forward command.
      *
      * @see #setActions
      */
-    public static final long ACTION_FASTFORWARD = 1 << 6;
+    public static final long ACTION_FAST_FORWARD = 1 << 6;
 
     /**
      * Indicates this performer supports the set rating command.
      *
      * @see #setActions
      */
-    public static final long ACTION_RATING = 1 << 7;
+    public static final long ACTION_SET_RATING = 1 << 7;
 
     /**
      * Indicates this performer supports the seek to command.
@@ -102,42 +102,42 @@
      *
      * @see #setState
      */
-    public final static int PLAYSTATE_NONE = 0;
+    public final static int STATE_NONE = 0;
 
     /**
      * State indicating this item is currently stopped.
      *
      * @see #setState
      */
-    public final static int PLAYSTATE_STOPPED = 1;
+    public final static int STATE_STOPPED = 1;
 
     /**
      * State indicating this item is currently paused.
      *
      * @see #setState
      */
-    public final static int PLAYSTATE_PAUSED = 2;
+    public final static int STATE_PAUSED = 2;
 
     /**
      * State indicating this item is currently playing.
      *
      * @see #setState
      */
-    public final static int PLAYSTATE_PLAYING = 3;
+    public final static int STATE_PLAYING = 3;
 
     /**
      * State indicating this item is currently fast forwarding.
      *
      * @see #setState
      */
-    public final static int PLAYSTATE_FAST_FORWARDING = 4;
+    public final static int STATE_FAST_FORWARDING = 4;
 
     /**
      * State indicating this item is currently rewinding.
      *
      * @see #setState
      */
-    public final static int PLAYSTATE_REWINDING = 5;
+    public final static int STATE_REWINDING = 5;
 
     /**
      * State indicating this item is currently buffering and will begin playing
@@ -145,7 +145,7 @@
      *
      * @see #setState
      */
-    public final static int PLAYSTATE_BUFFERING = 6;
+    public final static int STATE_BUFFERING = 6;
 
     /**
      * State indicating this item is currently in an error state. The error
@@ -153,30 +153,30 @@
      *
      * @see #setState
      */
-    public final static int PLAYSTATE_ERROR = 7;
+    public final static int STATE_ERROR = 7;
 
     /**
      * State indicating the class doing playback is currently connecting to a
      * route. Depending on the implementation you may return to the previous
-     * state when the connection finishes or enter {@link #PLAYSTATE_NONE}. If
-     * the connection failed {@link #PLAYSTATE_ERROR} should be used.
+     * state when the connection finishes or enter {@link #STATE_NONE}. If
+     * the connection failed {@link #STATE_ERROR} should be used.
      * @hide
      */
-    public final static int PLAYSTATE_CONNECTING = 8;
+    public final static int STATE_CONNECTING = 8;
 
     /**
      * State indicating the player is currently skipping to the previous item.
      *
      * @see #setState
      */
-    public final static int PLAYSTATE_SKIPPING_BACKWARDS = 9;
+    public final static int STATE_SKIPPING_TO_PREVIOUS = 9;
 
     /**
      * State indicating the player is currently skipping to the next item.
      *
      * @see #setState
      */
-    public final static int PLAYSTATE_SKIPPING_FORWARDS = 10;
+    public final static int STATE_SKIPPING_TO_NEXT = 10;
 
     /**
      * Use this value for the position to indicate the position is not known.
@@ -188,7 +188,7 @@
     private long mBufferPosition;
     private float mRate;
     private long mActions;
-    private String mErrorMessage;
+    private CharSequence mErrorMessage;
     private long mUpdateTime;
 
     /**
@@ -221,7 +221,7 @@
         mUpdateTime = in.readLong();
         mBufferPosition = in.readLong();
         mActions = in.readLong();
-        mErrorMessage = in.readString();
+        mErrorMessage = in.readCharSequence();
 
     }
 
@@ -252,20 +252,20 @@
         dest.writeLong(mUpdateTime);
         dest.writeLong(mBufferPosition);
         dest.writeLong(mActions);
-        dest.writeString(mErrorMessage);
+        dest.writeCharSequence(mErrorMessage);
     }
 
     /**
      * Get the current state of playback. One of the following:
      * <ul>
-     * <li> {@link PlaybackState#PLAYSTATE_NONE}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_STOPPED}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_PLAYING}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_PAUSED}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_FAST_FORWARDING}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_REWINDING}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_BUFFERING}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_ERROR}</li>
+     * <li> {@link PlaybackState#STATE_NONE}</li>
+     * <li> {@link PlaybackState#STATE_STOPPED}</li>
+     * <li> {@link PlaybackState#STATE_PLAYING}</li>
+     * <li> {@link PlaybackState#STATE_PAUSED}</li>
+     * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
+     * <li> {@link PlaybackState#STATE_REWINDING}</li>
+     * <li> {@link PlaybackState#STATE_BUFFERING}</li>
+     * <li> {@link PlaybackState#STATE_ERROR}</li>
      */
     public int getState() {
         return mState;
@@ -283,25 +283,25 @@
      * <p>
      * The state must be one of the following:
      * <ul>
-     * <li> {@link PlaybackState#PLAYSTATE_NONE}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_STOPPED}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_PLAYING}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_PAUSED}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_FAST_FORWARDING}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_REWINDING}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_BUFFERING}</li>
-     * <li> {@link PlaybackState#PLAYSTATE_ERROR}</li>
+     * <li> {@link PlaybackState#STATE_NONE}</li>
+     * <li> {@link PlaybackState#STATE_STOPPED}</li>
+     * <li> {@link PlaybackState#STATE_PLAYING}</li>
+     * <li> {@link PlaybackState#STATE_PAUSED}</li>
+     * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
+     * <li> {@link PlaybackState#STATE_REWINDING}</li>
+     * <li> {@link PlaybackState#STATE_BUFFERING}</li>
+     * <li> {@link PlaybackState#STATE_ERROR}</li>
      * </ul>
      *
      * @param state The current state of playback.
      * @param position The position in the current track in ms.
-     * @param rate The current rate of playback as a multiple of normal
+     * @param playbackRate The current rate of playback as a multiple of normal
      *            playback.
      */
-    public void setState(int state, long position, float rate) {
+    public void setState(int state, long position, float playbackRate) {
         this.mState = state;
         this.mPosition = position;
-        this.mRate = rate;
+        this.mRate = playbackRate;
         mUpdateTime = SystemClock.elapsedRealtime();
     }
 
@@ -337,7 +337,7 @@
      *
      * @return The current rate of playback.
      */
-    public float getRate() {
+    public float getPlaybackRate() {
         return mRate;
     }
 
@@ -345,15 +345,15 @@
      * Get the current actions available on this session. This should use a
      * bitmask of the available actions.
      * <ul>
-     * <li> {@link PlaybackState#ACTION_PREVIOUS_ITEM}</li>
+     * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
      * <li> {@link PlaybackState#ACTION_REWIND}</li>
      * <li> {@link PlaybackState#ACTION_PLAY}</li>
      * <li> {@link PlaybackState#ACTION_PAUSE}</li>
      * <li> {@link PlaybackState#ACTION_STOP}</li>
-     * <li> {@link PlaybackState#ACTION_FASTFORWARD}</li>
-     * <li> {@link PlaybackState#ACTION_NEXT_ITEM}</li>
+     * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
+     * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
      * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
-     * <li> {@link PlaybackState#ACTION_RATING}</li>
+     * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
      * </ul>
      */
     public long getActions() {
@@ -364,15 +364,15 @@
      * Set the current capabilities available on this session. This should use a
      * bitmask of the available capabilities.
      * <ul>
-     * <li> {@link PlaybackState#ACTION_PREVIOUS_ITEM}</li>
+     * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
      * <li> {@link PlaybackState#ACTION_REWIND}</li>
      * <li> {@link PlaybackState#ACTION_PLAY}</li>
      * <li> {@link PlaybackState#ACTION_PAUSE}</li>
      * <li> {@link PlaybackState#ACTION_STOP}</li>
-     * <li> {@link PlaybackState#ACTION_FASTFORWARD}</li>
-     * <li> {@link PlaybackState#ACTION_NEXT_ITEM}</li>
+     * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
+     * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
      * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
-     * <li> {@link PlaybackState#ACTION_RATING}</li>
+     * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
      * </ul>
      */
     public void setActions(long capabilities) {
@@ -381,9 +381,9 @@
 
     /**
      * Get a user readable error message. This should be set when the state is
-     * {@link PlaybackState#PLAYSTATE_ERROR}.
+     * {@link PlaybackState#STATE_ERROR}.
      */
-    public String getErrorMessage() {
+    public CharSequence getErrorMessage() {
         return mErrorMessage;
     }
 
@@ -400,9 +400,9 @@
 
     /**
      * Set a user readable error message. This should be set when the state is
-     * {@link PlaybackState#PLAYSTATE_ERROR}.
+     * {@link PlaybackState#STATE_ERROR}.
      */
-    public void setErrorMessage(String errorMessage) {
+    public void setErrorMessage(CharSequence errorMessage) {
         mErrorMessage = errorMessage;
     }
 
@@ -417,23 +417,23 @@
     public static int getStateFromRccState(int rccState) {
         switch (rccState) {
             case RemoteControlClient.PLAYSTATE_BUFFERING:
-                return PLAYSTATE_BUFFERING;
+                return STATE_BUFFERING;
             case RemoteControlClient.PLAYSTATE_ERROR:
-                return PLAYSTATE_ERROR;
+                return STATE_ERROR;
             case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-                return PLAYSTATE_FAST_FORWARDING;
+                return STATE_FAST_FORWARDING;
             case RemoteControlClient.PLAYSTATE_NONE:
-                return PLAYSTATE_NONE;
+                return STATE_NONE;
             case RemoteControlClient.PLAYSTATE_PAUSED:
-                return PLAYSTATE_PAUSED;
+                return STATE_PAUSED;
             case RemoteControlClient.PLAYSTATE_PLAYING:
-                return PLAYSTATE_PLAYING;
+                return STATE_PLAYING;
             case RemoteControlClient.PLAYSTATE_REWINDING:
-                return PLAYSTATE_REWINDING;
+                return STATE_REWINDING;
             case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-                return PLAYSTATE_SKIPPING_BACKWARDS;
+                return STATE_SKIPPING_TO_PREVIOUS;
             case RemoteControlClient.PLAYSTATE_STOPPED:
-                return PLAYSTATE_STOPPED;
+                return STATE_STOPPED;
             default:
                 return -1;
         }
@@ -457,7 +457,7 @@
     private static long getActionForRccFlag(int flag) {
         switch (flag) {
             case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS:
-                return ACTION_PREVIOUS_ITEM;
+                return ACTION_SKIP_TO_PREVIOUS;
             case RemoteControlClient.FLAG_KEY_MEDIA_REWIND:
                 return ACTION_REWIND;
             case RemoteControlClient.FLAG_KEY_MEDIA_PLAY:
@@ -469,13 +469,13 @@
             case RemoteControlClient.FLAG_KEY_MEDIA_STOP:
                 return ACTION_STOP;
             case RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD:
-                return ACTION_FASTFORWARD;
+                return ACTION_FAST_FORWARD;
             case RemoteControlClient.FLAG_KEY_MEDIA_NEXT:
-                return ACTION_NEXT_ITEM;
+                return ACTION_SKIP_TO_NEXT;
             case RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE:
                 return ACTION_SEEK_TO;
             case RemoteControlClient.FLAG_KEY_MEDIA_RATING:
-                return ACTION_RATING;
+                return ACTION_SET_RATING;
         }
         return 0;
     }
diff --git a/media/java/android/media/session/RemoteVolumeProvider.java b/media/java/android/media/session/RemoteVolumeProvider.java
index 9526cc8..47f672f 100644
--- a/media/java/android/media/session/RemoteVolumeProvider.java
+++ b/media/java/android/media/session/RemoteVolumeProvider.java
@@ -1,35 +1,61 @@
+/*
+ * 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 android.media.session;
 
 /**
  * Handles requests to adjust or set the volume on a session. This is also used
  * to push volume updates back to the session after a request has been handled.
  * You can set a volume provider on a session by calling
- * {@link MediaSession#useRemotePlayback}.
+ * {@link MediaSession#setPlaybackToRemote}.
  */
 public abstract class RemoteVolumeProvider {
 
     /**
-     * Handles relative volume changes via {@link #onAdjustVolume(int)}.
+     * The volume is fixed and can not be modified. Requests to change volume
+     * should be ignored.
      */
-    public static final int FLAG_VOLUME_RELATIVE = 1 << 0;
+    public static final int VOLUME_CONTROL_FIXED = 0;
 
     /**
-     * Handles setting the volume via {@link #onSetVolume(int)}.
+     * The volume control uses relative adjustment via
+     * {@link #onAdjustVolumeBy(int)}. Attempts to set the volume to a specific
+     * value should be ignored.
      */
-    public static final int FLAG_VOLUME_ABSOLUTE = 1 << 1;
+    public static final int VOLUME_CONTROL_RELATIVE = 1;
 
-    private final int mFlags;
+    /**
+     * The volume control uses an absolute value. It may be adjusted using
+     * {@link #onAdjustVolumeBy(int)} or set directly using
+     * {@link #onSetVolumeTo(int)}.
+     */
+    public static final int VOLUME_CONTROL_ABSOLUTE = 2;
+
+    private final int mControlType;
     private final int mMaxVolume;
 
     /**
      * Create a new volume provider for handling volume events. You must specify
-     * the type of events and the maximum volume that can be used.
+     * the type of volume control and the maximum volume that can be used.
      *
-     * @param flags The flags to use with this provider.
+     * @param volumeControl The method for controlling volume that is used by
+     *            this provider.
      * @param maxVolume The maximum allowed volume.
      */
-    public RemoteVolumeProvider(int flags, int maxVolume) {
-        mFlags = flags;
+    public RemoteVolumeProvider(int volumeControl, int maxVolume) {
+        mControlType = volumeControl;
         mMaxVolume = maxVolume;
     }
 
@@ -38,15 +64,15 @@
      *
      * @return The current volume.
      */
-    public abstract int getCurrentVolume();
+    public abstract int onGetCurrentVolume();
 
     /**
-     * Get the flags that were set for this volume provider.
+     * Get the volume control type that this volume provider uses.
      *
-     * @return The flags for this volume provider
+     * @return The volume control type for this volume provider
      */
-    public final int getFlags() {
-        return mFlags;
+    public final int getVolumeControl() {
+        return mControlType;
     }
 
     /**
@@ -59,7 +85,7 @@
     }
 
     /**
-     * Notify the system that the remove playback's volume has been changed.
+     * Notify the system that the remote playback's volume has been changed.
      */
     public final void notifyVolumeChanged() {
         // TODO
@@ -70,7 +96,7 @@
      *
      * @param volume The volume to set the output to.
      */
-    public void onSetVolume(int volume) {
+    public void onSetVolumeTo(int volume) {
     }
 
     /**
@@ -79,6 +105,6 @@
      *
      * @param delta The amount to change the volume
      */
-    public void onAdjustVolume(int delta) {
+    public void onAdjustVolumeBy(int delta) {
     }
 }
\ No newline at end of file
diff --git a/media/java/android/media/session/TransportController.java b/media/java/android/media/session/TransportController.java
deleted file mode 100644
index 090489b..0000000
--- a/media/java/android/media/session/TransportController.java
+++ /dev/null
@@ -1,343 +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 android.media.session;
-
-import android.media.MediaMetadata;
-import android.media.Rating;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-
-/**
- * Interface for controlling media playback on a session. This allows an app to
- * request changes in playback, retrieve the current playback state and
- * metadata, and listen for changes to the playback state and metadata.
- */
-public final class TransportController {
-    private static final String TAG = "TransportController";
-
-    private final Object mLock = new Object();
-    private final ArrayList<MessageHandler> mListeners = new ArrayList<MessageHandler>();
-    private final ISessionController mBinder;
-
-    /**
-     * @hide
-     */
-    public TransportController(ISessionController binder) {
-        mBinder = binder;
-    }
-
-    /**
-     * Start listening to changes in playback state.
-     */
-    public void addStateListener(TransportStateListener listener) {
-        addStateListener(listener, null);
-    }
-
-    public void addStateListener(TransportStateListener listener, Handler handler) {
-        if (listener == null) {
-            throw new IllegalArgumentException("Listener cannot be null");
-        }
-        synchronized (mLock) {
-            if (getHandlerForListenerLocked(listener) != null) {
-                Log.w(TAG, "Listener is already added, ignoring");
-                return;
-            }
-            if (handler == null) {
-                handler = new Handler();
-            }
-
-            MessageHandler msgHandler = new MessageHandler(handler.getLooper(), listener);
-            mListeners.add(msgHandler);
-        }
-    }
-
-    /**
-     * Stop listening to changes in playback state.
-     */
-    public void removeStateListener(TransportStateListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("Listener cannot be null");
-        }
-        synchronized (mLock) {
-            removeStateListenerLocked(listener);
-        }
-    }
-
-    /**
-     * Request that the player start its playback at its current position.
-     */
-    public void play() {
-        try {
-            mBinder.play();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling play.", e);
-        }
-    }
-
-    /**
-     * Request that the player pause its playback and stay at its current
-     * position.
-     */
-    public void pause() {
-        try {
-            mBinder.pause();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling pause.", e);
-        }
-    }
-
-    /**
-     * Request that the player stop its playback; it may clear its state in
-     * whatever way is appropriate.
-     */
-    public void stop() {
-        try {
-            mBinder.stop();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling stop.", e);
-        }
-    }
-
-    /**
-     * Move to a new location in the media stream.
-     *
-     * @param pos Position to move to, in milliseconds.
-     */
-    public void seekTo(long pos) {
-        try {
-            mBinder.seekTo(pos);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling seekTo.", e);
-        }
-    }
-
-    /**
-     * Start fast forwarding. If playback is already fast forwarding this may
-     * increase the rate.
-     */
-    public void fastForward() {
-        try {
-            mBinder.fastForward();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling fastForward.", e);
-        }
-    }
-
-    /**
-     * Skip to the next item.
-     */
-    public void next() {
-        try {
-            mBinder.next();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling next.", e);
-        }
-    }
-
-    /**
-     * Start rewinding. If playback is already rewinding this may increase the
-     * rate.
-     */
-    public void rewind() {
-        try {
-            mBinder.rewind();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling rewind.", e);
-        }
-    }
-
-    /**
-     * Skip to the previous item.
-     */
-    public void previous() {
-        try {
-            mBinder.previous();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling previous.", e);
-        }
-    }
-
-    /**
-     * Rate the current content. This will cause the rating to be set for the
-     * current user. The Rating type must match the type returned by
-     * {@link #getRatingType()}.
-     *
-     * @param rating The rating to set for the current content
-     */
-    public void rate(Rating rating) {
-        try {
-            mBinder.rate(rating);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling rate.", e);
-        }
-    }
-
-    /**
-     * Get the rating type supported by the session. One of:
-     * <ul>
-     * <li>{@link Rating#RATING_NONE}</li>
-     * <li>{@link Rating#RATING_HEART}</li>
-     * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
-     * <li>{@link Rating#RATING_3_STARS}</li>
-     * <li>{@link Rating#RATING_4_STARS}</li>
-     * <li>{@link Rating#RATING_5_STARS}</li>
-     * <li>{@link Rating#RATING_PERCENTAGE}</li>
-     * </ul>
-     *
-     * @return The supported rating type
-     */
-    public int getRatingType() {
-        try {
-            return mBinder.getRatingType();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getRatingType.", e);
-            return Rating.RATING_NONE;
-        }
-    }
-
-    /**
-     * Get the current playback state for this session.
-     *
-     * @return The current PlaybackState or null
-     */
-    public PlaybackState getPlaybackState() {
-        try {
-            return mBinder.getPlaybackState();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getPlaybackState.", e);
-            return null;
-        }
-    }
-
-    /**
-     * Get the current metadata for this session.
-     *
-     * @return The current MediaMetadata or null.
-     */
-    public MediaMetadata getMetadata() {
-        try {
-            return mBinder.getMetadata();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getMetadata.", e);
-            return null;
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public final void postPlaybackStateChanged(PlaybackState state) {
-        synchronized (mLock) {
-            for (int i = mListeners.size() - 1; i >= 0; i--) {
-                mListeners.get(i).post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE, state);
-            }
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public final void postMetadataChanged(MediaMetadata metadata) {
-        synchronized (mLock) {
-            for (int i = mListeners.size() - 1; i >= 0; i--) {
-                mListeners.get(i).post(MessageHandler.MSG_UPDATE_METADATA,
-                        metadata);
-            }
-        }
-    }
-
-    private MessageHandler getHandlerForListenerLocked(TransportStateListener listener) {
-        for (int i = mListeners.size() - 1; i >= 0; i--) {
-            MessageHandler handler = mListeners.get(i);
-            if (listener == handler.mListener) {
-                return handler;
-            }
-        }
-        return null;
-    }
-
-    private boolean removeStateListenerLocked(TransportStateListener listener) {
-        for (int i = mListeners.size() - 1; i >= 0; i--) {
-            if (listener == mListeners.get(i).mListener) {
-                mListeners.remove(i);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Register using {@link #addStateListener} to receive updates when there
-     * are playback changes on the session.
-     */
-    public static abstract class TransportStateListener {
-        private MessageHandler mHandler;
-        /**
-         * Override to handle changes in playback state.
-         *
-         * @param state The new playback state of the session
-         */
-        public void onPlaybackStateChanged(PlaybackState state) {
-        }
-
-        /**
-         * Override to handle changes to the current metadata.
-         *
-         * @see MediaMetadata
-         * @param metadata The current metadata for the session or null
-         */
-        public void onMetadataChanged(MediaMetadata metadata) {
-        }
-
-        private void setHandler(Handler handler) {
-            mHandler = new MessageHandler(handler.getLooper(), this);
-        }
-    }
-
-    private static class MessageHandler extends Handler {
-        private static final int MSG_UPDATE_PLAYBACK_STATE = 1;
-        private static final int MSG_UPDATE_METADATA = 2;
-
-        private TransportStateListener mListener;
-
-        public MessageHandler(Looper looper, TransportStateListener cb) {
-            super(looper, null, true);
-            mListener = cb;
-        }
-
-        public void post(int msg, Object obj) {
-            obtainMessage(msg, obj).sendToTarget();
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_UPDATE_PLAYBACK_STATE:
-                    mListener.onPlaybackStateChanged((PlaybackState) msg.obj);
-                    break;
-                case MSG_UPDATE_METADATA:
-                    mListener.onMetadataChanged((MediaMetadata) msg.obj);
-                    break;
-            }
-        }
-    }
-
-}
diff --git a/media/java/android/media/session/TransportPerformer.java b/media/java/android/media/session/TransportPerformer.java
deleted file mode 100644
index 1588d8f..0000000
--- a/media/java/android/media/session/TransportPerformer.java
+++ /dev/null
@@ -1,351 +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 android.media.session;
-
-import android.media.AudioManager;
-import android.media.MediaMetadata;
-import android.media.Rating;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-
-/**
- * Allows broadcasting of playback changes.
- */
-public final class TransportPerformer {
-    private static final String TAG = "TransportPerformer";
-    private final Object mLock = new Object();
-    private final ArrayList<MessageHandler> mListeners = new ArrayList<MessageHandler>();
-
-    private ISession mBinder;
-
-    /**
-     * @hide
-     */
-    public TransportPerformer(ISession binder) {
-        mBinder = binder;
-    }
-
-    /**
-     * Add a listener to receive updates on.
-     *
-     * @param listener The callback object
-     */
-    public void addListener(Listener listener) {
-        addListener(listener, null);
-    }
-
-    /**
-     * Add a listener to receive updates on. The updates will be posted to the
-     * specified handler. If no handler is provided they will be posted to the
-     * caller's thread.
-     *
-     * @param listener The listener to receive updates on
-     * @param handler The handler to post the updates on
-     */
-    public void addListener(Listener listener, Handler handler) {
-        if (listener == null) {
-            throw new IllegalArgumentException("Listener cannot be null");
-        }
-        synchronized (mLock) {
-            if (getHandlerForListenerLocked(listener) != null) {
-                Log.w(TAG, "Listener is already added, ignoring");
-            }
-            if (handler == null) {
-                handler = new Handler();
-            }
-            MessageHandler msgHandler = new MessageHandler(handler.getLooper(), listener);
-            mListeners.add(msgHandler);
-        }
-    }
-
-    /**
-     * Stop receiving updates on the specified handler. If an update has already
-     * been posted you may still receive it after this call returns.
-     *
-     * @param listener The listener to stop receiving updates on
-     */
-    public void removeListener(Listener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("Listener cannot be null");
-        }
-        synchronized (mLock) {
-            removeListenerLocked(listener);
-        }
-    }
-
-    /**
-     * Update the current playback state.
-     *
-     * @param state The current state of playback
-     */
-    public final void setPlaybackState(PlaybackState state) {
-        try {
-            mBinder.setPlaybackState(state);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
-        }
-    }
-
-    /**
-     * Update the current metadata. New metadata can be created using
-     * {@link MediaMetadata.Builder}.
-     *
-     * @param metadata The new metadata
-     */
-    public final void setMetadata(MediaMetadata metadata) {
-        try {
-            mBinder.setMetadata(metadata);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public final void onPlay() {
-        post(MessageHandler.MESSAGE_PLAY);
-    }
-
-    /**
-     * @hide
-     */
-    public final void onPause() {
-        post(MessageHandler.MESSAGE_PAUSE);
-    }
-
-    /**
-     * @hide
-     */
-    public final void onStop() {
-        post(MessageHandler.MESSAGE_STOP);
-    }
-
-    /**
-     * @hide
-     */
-    public final void onNext() {
-        post(MessageHandler.MESSAGE_NEXT);
-    }
-
-    /**
-     * @hide
-     */
-    public final void onPrevious() {
-        post(MessageHandler.MESSAGE_PREVIOUS);
-    }
-
-    /**
-     * @hide
-     */
-    public final void onFastForward() {
-        post(MessageHandler.MESSAGE_FAST_FORWARD);
-    }
-
-    /**
-     * @hide
-     */
-    public final void onRewind() {
-        post(MessageHandler.MESSAGE_REWIND);
-    }
-
-    /**
-     * @hide
-     */
-    public final void onSeekTo(long pos) {
-        post(MessageHandler.MESSAGE_SEEK_TO, pos);
-    }
-
-    /**
-     * @hide
-     */
-    public final void onRate(Rating rating) {
-        post(MessageHandler.MESSAGE_RATE, rating);
-    }
-
-    private MessageHandler getHandlerForListenerLocked(Listener listener) {
-        for (int i = mListeners.size() - 1; i >= 0; i--) {
-            MessageHandler handler = mListeners.get(i);
-            if (listener == handler.mListener) {
-                return handler;
-            }
-        }
-        return null;
-    }
-
-    private boolean removeListenerLocked(Listener listener) {
-        for (int i = mListeners.size() - 1; i >= 0; i--) {
-            if (listener == mListeners.get(i).mListener) {
-                mListeners.remove(i);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private void post(int what, Object obj) {
-        synchronized (mLock) {
-            for (int i = mListeners.size() - 1; i >= 0; i--) {
-                mListeners.get(i).post(what, obj);
-            }
-        }
-    }
-
-    private void post(int what) {
-        post(what, null);
-    }
-
-    /**
-     * Extend Listener to handle transport controls. Listeners can be registered
-     * using {@link #addListener}.
-     */
-    public static abstract class Listener {
-
-        /**
-         * Override to handle requests to begin playback.
-         */
-        public void onPlay() {
-        }
-
-        /**
-         * Override to handle requests to pause playback.
-         */
-        public void onPause() {
-        }
-
-        /**
-         * Override to handle requests to skip to the next media item.
-         */
-        public void onNext() {
-        }
-
-        /**
-         * Override to handle requests to skip to the previous media item.
-         */
-        public void onPrevious() {
-        }
-
-        /**
-         * Override to handle requests to fast forward.
-         */
-        public void onFastForward() {
-        }
-
-        /**
-         * Override to handle requests to rewind.
-         */
-        public void onRewind() {
-        }
-
-        /**
-         * Override to handle requests to stop playback.
-         */
-        public void onStop() {
-        }
-
-        /**
-         * Override to handle requests to seek to a specific position in ms.
-         *
-         * @param pos New position to move to, in milliseconds.
-         */
-        public void onSeekTo(long pos) {
-        }
-
-        /**
-         * Override to handle the item being rated.
-         *
-         * @param rating
-         */
-        public void onRate(Rating rating) {
-        }
-
-        /**
-         * Report that audio focus has changed on the app. This only happens if
-         * you have indicated you have started playing with
-         * {@link #setPlaybackState}.
-         *
-         * @param focusChange The type of focus change, TBD.
-         */
-        public void onRouteFocusChange(int focusChange) {
-        }
-    }
-
-    private class MessageHandler extends Handler {
-        private static final int MESSAGE_PLAY = 1;
-        private static final int MESSAGE_PAUSE = 2;
-        private static final int MESSAGE_STOP = 3;
-        private static final int MESSAGE_NEXT = 4;
-        private static final int MESSAGE_PREVIOUS = 5;
-        private static final int MESSAGE_FAST_FORWARD = 6;
-        private static final int MESSAGE_REWIND = 7;
-        private static final int MESSAGE_SEEK_TO = 8;
-        private static final int MESSAGE_RATE = 9;
-
-        private Listener mListener;
-
-        public MessageHandler(Looper looper, Listener cb) {
-            super(looper);
-            mListener = cb;
-        }
-
-        public void post(int what, Object obj) {
-            obtainMessage(what, obj).sendToTarget();
-        }
-
-        public void post(int what) {
-            post(what, null);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MESSAGE_PLAY:
-                    mListener.onPlay();
-                    break;
-                case MESSAGE_PAUSE:
-                    mListener.onPause();
-                    break;
-                case MESSAGE_STOP:
-                    mListener.onStop();
-                    break;
-                case MESSAGE_NEXT:
-                    mListener.onNext();
-                    break;
-                case MESSAGE_PREVIOUS:
-                    mListener.onPrevious();
-                    break;
-                case MESSAGE_FAST_FORWARD:
-                    mListener.onFastForward();
-                    break;
-                case MESSAGE_REWIND:
-                    mListener.onRewind();
-                    break;
-                case MESSAGE_SEEK_TO:
-                    mListener.onSeekTo((Long) msg.obj);
-                    break;
-                case MESSAGE_RATE:
-                    mListener.onRate((Rating) msg.obj);
-                    break;
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 030e3ed..c909a54 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -66,13 +66,13 @@
      * These are the playback states that count as currently active.
      */
     private static final int[] ACTIVE_STATES = {
-            PlaybackState.PLAYSTATE_FAST_FORWARDING,
-            PlaybackState.PLAYSTATE_REWINDING,
-            PlaybackState.PLAYSTATE_SKIPPING_BACKWARDS,
-            PlaybackState.PLAYSTATE_SKIPPING_FORWARDS,
-            PlaybackState.PLAYSTATE_BUFFERING,
-            PlaybackState.PLAYSTATE_CONNECTING,
-            PlaybackState.PLAYSTATE_PLAYING };
+            PlaybackState.STATE_FAST_FORWARDING,
+            PlaybackState.STATE_REWINDING,
+            PlaybackState.STATE_SKIPPING_TO_PREVIOUS,
+            PlaybackState.STATE_SKIPPING_TO_NEXT,
+            PlaybackState.STATE_BUFFERING,
+            PlaybackState.STATE_CONNECTING,
+            PlaybackState.STATE_PLAYING };
 
     /**
      * The length of time a session will still be considered active after
@@ -301,7 +301,7 @@
         if (isActiveState(state)) {
             return true;
         }
-        if (state == mPlaybackState.PLAYSTATE_PAUSED) {
+        if (state == mPlaybackState.STATE_PAUSED) {
             long inactiveTime = SystemClock.uptimeMillis() - mLastActiveTime;
             if (inactiveTime < ACTIVE_BUFFER) {
                 return true;
@@ -509,12 +509,12 @@
         }
         PlaybackState result = null;
         if (state != null) {
-            if (state.getState() == PlaybackState.PLAYSTATE_PLAYING
-                    || state.getState() == PlaybackState.PLAYSTATE_FAST_FORWARDING
-                    || state.getState() == PlaybackState.PLAYSTATE_REWINDING) {
+            if (state.getState() == PlaybackState.STATE_PLAYING
+                    || state.getState() == PlaybackState.STATE_FAST_FORWARDING
+                    || state.getState() == PlaybackState.STATE_REWINDING) {
                 long updateTime = state.getLastPositionUpdateTime();
                 if (updateTime > 0) {
-                    long position = (long) (state.getRate()
+                    long position = (long) (state.getPlaybackRate()
                             * (SystemClock.elapsedRealtime() - updateTime)) + state.getPosition();
                     if (duration >= 0 && position > duration) {
                         position = duration;
@@ -522,7 +522,7 @@
                         position = 0;
                     }
                     result = new PlaybackState(state);
-                    result.setState(state.getState(), position, state.getRate());
+                    result.setState(state.getState(), position, state.getPlaybackRate());
                 }
             }
         }
@@ -588,7 +588,7 @@
         public void setPlaybackState(PlaybackState state) {
             int oldState = mPlaybackState == null ? 0 : mPlaybackState.getState();
             int newState = state == null ? 0 : state.getState();
-            if (isActiveState(oldState) && newState == PlaybackState.PLAYSTATE_PAUSED) {
+            if (isActiveState(oldState) && newState == PlaybackState.STATE_PAUSED) {
                 mLastActiveTime = SystemClock.elapsedRealtime();
             }
             mPlaybackState = state;
@@ -649,14 +649,16 @@
             mCb = cb;
         }
 
-        public void sendMediaButton(KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
+        public boolean sendMediaButton(KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
             Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
             mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
             try {
                 mCb.onMediaButton(mediaButtonIntent, sequenceId, cb);
+                return true;
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
             }
+            return false;
         }
 
         public void sendCommand(String command, Bundle extras, ResultReceiver cb) {
@@ -788,8 +790,8 @@
         }
 
         @Override
-        public void sendMediaButton(KeyEvent mediaButtonIntent) {
-            mSessionCb.sendMediaButton(mediaButtonIntent, 0, null);
+        public boolean sendMediaButton(KeyEvent mediaButtonIntent) {
+            return mSessionCb.sendMediaButton(mediaButtonIntent, 0, null);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 7ba9212..56236f8 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -33,18 +33,18 @@
      * bump priority regardless of the old state.
      */
     private static final int[] ALWAYS_PRIORITY_STATES = {
-            PlaybackState.PLAYSTATE_FAST_FORWARDING,
-            PlaybackState.PLAYSTATE_REWINDING,
-            PlaybackState.PLAYSTATE_SKIPPING_BACKWARDS,
-            PlaybackState.PLAYSTATE_SKIPPING_FORWARDS };
+            PlaybackState.STATE_FAST_FORWARDING,
+            PlaybackState.STATE_REWINDING,
+            PlaybackState.STATE_SKIPPING_TO_PREVIOUS,
+            PlaybackState.STATE_SKIPPING_TO_NEXT };
     /**
      * These are states that usually indicate the user took an action if they
      * were entered from a non-priority state.
      */
     private static final int[] TRANSITION_PRIORITY_STATES = {
-            PlaybackState.PLAYSTATE_BUFFERING,
-            PlaybackState.PLAYSTATE_CONNECTING,
-            PlaybackState.PLAYSTATE_PLAYING };
+            PlaybackState.STATE_BUFFERING,
+            PlaybackState.STATE_CONNECTING,
+            PlaybackState.STATE_PLAYING };
 
     private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
 
diff --git a/telecomm/java/android/telecomm/CallServiceAdapter.java b/telecomm/java/android/telecomm/CallServiceAdapter.java
index d5bb989..dafc310 100644
--- a/telecomm/java/android/telecomm/CallServiceAdapter.java
+++ b/telecomm/java/android/telecomm/CallServiceAdapter.java
@@ -156,5 +156,17 @@
         }
     }
 
+    /**
+     * Asks Telecomm to start or stop a ringback tone for a call.
+     *
+     * @param callId The unique ID of the call whose ringback is being changed.
+     * @param ringback Whether Telecomm should start playing a ringback tone.
+     */
+    public void setRequestingRingback(String callId, boolean ringback) {
+        try {
+            mAdapter.setRequestingRingback(callId, ringback);
+        } catch (RemoteException e) {
+        }
+    }
 
 }
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 88de17a..8cce8e6 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -33,6 +33,7 @@
         void onHandleChanged(Connection c, Uri newHandle);
         void onSignalChanged(Connection c, Bundle details);
         void onDisconnected(Connection c, int cause, String message);
+        void onRequestingRingback(Connection c, boolean ringback);
         void onDestroyed(Connection c);
     }
 
@@ -60,6 +61,10 @@
         /** {@inheritDoc} */
         @Override
         public void onDestroyed(Connection c) {}
+
+        /** {@inheritDoc} */
+        @Override
+        public void onRequestingRingback(Connection c, boolean ringback) {}
     }
 
     public final class State {
@@ -77,6 +82,7 @@
     private int mState = State.NEW;
     private CallAudioState mCallAudioState;
     private Uri mHandle;
+    private boolean mRequestingRingback = false;
 
     /**
      * Create a new Connection.
@@ -268,6 +274,14 @@
     }
 
     /**
+     * @return Whether this connection is requesting that the system play a ringback tone
+     * on its behalf.
+     */
+    public boolean isRequestingRingback() {
+        return mRequestingRingback;
+    }
+
+    /**
      * Sets the value of the {@link #getHandle()} property and notifies listeners.
      *
      * @param handle The new handle.
@@ -286,6 +300,7 @@
      * communicate).
      */
     protected void setActive() {
+        setRequestingRingback(false);
         setState(State.ACTIVE);
     }
 
@@ -329,6 +344,21 @@
     }
 
     /**
+     * Requests that the framework play a ringback tone. This is to be invoked by implementations
+     * that do not play a ringback tone themselves in the call's audio stream.
+     *
+     * @param ringback Whether the ringback tone is to be played.
+     */
+    protected void setRequestingRingback(boolean ringback) {
+        if (mRequestingRingback != ringback) {
+            mRequestingRingback = ringback;
+            for (Listener l : mListeners) {
+                l.onRequestingRingback(this, ringback);
+            }
+        }
+    }
+
+    /**
      * Notifies this Connection and listeners that the {@link #getCallAudioState()} property
      * has a new value.
      *
@@ -336,7 +366,7 @@
      */
     protected void onSetAudioState(CallAudioState state) {
         // TODO: Enforce super called
-        this.mCallAudioState = state;
+        mCallAudioState = state;
         for (Listener l : mListeners) {
             l.onAudioStateChanged(this, state);
         }
@@ -356,6 +386,21 @@
     }
 
     /**
+     * Notifies this Connection of an internal state change. This method is called before the
+     * state is actually changed. Overriding implementations must call
+     * {@code super.onSetState(state)}.
+     *
+     * @param state The new state, a {@link Connection.State} member.
+     */
+    protected void onSetState(int state) {
+        // TODO: Enforce super called
+        this.mState = state;
+        for (Listener l : mListeners) {
+            l.onStateChanged(this, state);
+        }
+    }
+
+    /**
      * Notifies this Connection of a request to play a DTMF tone.
      *
      * @param c A DTMF character.
@@ -401,9 +446,6 @@
 
     private void setState(int state) {
         Log.d(this, "setState: %s", stateToString(state));
-        this.mState = state;
-        for (Listener l : mListeners) {
-            l.onStateChanged(this, state);
-        }
+        onSetState(state);
     }
 }
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 492b08e..8d02842 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -89,6 +89,13 @@
         public void onDestroyed(Connection c) {
             removeConnection(c);
         }
+
+        @Override
+        public void onRequestingRingback(Connection c, boolean ringback) {
+            String id = mIdByConnection.get(c);
+            Log.d(this, "Adapter onRingback %b", ringback);
+            getAdapter().setRequestingRingback(id, ringback);
+        }
     };
 
     @Override
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
index dfdaa75..6d36494 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
@@ -43,4 +43,6 @@
     void setDisconnected(String callId, int disconnectCause, String disconnectMessage);
 
     void setOnHold(String callId);
+
+    void setRequestingRingback(String callId, boolean ringing);
 }
diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
index 158f5e4..ee407ad 100644
--- a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
+++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
@@ -99,10 +99,10 @@
             switch (v.getId()) {
                 case R.id.play_button:
                     Log.d(TAG, "Play button pressed, in state " + mPlaybackState);
-                    if (mPlaybackState == PlaybackState.PLAYSTATE_PAUSED
-                            || mPlaybackState == PlaybackState.PLAYSTATE_STOPPED) {
+                    if (mPlaybackState == PlaybackState.STATE_PAUSED
+                            || mPlaybackState == PlaybackState.STATE_STOPPED) {
                         mPlayer.play();
-                    } else if (mPlaybackState == PlaybackState.PLAYSTATE_PLAYING) {
+                    } else if (mPlaybackState == PlaybackState.STATE_PLAYING) {
                         mPlayer.pause();
                     }
                     break;
@@ -126,31 +126,31 @@
             boolean enableControls = true;
             StringBuilder statusBuilder = new StringBuilder();
             switch (mPlaybackState) {
-                case PlaybackState.PLAYSTATE_PLAYING:
+                case PlaybackState.STATE_PLAYING:
                     statusBuilder.append("playing");
                     mPlayButton.setText("Pause");
                     enablePlay = true;
                     break;
-                case PlaybackState.PLAYSTATE_PAUSED:
+                case PlaybackState.STATE_PAUSED:
                     statusBuilder.append("paused");
                     mPlayButton.setText("Play");
                     enablePlay = true;
                     break;
-                case PlaybackState.PLAYSTATE_STOPPED:
+                case PlaybackState.STATE_STOPPED:
                     statusBuilder.append("ended");
                     mPlayButton.setText("Play");
                     enablePlay = true;
                     break;
-                case PlaybackState.PLAYSTATE_ERROR:
+                case PlaybackState.STATE_ERROR:
                     statusBuilder.append("error: ").append(state.getErrorMessage());
                     break;
-                case PlaybackState.PLAYSTATE_BUFFERING:
+                case PlaybackState.STATE_BUFFERING:
                     statusBuilder.append("buffering");
                     break;
-                case PlaybackState.PLAYSTATE_NONE:
+                case PlaybackState.STATE_NONE:
                     statusBuilder.append("none");
                     break;
-                case PlaybackState.PLAYSTATE_CONNECTING:
+                case PlaybackState.STATE_CONNECTING:
                     statusBuilder.append("connecting");
                     enableControls = false;
                     break;
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
index 9f7bb26..145b389 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerController.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
@@ -21,7 +21,6 @@
 import android.media.session.RouteInfo;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
-import android.media.session.TransportController;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -42,12 +41,11 @@
 
     protected MediaController mController;
     protected IPlayerService mBinder;
-    protected TransportController mTransportControls;
+    protected MediaController.TransportControls mTransportControls;
 
     private final Intent mServiceIntent;
     private Context mContext;
     private Listener mListener;
-    private TransportListener mTransportListener = new TransportListener();
     private SessionCallback mControllerCb;
     private MediaSessionManager mManager;
     private Handler mHandler = new Handler();
@@ -161,16 +159,13 @@
                 return;
             }
             mController.addCallback(mControllerCb, mHandler);
-            mTransportControls = mController.getTransportController();
-            if (mTransportControls != null) {
-                mTransportControls.addStateListener(mTransportListener);
-            }
+            mTransportControls = mController.getTransportControls();
             Log.d(TAG, "Ready to use PlayerService");
 
             if (mListener != null) {
                 mListener.onConnectionStateChange(STATE_CONNECTED);
                 if (mTransportControls != null) {
-                    mListener.onPlaybackStateChange(mTransportControls.getPlaybackState());
+                    mListener.onPlaybackStateChange(mController.getPlaybackState());
                 }
             }
         }
@@ -181,9 +176,7 @@
         public void onRouteChanged(RouteInfo route) {
             // TODO
         }
-    }
 
-    private class TransportListener extends TransportController.TransportStateListener {
         @Override
         public void onPlaybackStateChanged(PlaybackState state) {
             if (state == null) {
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerService.java b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
index 0ad6dd1..934f4ef 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerService.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
@@ -103,11 +103,11 @@
         @Override
         public void onPlayStateChanged(PlaybackState state) {
             switch (state.getState()) {
-                case PlaybackState.PLAYSTATE_PLAYING:
+                case PlaybackState.STATE_PLAYING:
                     onPlaybackStarted();
                     break;
-                case PlaybackState.PLAYSTATE_STOPPED:
-                case PlaybackState.PLAYSTATE_ERROR:
+                case PlaybackState.STATE_STOPPED:
+                case PlaybackState.STATE_ERROR:
                     onPlaybackEnded();
                     break;
             }
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index 94d0851..c1fa74f 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -25,7 +25,6 @@
 import android.media.session.MediaSessionManager;
 import android.media.session.MediaSessionToken;
 import android.media.session.PlaybackState;
-import android.media.session.TransportPerformer;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -45,7 +44,6 @@
     protected Renderer mRenderer;
     protected MediaSession.Callback mCallback;
     protected Renderer.Listener mRenderListener;
-    protected TransportPerformer mPerformer;
 
     protected PlaybackState mPlaybackState;
     protected Listener mListener;
@@ -84,9 +82,8 @@
         Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
         mSession = man.createSession("OneMedia");
         mSession.addCallback(mCallback);
-        mPerformer = mSession.getTransportPerformer();
-        mPerformer.addListener(new TransportListener());
-        mPerformer.setPlaybackState(mPlaybackState);
+        mSession.addTransportControlsCallback(new TransportListener());
+        mSession.setPlaybackState(mPlaybackState);
         mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
         mSession.setRouteOptions(mRouteOptions);
         mSession.setActive(true);
@@ -120,10 +117,10 @@
     }
 
     private void updateState(int newState) {
-        float rate = newState == PlaybackState.PLAYSTATE_PLAYING ? 1 : 0;
+        float rate = newState == PlaybackState.STATE_PLAYING ? 1 : 0;
         long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
         mPlaybackState.setState(newState, position, rate);
-        mPerformer.setPlaybackState(mPlaybackState);
+        mSession.setPlaybackState(mPlaybackState);
     }
 
     public interface Listener {
@@ -135,11 +132,11 @@
         @Override
         public void onError(int type, int extra, Bundle extras, Throwable error) {
             Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
-            mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, -1, 0);
+            mPlaybackState.setState(PlaybackState.STATE_ERROR, -1, 0);
             if (error != null) {
                 mPlaybackState.setErrorMessage(error.getLocalizedMessage());
             }
-            mPerformer.setPlaybackState(mPlaybackState);
+            mSession.setPlaybackState(mPlaybackState);
             if (mListener != null) {
                 mListener.onPlayStateChanged(mPlaybackState);
             }
@@ -157,27 +154,27 @@
             switch (newState) {
                 case Renderer.STATE_ENDED:
                 case Renderer.STATE_STOPPED:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED, position, 0);
+                    mPlaybackState.setState(PlaybackState.STATE_STOPPED, position, 0);
                     break;
                 case Renderer.STATE_INIT:
                 case Renderer.STATE_PREPARING:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING, position, 0);
+                    mPlaybackState.setState(PlaybackState.STATE_BUFFERING, position, 0);
                     break;
                 case Renderer.STATE_ERROR:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
+                    mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
                     break;
                 case Renderer.STATE_PAUSED:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, position, 0);
+                    mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0);
                     break;
                 case Renderer.STATE_PLAYING:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING, position, 1);
+                    mPlaybackState.setState(PlaybackState.STATE_PLAYING, position, 1);
                     break;
                 default:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
+                    mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
                     mPlaybackState.setErrorMessage("unkown state");
                     break;
             }
-            mPerformer.setPlaybackState(mPlaybackState);
+            mSession.setPlaybackState(mPlaybackState);
             if (mListener != null) {
                 mListener.onPlayStateChanged(mPlaybackState);
             }
@@ -191,8 +188,8 @@
         public void onFocusLost() {
             Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
             long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
-            mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, position, 0);
-            mPerformer.setPlaybackState(mPlaybackState);
+            mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0);
+            mSession.setPlaybackState(mPlaybackState);
             if (mListener != null) {
                 mListener.onPlayStateChanged(mPlaybackState);
             }
@@ -206,7 +203,7 @@
 
     private class SessionCb extends MediaSession.Callback {
         @Override
-        public void onMediaButton(Intent mediaRequestIntent) {
+        public void onMediaButtonEvent(Intent mediaRequestIntent) {
             if (Intent.ACTION_MEDIA_BUTTON.equals(mediaRequestIntent.getAction())) {
                 KeyEvent event = (KeyEvent) mediaRequestIntent
                         .getParcelableExtra(Intent.EXTRA_KEY_EVENT);
@@ -233,12 +230,12 @@
                 mRoute = null;
                 mRenderer = new LocalRenderer(mContext, null);
                 mRenderer.registerListener(mRenderListener);
-                updateState(PlaybackState.PLAYSTATE_NONE);
+                updateState(PlaybackState.STATE_NONE);
             } else {
                 // Use remote route
                 mSession.connect(route, mRouteOptions.get(0));
                 mRenderer = null;
-                updateState(PlaybackState.PLAYSTATE_CONNECTING);
+                updateState(PlaybackState.STATE_CONNECTING);
             }
         }
 
@@ -249,7 +246,7 @@
             mRouteControls.addListener(mRouteListener);
             Log.d(TAG, "Connected to route, registering listener");
             mRenderer = new OneMRPRenderer(mRouteControls);
-            updateState(PlaybackState.PLAYSTATE_NONE);
+            updateState(PlaybackState.STATE_NONE);
         }
 
         @Override
@@ -258,7 +255,7 @@
         }
     }
 
-    private class TransportListener extends TransportPerformer.Listener {
+    private class TransportListener extends MediaSession.TransportControlsCallback {
         @Override
         public void onPlay() {
             mRenderer.onPlay();
diff --git a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
index 6537d49..f2d691c 100644
--- a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
+++ b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
@@ -149,7 +149,7 @@
         public void onError(int type, int extra, Bundle extras, Throwable error) {
             Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
             if (mControls != null) {
-                mControls.sendPlaybackChangeEvent(PlaybackState.PLAYSTATE_ERROR);
+                mControls.sendPlaybackChangeEvent(PlaybackState.STATE_ERROR);
             }
         }
 
@@ -165,23 +165,23 @@
             switch (newState) {
                 case Renderer.STATE_ENDED:
                 case Renderer.STATE_STOPPED:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED, position, 0);
+                    mPlaybackState.setState(PlaybackState.STATE_STOPPED, position, 0);
                     break;
                 case Renderer.STATE_INIT:
                 case Renderer.STATE_PREPARING:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING, position, 0);
+                    mPlaybackState.setState(PlaybackState.STATE_BUFFERING, position, 0);
                     break;
                 case Renderer.STATE_ERROR:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
+                    mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
                     break;
                 case Renderer.STATE_PAUSED:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, position, 0);
+                    mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0);
                     break;
                 case Renderer.STATE_PLAYING:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING, position, 1);
+                    mPlaybackState.setState(PlaybackState.STATE_PLAYING, position, 1);
                     break;
                 default:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
+                    mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
                     mPlaybackState.setErrorMessage("unkown state");
                     break;
             }
@@ -196,7 +196,7 @@
         @Override
         public void onFocusLost() {
             Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
-            mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, mRenderer.getSeekPosition(), 0);
+            mPlaybackState.setState(PlaybackState.STATE_PAUSED, mRenderer.getSeekPosition(), 0);
             mRenderer.onPause();
         }