Merge "Workaround double-translate bug"
diff --git a/Android.mk b/Android.mk
index 19ee855..9828ea6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -326,7 +326,6 @@
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
-	telephony/java/com/android/internal/telephony/ITelephonyListener.aidl \
 	telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl \
 	telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl \
 	telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index 128c4d2..eda087d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27,7 +27,6 @@
     field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
-    field public static final java.lang.String BIND_ROUTE_PROVIDER = "android.permission.BIND_ROUTE_PROVIDER";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
@@ -14246,6 +14245,49 @@
     field public static final java.lang.String KEY_WIDTH = "width";
   }
 
+  public final class MediaMetadata implements android.os.Parcelable {
+    method public boolean containsKey(java.lang.String);
+    method public int describeContents();
+    method public android.graphics.Bitmap getBitmap(java.lang.String);
+    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 int size();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+    field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
+    field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+    field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+    field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
+    field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+    field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+    field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
+    field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+    field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+    field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+  }
+
+  public static final class MediaMetadata.Builder {
+    ctor public MediaMetadata.Builder();
+    ctor public MediaMetadata.Builder(android.media.MediaMetadata);
+    method public android.media.MediaMetadata build();
+    method public android.media.MediaMetadata.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
+    method public android.media.MediaMetadata.Builder putLong(java.lang.String, long);
+    method public android.media.MediaMetadata.Builder putRating(java.lang.String, android.media.Rating);
+    method public android.media.MediaMetadata.Builder putString(java.lang.String, java.lang.String);
+  }
+
   public abstract class MediaMetadataEditor {
     method public synchronized void addEditableKey(int);
     method public abstract void apply();
@@ -15341,109 +15383,61 @@
 
 }
 
-package android.media.routeprovider {
-
-  public final class RouteConnection {
-    ctor public RouteConnection(android.media.routeprovider.RouteProviderService, android.media.session.RouteInfo);
-    method public android.media.routeprovider.RouteInterfaceHandler addRouteInterface(java.lang.String);
-    method public android.media.routeprovider.RouteInterfaceHandler getRouteInterface(java.lang.String);
-    method public void shutDown();
-  }
-
-  public final class RouteInterfaceHandler {
-    method public void addListener(android.media.routeprovider.RouteInterfaceHandler.CommandListener, android.os.Handler);
-    method public java.lang.String getName();
-    method public void removeListener(android.media.routeprovider.RouteInterfaceHandler.CommandListener);
-    method public void sendEvent(java.lang.String, android.os.Bundle);
-    method public static void sendResult(android.os.ResultReceiver, int, android.os.Bundle);
-  }
-
-  public static abstract class RouteInterfaceHandler.CommandListener {
-    ctor public RouteInterfaceHandler.CommandListener();
-    method public abstract boolean onCommand(android.media.routeprovider.RouteInterfaceHandler, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-  }
-
-  public final class RoutePlaybackControlsHandler {
-    method public void addListener(android.media.routeprovider.RoutePlaybackControlsHandler.Listener);
-    method public void addListener(android.media.routeprovider.RoutePlaybackControlsHandler.Listener, android.os.Handler);
-    method public static android.media.routeprovider.RoutePlaybackControlsHandler addTo(android.media.routeprovider.RouteConnection);
-    method public void removeListener(android.media.routeprovider.RoutePlaybackControlsHandler.Listener);
-    method public void sendPlaybackChangeEvent(int);
-  }
-
-  public static abstract class RoutePlaybackControlsHandler.Listener extends android.media.routeprovider.RouteInterfaceHandler.CommandListener {
-    ctor public RoutePlaybackControlsHandler.Listener();
-    method public boolean fastForward();
-    method public long getCapabilities();
-    method public long getCurrentPosition();
-    method public final boolean onCommand(android.media.routeprovider.RouteInterfaceHandler, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-    method public boolean pause();
-    method public void playNow(java.lang.String, android.os.ResultReceiver);
-    method public boolean resume();
-  }
-
-  public abstract class RouteProviderService extends android.app.Service {
-    ctor public RouteProviderService();
-    method public abstract android.media.routeprovider.RouteConnection connect(android.media.session.RouteInfo, android.media.routeprovider.RouteRequest);
-    method public abstract java.util.List<android.media.session.RouteInfo> getMatchingRoutes(java.util.List<android.media.routeprovider.RouteRequest>);
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public void updateDiscoveryRequests(java.util.List<android.media.routeprovider.RouteRequest>);
-    field public static final java.lang.String SERVICE_INTERFACE = "com.android.media.session.MediaRouteProvider";
-  }
-
-  public final class RouteRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method public android.media.session.RouteOptions getConnectionOptions();
-    method public android.media.session.SessionInfo getSessionInfo();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-}
-
 package android.media.session {
 
-  public final class MediaMetadata implements android.os.Parcelable {
-    method public boolean containsKey(java.lang.String);
-    method public int describeContents();
-    method public android.graphics.Bitmap getBitmap(java.lang.String);
-    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 int size();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
-    field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
-    field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
-    field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
-    field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
-    field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
-    field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
-    field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
-    field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
-    field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
-    field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
-    field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
-    field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
-    field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
-    field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
-    field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
-    field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
-    field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+  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 static android.media.session.MediaController fromToken(android.media.session.MediaSessionToken);
+    method public android.media.session.TransportController getTransportController();
+    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);
   }
 
-  public static final class MediaMetadata.Builder {
-    ctor public MediaMetadata.Builder();
-    ctor public MediaMetadata.Builder(android.media.session.MediaMetadata);
-    method public android.media.session.MediaMetadata build();
-    method public android.media.session.MediaMetadata.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
-    method public android.media.session.MediaMetadata.Builder putLong(java.lang.String, long);
-    method public android.media.session.MediaMetadata.Builder putRating(java.lang.String, android.media.Rating);
-    method public android.media.session.MediaMetadata.Builder putString(java.lang.String, java.lang.String);
+  public static abstract class MediaController.Callback {
+    ctor public MediaController.Callback();
+    method public void onEvent(java.lang.String, android.os.Bundle);
+  }
+
+  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 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 setActive(boolean);
+    method public void setFlags(int);
+    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);
+  }
+
+  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 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 {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
   }
 
   public final class PlaybackState implements android.os.Parcelable {
@@ -15474,7 +15468,6 @@
     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_CONNECTING = 8; // 0x8
     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
@@ -15486,160 +15479,11 @@
     field public static final int PLAYSTATE_STOPPED = 1; // 0x1
   }
 
-  public final class Route {
-    method public android.media.session.RouteInterface getInterface(java.lang.String);
-    method public android.media.session.RouteOptions getOptions();
-    method public android.media.session.RouteInfo getRouteInfo();
-  }
-
-  public final class RouteInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.util.List<android.media.session.RouteOptions> getConnectionMethods();
-    method public java.lang.String getId();
-    method public java.lang.String getName();
-    method public java.lang.String getProvider();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public static final class RouteInfo.Builder {
-    ctor public RouteInfo.Builder(android.media.session.RouteInfo);
-    ctor public RouteInfo.Builder();
-    method public android.media.session.RouteInfo.Builder addRouteOptions(android.media.session.RouteOptions);
-    method public android.media.session.RouteInfo build();
-    method public android.media.session.RouteInfo.Builder clearRouteOptions();
-    method public int getOptionsSize();
-    method public android.media.session.RouteInfo.Builder setId(java.lang.String);
-    method public android.media.session.RouteInfo.Builder setName(java.lang.String);
-  }
-
-  public final class RouteInterface {
-    method public void addListener(android.media.session.RouteInterface.EventListener);
-    method public void addListener(android.media.session.RouteInterface.EventListener, android.os.Handler);
-    method public void removeListener(android.media.session.RouteInterface.EventListener);
-    method public boolean sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-    field public static final int RESULT_COMMAND_NOT_SUPPORTED = -3; // 0xfffffffd
-    field public static final int RESULT_ERROR = -1; // 0xffffffff
-    field public static final int RESULT_INTERFACE_NOT_SUPPORTED = -2; // 0xfffffffe
-    field public static final int RESULT_NOT_CONNECTED = -5; // 0xfffffffb
-    field public static final int RESULT_ROUTE_IS_STALE = -4; // 0xfffffffc
-    field public static final int RESULT_SUCCESS = 1; // 0x1
-  }
-
-  public static abstract class RouteInterface.EventListener {
-    ctor public RouteInterface.EventListener();
-    method public abstract void onEvent(java.lang.String, android.os.Bundle);
-  }
-
-  public final class RouteOptions implements android.os.Parcelable {
-    method public int describeContents();
-    method public android.os.Bundle getConnectionParams();
-    method public java.util.List<java.lang.String> getInterfaceNames();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public static final class RouteOptions.Builder {
-    ctor public RouteOptions.Builder();
-    method public android.media.session.RouteOptions.Builder addInterface(java.lang.String);
-    method public android.media.session.RouteOptions build();
-    method public android.media.session.RouteOptions.Builder setParameters(android.os.Bundle);
-  }
-
-  public final class RoutePlaybackControls {
-    method public void addListener(android.media.session.RoutePlaybackControls.Listener);
-    method public void addListener(android.media.session.RoutePlaybackControls.Listener, android.os.Handler);
-    method public void fastForward();
-    method public static android.media.session.RoutePlaybackControls from(android.media.session.Route);
-    method public void getCapabilities(android.os.ResultReceiver);
-    method public void getCurrentPosition(android.os.ResultReceiver);
-    method public void pause();
-    method public void playNow(java.lang.String);
-    method public void removeListener(android.media.session.RoutePlaybackControls.Listener);
-    method public void resume();
-    field public static final java.lang.String NAME = "android.media.session.RoutePlaybackControls";
-  }
-
-  public static abstract class RoutePlaybackControls.Listener extends android.media.session.RouteInterface.EventListener {
-    ctor public RoutePlaybackControls.Listener();
-    method public final void onEvent(java.lang.String, android.os.Bundle);
-    method public void onMetadataUpdate(android.media.session.MediaMetadata);
-    method public void onPlaybackStateChange(int);
-  }
-
-  public final class Session {
-    method public void addCallback(android.media.session.Session.Callback);
-    method public void addCallback(android.media.session.Session.Callback, android.os.Handler);
-    method public void connect(android.media.session.RouteInfo, android.media.session.RouteOptions);
-    method public void disconnect();
-    method public android.media.session.SessionToken getSessionToken();
-    method public android.media.session.TransportPerformer getTransportPerformer();
-    method public boolean isActive();
-    method public void release();
-    method public void removeCallback(android.media.session.Session.Callback);
-    method public void sendEvent(java.lang.String, android.os.Bundle);
-    method public void setActive(boolean);
-    method public void setFlags(int);
-    method public void setRouteOptions(java.util.List<android.media.session.RouteOptions>);
-    field public static final int DISCONNECT_REASON_PROVIDER_DISCONNECTED = 2; // 0x2
-    field public static final int DISCONNECT_REASON_ROUTE_CHANGED = 3; // 0x3
-    field public static final int DISCONNECT_REASON_SESSION_DESTROYED = 5; // 0x5
-    field public static final int DISCONNECT_REASON_SESSION_DISCONNECTED = 4; // 0x4
-    field public static final int DISCONNECT_REASON_USER_STOPPING = 1; // 0x1
-    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 Session.Callback {
-    ctor public Session.Callback();
-    method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-    method public void onMediaButton(android.content.Intent);
-    method public void onRequestRouteChange(android.media.session.RouteInfo);
-    method public void onRouteConnected(android.media.session.Route);
-    method public void onRouteDisconnected(android.media.session.Route, int);
-  }
-
-  public final class SessionController {
-    method public void addCallback(android.media.session.SessionController.Callback);
-    method public void addCallback(android.media.session.SessionController.Callback, android.os.Handler);
-    method public static android.media.session.SessionController fromToken(android.media.session.SessionToken);
-    method public android.media.session.TransportController getTransportController();
-    method public void removeCallback(android.media.session.SessionController.Callback);
-    method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-    method public void sendMediaButton(int);
-    method public void showRoutePicker();
-  }
-
-  public static abstract class SessionController.Callback {
-    ctor public SessionController.Callback();
-    method public void onEvent(java.lang.String, android.os.Bundle);
-    method public void onRouteChanged(android.media.session.RouteInfo);
-  }
-
-  public final class SessionInfo 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 final class SessionManager {
-    method public android.media.session.Session createSession(java.lang.String);
-    method public java.util.List<android.media.session.SessionController> getActiveSessions(android.content.ComponentName);
-  }
-
-  public class SessionToken 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;
-  }
-
   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.session.MediaMetadata getMetadata();
+    method public android.media.MediaMetadata getMetadata();
     method public android.media.session.PlaybackState getPlaybackState();
     method public int getRatingType();
     method public void next();
@@ -15655,7 +15499,7 @@
 
   public static abstract class TransportController.TransportStateListener {
     ctor public TransportController.TransportStateListener();
-    method public void onMetadataChanged(android.media.session.MediaMetadata);
+    method public void onMetadataChanged(android.media.MediaMetadata);
     method public void onPlaybackStateChanged(android.media.session.PlaybackState);
   }
 
@@ -15663,7 +15507,7 @@
     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.session.MediaMetadata);
+    method public final void setMetadata(android.media.MediaMetadata);
     method public final void setPlaybackState(android.media.session.PlaybackState);
   }
 
@@ -15816,18 +15660,23 @@
     method public android.net.NetworkInfo getActiveNetworkInfo();
     method public android.net.NetworkInfo[] getAllNetworkInfo();
     method public deprecated boolean getBackgroundDataSetting();
-    method public android.net.ProxyInfo getGlobalProxy();
+    method public android.net.LinkProperties getLinkProperties(android.net.Network);
+    method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
     method public android.net.NetworkInfo getNetworkInfo(int);
-    method public int getNetworkPreference();
+    method public deprecated int getNetworkPreference();
     method public boolean isActiveNetworkMetered();
     method public boolean isNetworkActive();
     method public static boolean isNetworkTypeValid(int);
+    method public android.net.NetworkRequest listenForNetwork(android.net.NetworkCapabilities, android.net.ConnectivityManager.NetworkCallbackListener);
     method public void registerNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
-    method public boolean requestRouteToHost(int, int);
-    method public void setGlobalProxy(android.net.ProxyInfo);
-    method public void setNetworkPreference(int);
-    method public int startUsingNetworkFeature(int, java.lang.String);
-    method public int stopUsingNetworkFeature(int, java.lang.String);
+    method public void releaseNetworkRequest(android.net.NetworkRequest);
+    method public void reportBadNetwork(android.net.Network);
+    method public android.net.NetworkRequest requestNetwork(android.net.NetworkCapabilities, android.net.ConnectivityManager.NetworkCallbackListener);
+    method public android.net.NetworkRequest requestNetwork(android.net.NetworkCapabilities, android.app.PendingIntent);
+    method public deprecated boolean requestRouteToHost(int, int);
+    method public deprecated void setNetworkPreference(int);
+    method public deprecated int startUsingNetworkFeature(int, java.lang.String);
+    method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
     method public void unregisterNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
     field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
     field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
@@ -15835,6 +15684,8 @@
     field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
     field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
     field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
+    field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork";
+    field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES = "networkRequestNetworkCapabilities";
     field public static final java.lang.String EXTRA_NETWORK_TYPE = "networkType";
     field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
     field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
@@ -15851,6 +15702,16 @@
     field public static final int TYPE_WIMAX = 6; // 0x6
   }
 
+  public static class ConnectivityManager.NetworkCallbackListener {
+    ctor public ConnectivityManager.NetworkCallbackListener();
+    method public void onAvailable(android.net.NetworkRequest, android.net.Network);
+    method public void onLinkPropertiesChanged(android.net.NetworkRequest, android.net.Network, android.net.LinkProperties);
+    method public void onLosing(android.net.NetworkRequest, android.net.Network, int);
+    method public void onLost(android.net.NetworkRequest, android.net.Network);
+    method public void onNetworkCapabilitiesChanged(android.net.NetworkRequest, android.net.Network, android.net.NetworkCapabilities);
+    method public void onReleased(android.net.NetworkRequest);
+  }
+
   public static abstract interface ConnectivityManager.OnNetworkActiveListener {
     method public abstract void onNetworkActive();
   }
@@ -15885,6 +15746,38 @@
     method public void writeToParcel(android.os.Parcel, int);
   }
 
+  public class LinkProperties implements android.os.Parcelable {
+    ctor public LinkProperties();
+    ctor public LinkProperties(android.net.LinkProperties);
+    method public void addDns(java.net.InetAddress);
+    method public boolean addLinkAddress(android.net.LinkAddress);
+    method public void addRoute(android.net.RouteInfo);
+    method public void clear();
+    method public int describeContents();
+    method public java.util.Collection<java.lang.String> getAllInterfaceNames();
+    method public java.util.Collection<java.net.InetAddress> getDnses();
+    method public java.lang.String getDomains();
+    method public android.net.ProxyInfo getHttpProxy();
+    method public java.lang.String getInterfaceName();
+    method public java.util.Collection<android.net.LinkAddress> getLinkAddresses();
+    method public java.util.Collection<android.net.RouteInfo> getRoutes();
+    method public boolean hasIPv4Address();
+    method public boolean hasIPv6Address();
+    method public boolean removeLinkAddress(android.net.LinkAddress);
+    method public void setDomains(java.lang.String);
+    method public void setHttpProxy(android.net.ProxyInfo);
+    method public void setInterfaceName(java.lang.String);
+    method public void setLinkAddresses(java.util.Collection<android.net.LinkAddress>);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static class LinkProperties.CompareResult {
+    ctor public LinkProperties.CompareResult();
+    field public java.util.Collection added;
+    field public java.util.Collection removed;
+  }
+
   public class LocalServerSocket {
     ctor public LocalServerSocket(java.lang.String) throws java.io.IOException;
     ctor public LocalServerSocket(java.io.FileDescriptor) throws java.io.IOException;
@@ -15953,6 +15846,56 @@
     field public static final java.lang.String MAILTO_SCHEME = "mailto:";
   }
 
+  public class Network implements android.os.Parcelable {
+    method public void bindProcess();
+    method public int describeContents();
+    method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
+    method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException;
+    method public static android.net.Network getProcessBoundNetwork();
+    method public javax.net.SocketFactory socketFactory();
+    method public static void unbindProcess();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public final class NetworkCapabilities implements android.os.Parcelable {
+    ctor public NetworkCapabilities();
+    ctor public NetworkCapabilities(android.net.NetworkCapabilities);
+    method public void addNetworkCapability(int);
+    method public void addTransportType(int);
+    method public int describeContents();
+    method public int getLinkDownstreamBandwidthKbps();
+    method public int getLinkUpstreamBandwidthKbps();
+    method public java.util.Collection<java.lang.Integer> getNetworkCapabilities();
+    method public java.util.Collection<java.lang.Integer> getTransportTypes();
+    method public boolean hasCapability(int);
+    method public boolean hasTransport(int);
+    method public void removeNetworkCapability(int);
+    method public void removeTransportType(int);
+    method public void setLinkDownstreamBandwidthKbps(int);
+    method public void setLinkUpstreamBandwidthKbps(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int NET_CAPABILITY_CBS = 5; // 0x5
+    field public static final int NET_CAPABILITY_DUN = 2; // 0x2
+    field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
+    field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
+    field public static final int NET_CAPABILITY_IA = 7; // 0x7
+    field public static final int NET_CAPABILITY_IMS = 4; // 0x4
+    field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
+    field public static final int NET_CAPABILITY_MMS = 0; // 0x0
+    field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
+    field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+    field public static final int NET_CAPABILITY_RCS = 8; // 0x8
+    field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
+    field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
+    field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
+    field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
+    field public static final int TRANSPORT_CELLULAR = 0; // 0x0
+    field public static final int TRANSPORT_ETHERNET = 3; // 0x3
+    field public static final int TRANSPORT_WIFI = 1; // 0x1
+  }
+
   public class NetworkInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.net.NetworkInfo.DetailedState getDetailedState();
@@ -16000,6 +15943,13 @@
     enum_constant public static final android.net.NetworkInfo.State UNKNOWN;
   }
 
+  public class NetworkRequest 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;
+    field public final android.net.NetworkCapabilities networkCapabilities;
+  }
+
   public class ParseException extends java.lang.RuntimeException {
     field public java.lang.String response;
   }
@@ -16027,6 +15977,7 @@
   }
 
   public class RouteInfo implements android.os.Parcelable {
+    ctor public RouteInfo(android.net.LinkAddress, java.net.InetAddress, java.lang.String);
     ctor public RouteInfo(android.net.LinkAddress, java.net.InetAddress);
     ctor public RouteInfo(java.net.InetAddress);
     ctor public RouteInfo(android.net.LinkAddress);
@@ -16034,9 +15985,8 @@
     method public android.net.LinkAddress getDestination();
     method public java.net.InetAddress getGateway();
     method public java.lang.String getInterface();
-    method public boolean hasGateway();
     method public boolean isDefaultRoute();
-    method public boolean isHostRoute();
+    method public boolean matches(java.net.InetAddress);
     method public void writeToParcel(android.os.Parcel, int);
   }
 
@@ -26738,6 +26688,83 @@
     enum_constant public static final android.telecomm.CallState RINGING;
   }
 
+  public abstract class Connection {
+    ctor protected Connection();
+    method public final android.telecomm.CallAudioState getCallAudioState();
+    method public final android.net.Uri getHandle();
+    method protected void onAbort();
+    method protected void onAnswer();
+    method protected void onDisconnect();
+    method protected void onHold();
+    method protected void onPlayDtmfTone(char);
+    method protected void onReject();
+    method protected void onSetAudioState(android.telecomm.CallAudioState);
+    method protected void onSetSignal(android.os.Bundle);
+    method protected void onStopDtmfTone();
+    method protected void onUnhold();
+    method protected void setActive();
+    method public void setAudioState(android.telecomm.CallAudioState);
+    method protected void setDialing();
+    method protected void setDisconnected(int, java.lang.String);
+    method protected void setHandle(android.net.Uri);
+    method protected void setOnHold();
+    method protected void setRinging();
+    method public static java.lang.String stateToString(int);
+  }
+
+  public static abstract interface Connection.Listener {
+    method public abstract void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+    method public abstract void onDestroyed(android.telecomm.Connection);
+    method public abstract void onDisconnected(android.telecomm.Connection, int, java.lang.String);
+    method public abstract void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+    method public abstract void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
+    method public abstract void onStateChanged(android.telecomm.Connection, int);
+  }
+
+  public static class Connection.ListenerBase implements android.telecomm.Connection.Listener {
+    ctor public Connection.ListenerBase();
+    method public void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+    method public void onDestroyed(android.telecomm.Connection);
+    method public void onDisconnected(android.telecomm.Connection, int, java.lang.String);
+    method public void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+    method public void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
+    method public void onStateChanged(android.telecomm.Connection, int);
+  }
+
+  public final class Connection.State {
+    field public static final int ACTIVE = 3; // 0x3
+    field public static final int DIALING = 2; // 0x2
+    field public static final int DISCONNECTED = 5; // 0x5
+    field public static final int HOLDING = 4; // 0x4
+    field public static final int NEW = 0; // 0x0
+    field public static final int RINGING = 1; // 0x1
+  }
+
+  public final class ConnectionRequest {
+    ctor public ConnectionRequest(android.net.Uri, android.os.Bundle);
+    method public android.os.Bundle getExtras();
+    method public android.net.Uri getHandle();
+  }
+
+  public abstract class ConnectionService extends android.telecomm.CallService {
+    ctor public ConnectionService();
+    method public final void abort(java.lang.String);
+    method public final void answer(java.lang.String);
+    method public final void call(android.telecomm.CallInfo);
+    method public final void disconnect(java.lang.String);
+    method public final void hold(java.lang.String);
+    method public final void isCompatibleWith(android.telecomm.CallInfo);
+    method public final void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
+    method public void onCreateConnections(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
+    method public void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
+    method public void onFindSubscriptions(android.net.Uri, android.telecomm.Response<android.net.Uri, android.telecomm.Subscription>);
+    method public final void playDtmfTone(java.lang.String, char);
+    method public final void reject(java.lang.String);
+    method public final void setIncomingCallId(java.lang.String, android.os.Bundle);
+    method public final void stopDtmfTone(java.lang.String);
+    method public final void unhold(java.lang.String);
+  }
+
   public class GatewayInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.net.Uri getGatewayHandle();
@@ -26789,6 +26816,18 @@
     method protected abstract void updateCall(android.telecomm.InCallCall);
   }
 
+  public abstract interface Response {
+    method public abstract void onError(IN, java.lang.String);
+    method public abstract void onResult(IN, OUT...);
+  }
+
+  public class Subscription implements android.os.Parcelable {
+    ctor public Subscription();
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public final class TelecommConstants {
     ctor public TelecommConstants();
     field public static final java.lang.String ACTION_CALL_SERVICE;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 71e4e82..5fd288f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3010,19 +3010,10 @@
                 int h;
                 if (w < 0) {
                     Resources res = r.activity.getResources();
-                    Configuration config = res.getConfiguration();
-                    boolean useAlternateRecents = (config.smallestScreenWidthDp < 600);
-                    if (useAlternateRecents) {
-                        int wId = com.android.internal.R.dimen.recents_thumbnail_width;
-                        int hId = com.android.internal.R.dimen.recents_thumbnail_height;
-                        mThumbnailWidth = w = res.getDimensionPixelSize(wId);
-                        mThumbnailHeight = h = res.getDimensionPixelSize(hId);
-                    } else {
-                        mThumbnailHeight = h =
-                            res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
-                        mThumbnailWidth = w =
-                            res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
-                    }
+                    int wId = com.android.internal.R.dimen.recents_thumbnail_width;
+                    int hId = com.android.internal.R.dimen.recents_thumbnail_height;
+                    mThumbnailWidth = w = res.getDimensionPixelSize(wId);
+                    mThumbnailHeight = h = res.getDimensionPixelSize(hId);
                 } else {
                     h = mThumbnailHeight;
                 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index ca6b008..6324d4c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -70,7 +70,7 @@
 import android.location.LocationManager;
 import android.media.AudioManager;
 import android.media.MediaRouter;
-import android.media.session.SessionManager;
+import android.media.session.MediaSessionManager;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.INetworkPolicyManager;
@@ -657,7 +657,7 @@
 
         registerService(MEDIA_SESSION_SERVICE, new ServiceFetcher() {
             public Object createService(ContextImpl ctx) {
-                return new SessionManager(ctx);
+                return new MediaSessionManager(ctx);
             }
         });
         registerService(TRUST_SERVICE, new ServiceFetcher() {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f7f51fe..c11b04c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2422,10 +2422,10 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
-     * {@link android.media.session.SessionManager} for managing media Sessions.
+     * {@link android.media.session.MediaSessionManager} for managing media Sessions.
      *
      * @see #getSystemService
-     * @see android.media.session.SessionManager
+     * @see android.media.session.MediaSessionManager
      */
     public static final String MEDIA_SESSION_SERVICE = "media_session";
 
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a414421..1837335 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -21,6 +21,7 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
 import android.os.Handler;
@@ -57,13 +58,15 @@
  * is lost</li>
  * <li>Provide an API that allows applications to query the coarse-grained or fine-grained
  * state of the available networks</li>
+ * <li>Provide an API that allows applications to request and select networks for their data
+ * traffic</li>
  * </ol>
  */
 public class ConnectivityManager {
     private static final String TAG = "ConnectivityManager";
 
     /**
-     * A change in network connectivity has occurred. A connection has either
+     * A change in network connectivity has occurred. A default connection has either
      * been established or lost. The NetworkInfo for the affected network is
      * sent as an extra; it should be consulted to see what kind of
      * connectivity event occurred.
@@ -547,13 +550,12 @@
      * @param preference the network type to prefer over all others.  It is
      *         unspecified what happens to the old preferred network in the
      *         overall ordering.
+     * @deprecated Functionality has been removed as it no longer makes sense,
+     *             with many more than two networks - we'd need an array to express
+     *             preference.  Instead we use dynamic network properties of
+     *             the networks to describe their precedence.
      */
     public void setNetworkPreference(int preference) {
-        // TODO - deprecate with:
-        // @deprecated Functionality has been removed as it no longer makes sense,
-        //         with many more than two networks - we'd need an array to express
-        //         preference.  Instead we use dynamic network properties of
-        //         the networks to describe their precedence.
     }
 
     /**
@@ -563,14 +565,13 @@
      *
      * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     * @deprecated Functionality has been removed as it no longer makes sense,
+     *             with many more than two networks - we'd need an array to express
+     *             preference.  Instead we use dynamic network properties of
+     *             the networks to describe their precedence.
      */
     public int getNetworkPreference() {
-        // TODO - deprecate with:
-        // @deprecated Functionality has been removed as it no longer makes sense,
-        //         with many more than two networks - we'd need an array to express
-        //         preference.  Instead we use dynamic network properties of
-        //         the networks to describe their precedence.
-        return -1;
+        return TYPE_NONE;
     }
 
     /**
@@ -716,7 +717,13 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Get the {@link LinkProperties} for the given {@link Network}.  This
+     * will return {@code null} if the network is unknown.
+     *
+     * @param network The {@link Network} object identifying the network in question.
+     * @return The {@link LinkProperties} for the network, or {@code null}.
+     **/
     public LinkProperties getLinkProperties(Network network) {
         try {
             return mService.getLinkProperties(network);
@@ -725,7 +732,13 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Get the {@link NetworkCapabilities} for the given {@link Network}.  This
+     * will return {@code null} if the network is unknown.
+     *
+     * @param network The {@link Network} object identifying the network in question.
+     * @return The {@link NetworkCapabilities} for the network, or {@code null}.
+     */
     public NetworkCapabilities getNetworkCapabilities(Network network) {
         try {
             return mService.getNetworkCapabilities(network);
@@ -788,6 +801,8 @@
      * The interpretation of this value is specific to each networking
      * implementation+feature combination, except that the value {@code -1}
      * always indicates failure.
+     *
+     * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api.
      */
     public int startUsingNetworkFeature(int networkType, String feature) {
         try {
@@ -810,6 +825,8 @@
      * The interpretation of this value is specific to each networking
      * implementation+feature combination, except that the value {@code -1}
      * always indicates failure.
+     *
+     * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api.
      */
     public int stopUsingNetworkFeature(int networkType, String feature) {
         try {
@@ -829,6 +846,9 @@
      * host is to be routed
      * @param hostAddress the IP address of the host to which the route is desired
      * @return {@code true} on success, {@code false} on failure
+     *
+     * @deprecated Deprecated in favor of the {@link #requestNetwork},
+     *             {@link Network#bindProcess} and {@link Network#socketFactory} api.
      */
     public boolean requestRouteToHost(int networkType, int hostAddress) {
         InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
@@ -851,6 +871,8 @@
      * @param hostAddress the IP address of the host to which the route is desired
      * @return {@code true} on success, {@code false} on failure
      * @hide
+     * @deprecated Deprecated in favor of the {@link #requestNetwork} and
+     *             {@link Network#bindProcess} api.
      */
     public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
         byte[] address = hostAddress.getAddress();
@@ -1332,13 +1354,13 @@
     }
 
     /**
-     * Report a problem network to the framework.  This will cause the framework
-     * to evaluate the situation and try to fix any problems.  Note that false
-     * may be subsequently ignored.
+     * Report a problem network to the framework.  This provides a hint to the system
+     * that there might be connectivity problems on this network and may cause 
+     * the framework to re-evaluate network connectivity and/or switch to another
+     * network.
      *
-     * @param network The Network the application was attempting to use or null
-     *                to indicate the current default network.
-     * {@hide}
+     * @param network The {@link Network} the application was attempting to use
+     *                or {@code null} to indicate the current default network.
      */
     public void reportBadNetwork(Network network) {
         try {
@@ -1358,6 +1380,7 @@
      *
      * <p>This method requires the call to hold the permission
      * android.Manifest.permission#CONNECTIVITY_INTERNAL.
+     * @hide
      */
     public void setGlobalProxy(ProxyInfo p) {
         try {
@@ -1374,6 +1397,7 @@
      *
      * <p>This method requires the call to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     * @hide
      */
     public ProxyInfo getGlobalProxy() {
         try {
@@ -1393,6 +1417,7 @@
      * <p>This method requires the call to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
+     * @deprecated Deprecated in favor of {@link #getLinkProperties}
      */
     public ProxyInfo getProxy() {
         try {
@@ -1645,11 +1670,10 @@
     }
 
     /**
-     * Interface for NetworkRequest callbacks.  Used for notifications about network
-     * changes.
-     * @hide
+     * Base class for NetworkRequest callbacks.  Used for notifications about network
+     * changes.  Should be extended by applications wanting notifications.
      */
-    public static class NetworkCallbacks {
+    public static class NetworkCallbackListener {
         /** @hide */
         public static final int PRECHECK     = 1;
         /** @hide */
@@ -1675,51 +1699,73 @@
         public void onPreCheck(NetworkRequest networkRequest, Network network) {}
 
         /**
-         * Called when the framework connects and has validated the new network.
+         * Called when the framework connects and has declared new network ready for use.
+         *
+         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
+         * @param network The {@link Network} of the satisfying network.
          */
         public void onAvailable(NetworkRequest networkRequest, Network network) {}
 
         /**
-         * Called when the framework is losing the network.  Often paired with an
-         * onAvailable call with the new replacement network for graceful handover.
-         * This may not be called if we have a hard loss (loss without warning).
-         * This may be followed by either an onLost call or an onAvailable call for this
-         * network depending on if we lose or regain it.
+         * Called when the network is about to be disconnected.  Often paired with an
+         * {@link NetworkCallbackListener#onAvailable} call with the new replacement network
+         * for graceful handover.  This may not be called if we have a hard loss
+         * (loss without warning).  This may be followed by either a
+         * {@link NetworkCallbackListener#onLost} call or a
+         * {@link NetworkCallbackListener#onAvailable} call for this network depending
+         * on whether we lose or regain it.
+         *
+         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
+         * @param network The {@link Network} of the failing network.
+         * @param maxSecToLive The time in seconds the framework will attempt to keep the
+         *                     network connected.  Note that the network may suffers a
+         *                     hard loss at any time.
          */
         public void onLosing(NetworkRequest networkRequest, Network network, int maxSecToLive) {}
 
         /**
          * Called when the framework has a hard loss of the network or when the
-         * graceful failure ends.  Note applications should only request this callback
-         * if the application is willing to track the Available and Lost callbacks
-         * together, else the application may think it has no network when it
-         * really does (A Avail, B Avail, A Lost..  still have B).
+         * graceful failure ends.
+         *
+         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
+         * @param network The {@link Network} lost.
          */
         public void onLost(NetworkRequest networkRequest, Network network) {}
 
         /**
          * Called if no network is found in the given timeout time.  If no timeout is given,
          * this will not be called.
+         * @hide
          */
         public void onUnavailable(NetworkRequest networkRequest) {}
 
         /**
          * Called when the network the framework connected to for this request
          * changes capabilities but still satisfies the stated need.
+         *
+         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
+         * @param network The {@link Network} whose capabilities have changed.
+         * @param networkCapabilities The new {@link NetworkCapabilities} for this network.
          */
         public void onNetworkCapabilitiesChanged(NetworkRequest networkRequest, Network network,
                 NetworkCapabilities networkCapabilities) {}
 
         /**
          * Called when the network the framework connected to for this request
-         * changes LinkProperties.
+         * changes {@link LinkProperties}.
+         *
+         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
+         * @param network The {@link Network} whose link properties have changed.
+         * @param linkProperties The new {@link LinkProperties} for this network.
          */
         public void onLinkPropertiesChanged(NetworkRequest networkRequest, Network network,
                 LinkProperties linkProperties) {}
 
         /**
-         * Called when a releaseNetworkRequest call concludes and the registered callbacks will
-         * no longer be used.
+         * Called when a {@link #releaseNetworkRequest} call concludes and the registered
+         * callbacks will no longer be used.
+         *
+         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
          */
         public void onReleased(NetworkRequest networkRequest) {}
     }
@@ -1745,12 +1791,12 @@
     public static final int CALLBACK_EXIT               = BASE + 9;
 
     private static class CallbackHandler extends Handler {
-        private final HashMap<NetworkRequest, NetworkCallbacks>mCallbackMap;
+        private final HashMap<NetworkRequest, NetworkCallbackListener>mCallbackMap;
         private final AtomicInteger mRefCount;
         private static final String TAG = "ConnectivityManager.CallbackHandler";
         private final ConnectivityManager mCm;
 
-        CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallbacks>callbackMap,
+        CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallbackListener>callbackMap,
                 AtomicInteger refCount, ConnectivityManager cm) {
             super(looper);
             mCallbackMap = callbackMap;
@@ -1764,7 +1810,7 @@
             switch (message.what) {
                 case CALLBACK_PRECHECK: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbacks callbacks = getCallbacks(request);
+                    NetworkCallbackListener callbacks = getCallbacks(request);
                     if (callbacks != null) {
                         callbacks.onPreCheck(request, getNetwork(message));
                     } else {
@@ -1774,7 +1820,7 @@
                 }
                 case CALLBACK_AVAILABLE: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbacks callbacks = getCallbacks(request);
+                    NetworkCallbackListener callbacks = getCallbacks(request);
                     if (callbacks != null) {
                         callbacks.onAvailable(request, getNetwork(message));
                     } else {
@@ -1784,7 +1830,7 @@
                 }
                 case CALLBACK_LOSING: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbacks callbacks = getCallbacks(request);
+                    NetworkCallbackListener callbacks = getCallbacks(request);
                     if (callbacks != null) {
                         callbacks.onLosing(request, getNetwork(message), message.arg1);
                     } else {
@@ -1794,7 +1840,7 @@
                 }
                 case CALLBACK_LOST: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbacks callbacks = getCallbacks(request);
+                    NetworkCallbackListener callbacks = getCallbacks(request);
                     if (callbacks != null) {
                         callbacks.onLost(request, getNetwork(message));
                     } else {
@@ -1804,7 +1850,7 @@
                 }
                 case CALLBACK_UNAVAIL: {
                     NetworkRequest req = (NetworkRequest)message.obj;
-                    NetworkCallbacks callbacks = null;
+                    NetworkCallbackListener callbacks = null;
                     synchronized(mCallbackMap) {
                         callbacks = mCallbackMap.get(req);
                     }
@@ -1817,7 +1863,7 @@
                 }
                 case CALLBACK_CAP_CHANGED: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbacks callbacks = getCallbacks(request);
+                    NetworkCallbackListener callbacks = getCallbacks(request);
                     if (callbacks != null) {
                         Network network = getNetwork(message);
                         NetworkCapabilities cap = mCm.getNetworkCapabilities(network);
@@ -1830,7 +1876,7 @@
                 }
                 case CALLBACK_IP_CHANGED: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbacks callbacks = getCallbacks(request);
+                    NetworkCallbackListener callbacks = getCallbacks(request);
                     if (callbacks != null) {
                         Network network = getNetwork(message);
                         LinkProperties lp = mCm.getLinkProperties(network);
@@ -1843,7 +1889,7 @@
                 }
                 case CALLBACK_RELEASED: {
                     NetworkRequest req = (NetworkRequest)message.obj;
-                    NetworkCallbacks callbacks = null;
+                    NetworkCallbackListener callbacks = null;
                     synchronized(mCallbackMap) {
                         callbacks = mCallbackMap.remove(req);
                     }
@@ -1870,7 +1916,7 @@
         private NetworkRequest getNetworkRequest(Message msg) {
             return (NetworkRequest)(msg.obj);
         }
-        private NetworkCallbacks getCallbacks(NetworkRequest req) {
+        private NetworkCallbackListener getCallbacks(NetworkRequest req) {
             synchronized(mCallbackMap) {
                 return mCallbackMap.get(req);
             }
@@ -1878,7 +1924,7 @@
         private Network getNetwork(Message msg) {
             return new Network(msg.arg2);
         }
-        private NetworkCallbacks removeCallbacks(Message msg) {
+        private NetworkCallbackListener removeCallbacks(Message msg) {
             NetworkRequest req = (NetworkRequest)msg.obj;
             synchronized(mCallbackMap) {
                 return mCallbackMap.remove(req);
@@ -1893,7 +1939,7 @@
                 HandlerThread callbackThread = new HandlerThread("ConnectivityManager");
                 callbackThread.start();
                 sCallbackHandler = new CallbackHandler(callbackThread.getLooper(),
-                        sNetworkCallbacks, sCallbackRefCount, this);
+                        sNetworkCallbackListener, sCallbackRefCount, this);
             }
         }
     }
@@ -1907,8 +1953,8 @@
         }
     }
 
-    static final HashMap<NetworkRequest, NetworkCallbacks> sNetworkCallbacks =
-            new HashMap<NetworkRequest, NetworkCallbacks>();
+    static final HashMap<NetworkRequest, NetworkCallbackListener> sNetworkCallbackListener =
+            new HashMap<NetworkRequest, NetworkCallbackListener>();
     static final AtomicInteger sCallbackRefCount = new AtomicInteger(0);
     static CallbackHandler sCallbackHandler = null;
 
@@ -1916,9 +1962,11 @@
     private final static int REQUEST = 2;
 
     private NetworkRequest somethingForNetwork(NetworkCapabilities need,
-            NetworkCallbacks networkCallbacks, int timeoutSec, int action) {
+            NetworkCallbackListener networkCallbackListener, int timeoutSec, int action) {
         NetworkRequest networkRequest = null;
-        if (networkCallbacks == null) throw new IllegalArgumentException("null NetworkCallbacks");
+        if (networkCallbackListener == null) {
+            throw new IllegalArgumentException("null NetworkCallbackListener");
+        }
         if (need == null) throw new IllegalArgumentException("null NetworkCapabilities");
         try {
             addCallbackListener();
@@ -1930,8 +1978,8 @@
                         timeoutSec, new Binder());
             }
             if (networkRequest != null) {
-                synchronized(sNetworkCallbacks) {
-                    sNetworkCallbacks.put(networkRequest, networkCallbacks);
+                synchronized(sNetworkCallbackListener) {
+                    sNetworkCallbackListener.put(networkRequest, networkCallbackListener);
                 }
             }
         } catch (RemoteException e) {}
@@ -1943,46 +1991,44 @@
      * Request a network to satisfy a set of {@link NetworkCapabilities}.
      *
      * This {@link NetworkRequest} will live until released via
-     * {@link releaseNetworkRequest} or the calling application exits.
-     * Status of the request can be follwed by listening to the various
-     * callbacks described in {@link NetworkCallbacks}.  The {@link Network}
-     * can be used by using the {@link bindSocketToNetwork},
-     * {@link bindApplicationToNetwork} and {@link getAddrInfoOnNetwork} functions.
+     * {@link #releaseNetworkRequest} or the calling application exits.
+     * Status of the request can be followed by listening to the various
+     * callbacks described in {@link NetworkCallbackListener}.  The {@link Network}
+     * can be used to direct traffic to the network.
      *
      * @param need {@link NetworkCapabilities} required by this request.
-     * @param networkCallbacks The callbacks to be utilized for this request.  Note
-     *                         the callbacks can be shared by multiple requests and
-     *                         the NetworkRequest token utilized to determine to which
-     *                         request the callback relates.
+     * @param networkCallbackListener The {@link NetworkCallbackListener} to be utilized for this
+     *                         request.  Note the callbacks can be shared by multiple
+     *                         requests and the NetworkRequest token utilized to
+     *                         determine to which request the callback relates.
      * @return A {@link NetworkRequest} object identifying the request.
-     * @hide
      */
     public NetworkRequest requestNetwork(NetworkCapabilities need,
-            NetworkCallbacks networkCallbacks) {
-        return somethingForNetwork(need, networkCallbacks, 0, REQUEST);
+            NetworkCallbackListener networkCallbackListener) {
+        return somethingForNetwork(need, networkCallbackListener, 0, REQUEST);
     }
 
     /**
      * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
      * by a timeout.
      *
-     * This function behaves identically, but if a suitable network is not found
-     * within the given time (in Seconds) the {@link NetworkCallbacks#unavailable}
-     * callback is called.  The request must still be released normally by
-     * calling {@link releaseNetworkRequest}.
+     * This function behaves identically to the non-timedout version, but if a suitable
+     * network is not found within the given time (in Seconds) the
+     * {@link NetworkCallbackListener#unavailable} callback is called.  The request must
+     * still be released normally by calling {@link releaseNetworkRequest}.
      * @param need {@link NetworkCapabilities} required by this request.
-     * @param networkCallbacks The callbacks to be utilized for this request.  Note
+     * @param networkCallbackListener The callbacks to be utilized for this request.  Note
      *                         the callbacks can be shared by multiple requests and
      *                         the NetworkRequest token utilized to determine to which
      *                         request the callback relates.
      * @param timeoutSec The time in seconds to attempt looking for a suitable network
-     *                   before {@link NetworkCallbacks#unavailable} is called.
+     *                   before {@link NetworkCallbackListener#unavailable} is called.
      * @return A {@link NetworkRequest} object identifying the request.
      * @hide
      */
     public NetworkRequest requestNetwork(NetworkCapabilities need,
-            NetworkCallbacks networkCallbacks, int timeoutSec) {
-        return somethingForNetwork(need, networkCallbacks, timeoutSec, REQUEST);
+            NetworkCallbackListener networkCallbackListener, int timeoutSec) {
+        return somethingForNetwork(need, networkCallbackListener, timeoutSec, REQUEST);
     }
 
     /**
@@ -1993,36 +2039,52 @@
     public final static int MAX_NETWORK_REQUEST_TIMEOUT_SEC = 100 * 60;
 
     /**
+     * The lookup key for a {@link Network} object included with the intent after
+     * succesfully finding a network for the applications request.  Retrieve it with
+     * {@link android.content.Intent#getParcelableExtra(String)}.
+     */
+    public static final String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork";
+
+    /**
+     * The lookup key for a {@link NetworkCapabilities} object included with the intent after
+     * succesfully finding a network for the applications request.  Retrieve it with
+     * {@link android.content.Intent#getParcelableExtra(String)}.
+     */
+    public static final String EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES =
+            "networkRequestNetworkCapabilities";
+
+
+    /**
      * Request a network to satisfy a set of {@link NetworkCapabilities}.
      *
-     * This function behavies identically, but instead of {@link NetworkCallbacks}
-     * a {@link PendingIntent} is used.  This means the request may outlive the
-     * calling application and get called back when a suitable network is found.
+     * This function behavies identically to the callback-equiped version, but instead
+     * of {@link NetworkCallbackListener} a {@link PendingIntent} is used.  This means
+     * the request may outlive the calling application and get called back when a suitable
+     * network is found.
      * <p>
      * The operation is an Intent broadcast that goes to a broadcast receiver that
      * you registered with {@link Context#registerReceiver} or through the
      * &lt;receiver&gt; tag in an AndroidManifest.xml file
      * <p>
      * The operation Intent is delivered with two extras, a {@link Network} typed
-     * extra called {@link EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities}
-     * typed extra called {@link EXTRA_NETWORK_REQUEST_NETWORK_CAPABILTIES} containing
+     * extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities}
+     * typed extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES} containing
      * the original requests parameters.  It is important to create a new,
-     * {@link NetworkCallbacks} based request before completing the processing of the
+     * {@link NetworkCallbackListener} based request before completing the processing of the
      * Intent to reserve the network or it will be released shortly after the Intent
      * is processed.
      * <p>
      * If there is already an request for this Intent registered (with the equality of
      * two Intents defined by {@link Intent#filterEquals}), then it will be removed and
-     * replace by this one, effectively releasing the previous {@link NetworkRequest}.
+     * replaced by this one, effectively releasing the previous {@link NetworkRequest}.
      * <p>
-     * The request may be released normally by calling {@link releaseNetworkRequest}.
+     * The request may be released normally by calling {@link #releaseNetworkRequest}.
      *
-     * @param need {@link NetworkCapabilties} required by this request.
+     * @param need {@link NetworkCapabilities} required by this request.
      * @param operation Action to perform when the network is available (corresponds
-     *                  to the {@link NetworkCallbacks#onAvailable} call.  Typically
+     *                  to the {@link NetworkCallbackListener#onAvailable} call.  Typically
      *                  comes from {@link PendingIntent#getBroadcast}.
      * @return A {@link NetworkRequest} object identifying the request.
-     * @hide
      */
     public NetworkRequest requestNetwork(NetworkCapabilities need, PendingIntent operation) {
         try {
@@ -2035,28 +2097,27 @@
      * Registers to receive notifications about all networks which satisfy the given
      * {@link NetworkCapabilities}.  The callbacks will continue to be called until
      * either the application exits or the request is released using
-     * {@link releaseNetworkRequest}.
+     * {@link #releaseNetworkRequest}.
      *
      * @param need {@link NetworkCapabilities} required by this request.
-     * @param networkCallbacks The {@link NetworkCallbacks} to be called as suitable
+     * @param networkCallbackListener The {@link NetworkCallbackListener} to be called as suitable
      *                         networks change state.
      * @return A {@link NetworkRequest} object identifying the request.
-     * @hide
      */
     public NetworkRequest listenForNetwork(NetworkCapabilities need,
-            NetworkCallbacks networkCallbacks) {
-        return somethingForNetwork(need, networkCallbacks, 0, LISTEN);
+            NetworkCallbackListener networkCallbackListener) {
+        return somethingForNetwork(need, networkCallbackListener, 0, LISTEN);
     }
 
     /**
-     * Releases a {NetworkRequest} generated either through a {@link requestNetwork}
-     * or a {@link listenForNetwork} call.  The {@link NetworkCallbacks} given in the
-     * earlier call may continue receiving calls until the {@link NetworkCallbacks#onReleased}
-     * function is called, signifiying the end of the request.
+     * Releases a {@link NetworkRequest} generated either through a {@link #requestNetwork}
+     * or a {@link #listenForNetwork} call.  The {@link NetworkCallbackListener} given in the
+     * earlier call may continue receiving calls until the
+     * {@link NetworkCallbackListener#onReleased} function is called, signifying the end
+     * of the request.
      *
      * @param networkRequest The {@link NetworkRequest} generated by an earlier call to
-     *                       {@link requestNetwork} or {@link listenForNetwork}.
-     * @hide
+     *                       {@link #requestNetwork} or {@link #listenForNetwork}.
      */
     public void releaseNetworkRequest(NetworkRequest networkRequest) {
         if (networkRequest == null) throw new IllegalArgumentException("null NetworkRequest");
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 489b8a5..3c36679 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -36,27 +36,12 @@
  *
  * A link represents a connection to a network.
  * It may have multiple addresses and multiple gateways,
- * multiple dns servers but only one http proxy.
+ * multiple dns servers but only one http proxy and one
+ * network interface.
  *
- * Because it's a single network, the dns's
- * are interchangeable and don't need associating with
- * particular addresses.  The gateways similarly don't
- * need associating with particular addresses.
+ * Note that this is just a holder of data.  Modifying it
+ * does not affect live networks.
  *
- * A dual stack interface works fine in this model:
- * each address has it's own prefix length to describe
- * the local network.  The dns servers all return
- * both v4 addresses and v6 addresses regardless of the
- * address family of the server itself (rfc4213) and we
- * don't care which is used.  The gateways will be
- * selected based on the destination address and the
- * source address has no relavence.
- *
- * Links can also be stacked on top of each other.
- * This can be used, for example, to represent a tunnel
- * interface that runs on top of a physical interface.
- *
- * @hide
  */
 public class LinkProperties implements Parcelable {
     // The interface described by the network link.
@@ -73,6 +58,7 @@
     private Hashtable<String, LinkProperties> mStackedLinks =
         new Hashtable<String, LinkProperties>();
 
+    // @hide
     public static class CompareResult<T> {
         public Collection<T> removed = new ArrayList<T>();
         public Collection<T> added = new ArrayList<T>();
@@ -91,7 +77,6 @@
     public LinkProperties() {
     }
 
-    // copy constructor instead of clone
     public LinkProperties(LinkProperties source) {
         if (source != null) {
             mIfaceName = source.getInterfaceName();
@@ -108,6 +93,12 @@
         }
     }
 
+    /**
+     * Sets the interface name for this link.  All {@link RouteInfo} already set for this
+     * will have their interface changed to match this new value.
+     *
+     * @param iface The name of the network interface used for this link.
+     */
     public void setInterfaceName(String iface) {
         mIfaceName = iface;
         ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
@@ -117,10 +108,16 @@
         mRoutes = newRoutes;
     }
 
+    /**
+     * Gets the interface name for this link.  May be {@code null} if not set.
+     *
+     * @return The interface name set for this link or {@code null}.
+     */
     public String getInterfaceName() {
         return mIfaceName;
     }
 
+    // @hide
     public Collection<String> getAllInterfaceNames() {
         Collection interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
         if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
@@ -131,7 +128,14 @@
     }
 
     /**
-     * Returns all the addresses on this link.
+     * Returns all the addresses on this link.  We often think of a link having a single address,
+     * however, particularly with Ipv6 several addresses are typical.  Note that the
+     * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include
+     * prefix lengths for each address.  This is a simplified utility alternative to
+     * {@link LinkProperties#getLinkAddresses}.
+     *
+     * @return An umodifiable {@link Collection} of {@link InetAddress} for this link.
+     * @hide
      */
     public Collection<InetAddress> getAddresses() {
         Collection<InetAddress> addresses = new ArrayList<InetAddress>();
@@ -143,6 +147,7 @@
 
     /**
      * Returns all the addresses on this link and all the links stacked above it.
+     * @hide
      */
     public Collection<InetAddress> getAllAddresses() {
         Collection<InetAddress> addresses = new ArrayList<InetAddress>();
@@ -165,7 +170,8 @@
     }
 
     /**
-     * Adds a link address if it does not exist, or updates it if it does.
+     * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the
+     * same address/prefix does not already exist.  If it does exist it is replaced.
      * @param address The {@code LinkAddress} to add.
      * @return true if {@code address} was added or updated, false otherwise.
      */
@@ -189,9 +195,10 @@
     }
 
     /**
-     * Removes a link address. Specifically, removes the link address, if any, for which
-     * {@code isSameAddressAs(toRemove)} returns true.
-     * @param address A {@code LinkAddress} specifying the address to remove.
+     * Removes a {@link LinkAddress} from this {@code LinkProperties}.  Specifically, matches
+     * and {@link LinkAddress} with the same address and prefix.
+     *
+     * @param toRemove A {@link LinkAddress} specifying the address to remove.
      * @return true if the address was removed, false if it did not exist.
      */
     public boolean removeLinkAddress(LinkAddress toRemove) {
@@ -204,7 +211,10 @@
     }
 
     /**
-     * Returns all the addresses on this link.
+     * Returns all the {@link LinkAddress} on this link.  Typically a link will have
+     * one IPv4 address and one or more IPv6 addresses.
+     *
+     * @return An unmodifiable {@link Collection} of {@link LinkAddress} for this link.
      */
     public Collection<LinkAddress> getLinkAddresses() {
         return Collections.unmodifiableCollection(mLinkAddresses);
@@ -212,6 +222,7 @@
 
     /**
      * Returns all the addresses on this link and all the links stacked above it.
+     * @hide
      */
     public Collection<LinkAddress> getAllLinkAddresses() {
         Collection<LinkAddress> addresses = new ArrayList<LinkAddress>();
@@ -223,7 +234,11 @@
     }
 
     /**
-     * Replaces the LinkAddresses on this link with the given collection of addresses.
+     * Replaces the {@link LinkAddress} in this {@code LinkProperties} with
+     * the given {@link Collection} of {@link LinkAddress}.
+     *
+     * @param addresses The {@link Collection} of {@link LinkAddress} to set in this
+     *                  object.
      */
     public void setLinkAddresses(Collection<LinkAddress> addresses) {
         mLinkAddresses.clear();
@@ -232,26 +247,64 @@
         }
     }
 
+    /**
+     * Adds the given {@link InetAddress} to the list of DNS servers.
+     *
+     * @param dns The {@link InetAddress} to add to the list of DNS servers.
+     */
     public void addDns(InetAddress dns) {
         if (dns != null) mDnses.add(dns);
     }
 
+    /**
+     * Returns all the {@link LinkAddress} for DNS servers on this link.
+     *
+     * @return An umodifiable {@link Collection} of {@link InetAddress} for DNS servers on
+     *         this link.
+     */
     public Collection<InetAddress> getDnses() {
         return Collections.unmodifiableCollection(mDnses);
     }
 
-    public String getDomains() {
-        return mDomains;
-    }
-
+    /**
+     * Sets the DNS domain search path used on this link.
+     *
+     * @param domains A {@link String} listing in priority order the comma separated
+     *                domains to search when resolving host names on this link.
+     */
     public void setDomains(String domains) {
         mDomains = domains;
     }
 
+    /**
+     * Get the DNS domains search path set for this link.
+     *
+     * @return A {@link String} containing the comma separated domains to search when resolving
+     *         host names on this link.
+     */
+    public String getDomains() {
+        return mDomains;
+    }
+
+    /**
+     * Sets the Maximum Transmission Unit size to use on this link.  This should not be used
+     * unless the system default (1500) is incorrect.  Values less than 68 or greater than
+     * 10000 will be ignored.
+     *
+     * @param mtu The MTU to use for this link.
+     * @hide
+     */
     public void setMtu(int mtu) {
         mMtu = mtu;
     }
 
+    /**
+     * Gets any non-default MTU size set for this link.  Note that if the default is being used
+     * this will return 0.
+     *
+     * @return The mtu value set for this link.
+     * @hide
+     */
     public int getMtu() {
         return mMtu;
     }
@@ -263,6 +316,14 @@
             mIfaceName);
     }
 
+    /**
+     * Adds a {@link RouteInfo} to this {@code LinkProperties}.  If the {@link RouteInfo}
+     * had an interface name set and that differs from the interface set for this
+     * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown.  The
+     * proper course is to add either un-named or properly named {@link RouteInfo}.
+     *
+     * @param route A {@link RouteInfo} to add to this object.
+     */
     public void addRoute(RouteInfo route) {
         if (route != null) {
             String routeIface = route.getInterface();
@@ -276,7 +337,9 @@
     }
 
     /**
-     * Returns all the routes on this link.
+     * Returns all the {@link RouteInfo} set on this link.
+     *
+     * @return An unmodifiable {@link Collection} of {@link RouteInfo} for this link.
      */
     public Collection<RouteInfo> getRoutes() {
         return Collections.unmodifiableCollection(mRoutes);
@@ -284,6 +347,7 @@
 
     /**
      * Returns all the routes on this link and all the links stacked above it.
+     * @hide
      */
     public Collection<RouteInfo> getAllRoutes() {
         Collection<RouteInfo> routes = new ArrayList();
@@ -294,9 +358,22 @@
         return routes;
     }
 
+    /**
+     * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none.
+     * Note that Http Proxies are only a hint - the system recommends their use, but it does
+     * not enforce it and applications may ignore them.
+     *
+     * @param proxy A {@link ProxyInfo} defining the Http Proxy to use on this link.
+     */
     public void setHttpProxy(ProxyInfo proxy) {
         mHttpProxy = proxy;
     }
+
+    /**
+     * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link.
+     *
+     * @return The {@link ProxyInfo} set on this link
+     */
     public ProxyInfo getHttpProxy() {
         return mHttpProxy;
     }
@@ -310,6 +387,7 @@
      *
      * @param link The link to add.
      * @return true if the link was stacked, false otherwise.
+     * @hide
      */
     public boolean addStackedLink(LinkProperties link) {
         if (link != null && link.getInterfaceName() != null) {
@@ -327,6 +405,7 @@
      *
      * @param link The link to remove.
      * @return true if the link was removed, false otherwise.
+     * @hide
      */
     public boolean removeStackedLink(LinkProperties link) {
         if (link != null && link.getInterfaceName() != null) {
@@ -338,6 +417,7 @@
 
     /**
      * Returns all the links stacked on top of this link.
+     * @hide
      */
     public Collection<LinkProperties> getStackedLinks() {
         Collection<LinkProperties> stacked = new ArrayList<LinkProperties>();
@@ -347,6 +427,9 @@
         return Collections.unmodifiableCollection(stacked);
     }
 
+    /**
+     * Clears this object to its initial state.
+     */
     public void clear() {
         mIfaceName = null;
         mLinkAddresses.clear();
@@ -432,6 +515,7 @@
      *
      * @param target LinkProperties to compare.
      * @return {@code true} if both are identical, {@code false} otherwise.
+     * @hide
      */
     public boolean isIdenticalInterfaceName(LinkProperties target) {
         return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
@@ -442,6 +526,7 @@
      *
      * @param target LinkProperties to compare.
      * @return {@code true} if both are identical, {@code false} otherwise.
+     * @hide
      */
     public boolean isIdenticalAddresses(LinkProperties target) {
         Collection<InetAddress> targetAddresses = target.getAddresses();
@@ -455,6 +540,7 @@
      *
      * @param target LinkProperties to compare.
      * @return {@code true} if both are identical, {@code false} otherwise.
+     * @hide
      */
     public boolean isIdenticalDnses(LinkProperties target) {
         Collection<InetAddress> targetDnses = target.getDnses();
@@ -473,6 +559,7 @@
      *
      * @param target LinkProperties to compare.
      * @return {@code true} if both are identical, {@code false} otherwise.
+     * @hide
      */
     public boolean isIdenticalRoutes(LinkProperties target) {
         Collection<RouteInfo> targetRoutes = target.getRoutes();
@@ -485,6 +572,7 @@
      *
      * @param target LinkProperties to compare.
      * @return {@code true} if both are identical, {@code false} otherwise.
+     * @hide
      */
     public boolean isIdenticalHttpProxy(LinkProperties target) {
         return getHttpProxy() == null ? target.getHttpProxy() == null :
@@ -496,6 +584,7 @@
      *
      * @param target LinkProperties to compare.
      * @return {@code true} if both are identical, {@code false} otherwise.
+     * @hide
      */
     public boolean isIdenticalStackedLinks(LinkProperties target) {
         if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
@@ -516,6 +605,7 @@
      *
      * @param target LinkProperties to compare.
      * @return {@code true} if both are identical, {@code false} otherwise.
+     * @hide
      */
     public boolean isIdenticalMtu(LinkProperties target) {
         return getMtu() == target.getMtu();
@@ -533,10 +623,6 @@
      * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
      * 2. Worst case performance is O(n^2).
      *
-     * This method does not check that stacked interfaces are equal, because
-     * stacked interfaces are not so much a property of the link as a
-     * description of connections between links.
-     *
      * @param obj the object to be tested for equality.
      * @return {@code true} if both objects are equal, {@code false} otherwise.
      */
@@ -546,7 +632,11 @@
         if (!(obj instanceof LinkProperties)) return false;
 
         LinkProperties target = (LinkProperties) obj;
-
+        /**
+         * This method does not check that stacked interfaces are equal, because
+         * stacked interfaces are not so much a property of the link as a
+         * description of connections between links.
+         */
         return isIdenticalInterfaceName(target) &&
                 isIdenticalAddresses(target) &&
                 isIdenticalDnses(target) &&
@@ -562,6 +652,7 @@
      *
      * @param target a LinkProperties with the new list of addresses
      * @return the differences between the addresses.
+     * @hide
      */
     public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
         /*
@@ -590,6 +681,7 @@
      *
      * @param target a LinkProperties with the new list of dns addresses
      * @return the differences between the DNS addresses.
+     * @hide
      */
     public CompareResult<InetAddress> compareDnses(LinkProperties target) {
         /*
@@ -619,6 +711,7 @@
      *
      * @param target a LinkProperties with the new list of routes
      * @return the differences between the routes.
+     * @hide
      */
     public CompareResult<RouteInfo> compareAllRoutes(LinkProperties target) {
         /*
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index ac1289b..e0d69e3 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -20,20 +20,34 @@
 import android.os.Parcel;
 
 import java.net.InetAddress;
+import java.net.Socket;
 import java.net.UnknownHostException;
+import javax.net.SocketFactory;
 
 /**
- * Identifies the Network.
- * @hide
+ * Identifies a {@code Network}.  This is supplied to applications via
+ * {@link ConnectivityManager.NetworkCallbackListener} in response to
+ * {@link ConnectivityManager#requestNetwork} or {@link ConnectivityManager#listenForNetwork}.
+ * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis
+ * through a targeted {@link SocketFactory} or process-wide via {@link #bindProcess}.
  */
 public class Network implements Parcelable {
 
+    /**
+     * @hide
+     */
     public final int netId;
 
+    /**
+     * @hide
+     */
     public Network(int netId) {
         this.netId = netId;
     }
 
+    /**
+     * @hide
+     */
     public Network(Network that) {
         this.netId = that.netId;
     }
@@ -64,6 +78,45 @@
         return InetAddress.getByNameOnNet(host, netId);
     }
 
+    /**
+     * Returns a {@link SocketFactory} bound to this network.  Any {@link Socket} created by
+     * this factory will have its traffic sent over this {@code Network}.  Note that if this
+     * {@code Network} ever disconnects, this factory and any {@link Socket} it produced in the
+     * past or future will cease to work.
+     *
+     * @return a {@link SocketFactory} which produces {@link Socket} instances bound to this
+     *         {@code Network}.
+     */
+    public SocketFactory socketFactory() {
+        return null;
+    }
+
+    /**
+     * Binds the current process to this network.  All sockets created in the future (and not
+     * explicitly bound via a bound {@link SocketFactory} (see {@link Network#socketFactory})
+     * will be bound to this network.  Note that if this {@code Network} ever disconnects
+     * all sockets created in this way will cease to work.  This is by design so an application
+     * doesn't accidentally use sockets it thinks are still bound to a particular {@code Network}.
+     */
+    public void bindProcess() {
+    }
+
+    /**
+     * A static utility method to return any {@code Network} currently bound by this process.
+     *
+     * @return {@code Network} to which this process is bound.
+     */
+    public static Network getProcessBoundNetwork() {
+        return null;
+    }
+
+    /**
+     * Clear any process specific {@code Network} binding.  This reverts a call to
+     * {@link Network#bindProcess}.
+     */
+    public static void unbindProcess() {
+    }
+
     // implement the Parcelable interface
     public int describeContents() {
         return 0;
@@ -84,4 +137,14 @@
                 return new Network[size];
             }
     };
+
+    public boolean equals(Object obj) {
+        if (obj instanceof Network == false) return false;
+        Network other = (Network)obj;
+        return this.netId == other.netId;
+    }
+
+    public int hashCode() {
+        return netId * 11;
+    }
 }
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 8005e5c..35274f1 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -30,13 +30,31 @@
 import java.util.Set;
 
 /**
- * A class representing the capabilities of a network
- * @hide
+ * This class represents the capabilities of a network.  This is used both to specify
+ * needs to {@link ConnectivityManager} and when inspecting a network.
+ *
+ * Note that this replaces the old {@link ConnectivityManager#TYPE_MOBILE} method
+ * of network selection.  Rather than indicate a need for Wi-Fi because an application
+ * needs high bandwidth and risk obselence when a new, fast network appears (like LTE),
+ * the application should specify it needs high bandwidth.  Similarly if an application
+ * needs an unmetered network for a bulk transfer it can specify that rather than assuming
+ * all cellular based connections are metered and all Wi-Fi based connections are not.
  */
 public final class NetworkCapabilities implements Parcelable {
     private static final String TAG = "NetworkCapabilities";
     private static final boolean DBG = false;
 
+    public NetworkCapabilities() {
+    }
+
+    public NetworkCapabilities(NetworkCapabilities nc) {
+        if (nc != null) {
+            mNetworkCapabilities = nc.mNetworkCapabilities;
+            mTransportTypes = nc.mTransportTypes;
+            mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
+            mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
+        }
+    }
 
     /**
      * Represents the network's capabilities.  If any are specified they will be satisfied
@@ -45,28 +63,99 @@
     private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED);
 
     /**
-     * Values for NetworkCapabilities.  Roughly matches/extends deprecated
-     * ConnectivityManager TYPE_*
+     * Indicates this is a network that has the ability to reach the
+     * carrier's MMSC for sending and receiving MMS messages.
      */
     public static final int NET_CAPABILITY_MMS            = 0;
+
+    /**
+     * Indicates this is a network that has the ability to reach the carrier's
+     * SUPL server, used to retrieve GPS information.
+     */
     public static final int NET_CAPABILITY_SUPL           = 1;
+
+    /**
+     * Indicates this is a network that has the ability to reach the carrier's
+     * DUN or tethering gateway.
+     */
     public static final int NET_CAPABILITY_DUN            = 2;
+
+    /**
+     * Indicates this is a network that has the ability to reach the carrier's
+     * FOTA portal, used for over the air updates.
+     */
     public static final int NET_CAPABILITY_FOTA           = 3;
+
+    /**
+     * Indicates this is a network that has the ability to reach the carrier's
+     * IMS servers, used for network registration and signaling.
+     */
     public static final int NET_CAPABILITY_IMS            = 4;
+
+    /**
+     * Indicates this is a network that has the ability to reach the carrier's
+     * CBS servers, used for carrier specific services.
+     */
     public static final int NET_CAPABILITY_CBS            = 5;
+
+    /**
+     * Indicates this is a network that has the ability to reach a Wi-Fi direct
+     * peer.
+     */
     public static final int NET_CAPABILITY_WIFI_P2P       = 6;
+
+    /**
+     * Indicates this is a network that has the ability to reach a carrier's
+     * Initial Attach servers.
+     */
     public static final int NET_CAPABILITY_IA             = 7;
+
+    /**
+     * Indicates this is a network that has the ability to reach a carrier's
+     * RCS servers, used for Rich Communication Services.
+     */
     public static final int NET_CAPABILITY_RCS            = 8;
+
+    /**
+     * Indicates this is a network that has the ability to reach a carrier's
+     * XCAP servers, used for configuration and control.
+     */
     public static final int NET_CAPABILITY_XCAP           = 9;
+
+    /**
+     * Indicates this is a network that has the ability to reach a carrier's
+     * Emergency IMS servers, used for network signaling during emergency calls.
+     */
     public static final int NET_CAPABILITY_EIMS           = 10;
+
+    /**
+     * Indicates that this network is unmetered.
+     */
     public static final int NET_CAPABILITY_NOT_METERED    = 11;
+
+    /**
+     * Indicates that this network should be able to reach the internet.
+     */
     public static final int NET_CAPABILITY_INTERNET       = 12;
-    /** Set by default */
+
+    /**
+     * Indicates that this network is available for general use.  If this is not set
+     * applications should not attempt to communicate on this network.  Note that this
+     * is simply informative and not enforcement - enforcement is handled via other means.
+     * Set by default.
+     */
     public static final int NET_CAPABILITY_NOT_RESTRICTED = 13;
 
     private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
     private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_RESTRICTED;
 
+    /**
+     * Adds the given capability to this {@code NetworkCapability} instance.
+     * Multiple capabilities may be applied sequentially.  Note that when searching
+     * for a network to satisfy a request, all capabilities requested must be satisfied.
+     *
+     * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added.
+     */
     public void addNetworkCapability(int networkCapability) {
         if (networkCapability < MIN_NET_CAPABILITY ||
                 networkCapability > MAX_NET_CAPABILITY) {
@@ -74,6 +163,12 @@
         }
         mNetworkCapabilities |= 1 << networkCapability;
     }
+
+    /**
+     * Removes (if found) the given capability from this {@code NetworkCapability} instance.
+     *
+     * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed.
+     */
     public void removeNetworkCapability(int networkCapability) {
         if (networkCapability < MIN_NET_CAPABILITY ||
                 networkCapability > MAX_NET_CAPABILITY) {
@@ -81,9 +176,23 @@
         }
         mNetworkCapabilities &= ~(1 << networkCapability);
     }
+
+    /**
+     * Gets all the capabilities set on this {@code NetworkCapability} instance.
+     *
+     * @return a {@link Collection} of {@code NetworkCapabilities.NET_CAPABILITY_*} values
+     *         for this instance.
+     */
     public Collection<Integer> getNetworkCapabilities() {
         return enumerateBits(mNetworkCapabilities);
     }
+
+    /**
+     * Tests for the presence of a capabilitity on this instance.
+     *
+     * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for.
+     * @return {@code true} if set on this instance.
+     */
     public boolean hasCapability(int networkCapability) {
         if (networkCapability < MIN_NET_CAPABILITY ||
                 networkCapability > MAX_NET_CAPABILITY) {
@@ -124,31 +233,74 @@
     private long mTransportTypes;
 
     /**
-     * Values for TransportType
+     * Indicates this network uses a Cellular transport.
      */
     public static final int TRANSPORT_CELLULAR = 0;
+
+    /**
+     * Indicates this network uses a Wi-Fi transport.
+     */
     public static final int TRANSPORT_WIFI = 1;
+
+    /**
+     * Indicates this network uses a Bluetooth transport.
+     */
     public static final int TRANSPORT_BLUETOOTH = 2;
+
+    /**
+     * Indicates this network uses an Ethernet transport.
+     */
     public static final int TRANSPORT_ETHERNET = 3;
 
     private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
     private static final int MAX_TRANSPORT = TRANSPORT_ETHERNET;
 
+    /**
+     * Adds the given transport type to this {@code NetworkCapability} instance.
+     * Multiple transports may be applied sequentially.  Note that when searching
+     * for a network to satisfy a request, any listed in the request will satisfy the request.
+     * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
+     * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
+     * to be selected.  This is logically different than
+     * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above.
+     *
+     * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added.
+     */
     public void addTransportType(int transportType) {
         if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
             throw new IllegalArgumentException("TransportType out of range");
         }
         mTransportTypes |= 1 << transportType;
     }
+
+    /**
+     * Removes (if found) the given transport from this {@code NetworkCapability} instance.
+     *
+     * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed.
+     */
     public void removeTransportType(int transportType) {
         if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
             throw new IllegalArgumentException("TransportType out of range");
         }
         mTransportTypes &= ~(1 << transportType);
     }
+
+    /**
+     * Gets all the transports set on this {@code NetworkCapability} instance.
+     *
+     * @return a {@link Collection} of {@code NetworkCapabilities.TRANSPORT_*} values
+     *         for this instance.
+     */
     public Collection<Integer> getTransportTypes() {
         return enumerateBits(mTransportTypes);
     }
+
+    /**
+     * Tests for the presence of a transport on this instance.
+     *
+     * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be tested for.
+     * @return {@code true} if set on this instance.
+     */
     public boolean hasTransport(int transportType) {
         if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
             return false;
@@ -175,15 +327,58 @@
     private int mLinkUpBandwidthKbps;
     private int mLinkDownBandwidthKbps;
 
+    /**
+     * Sets the upstream bandwidth for this network in Kbps.  This always only refers to
+     * the estimated first hop transport bandwidth.
+     * <p>
+     * Note that when used to request a network, this specifies the minimum acceptable.
+     * When received as the state of an existing network this specifies the typical
+     * first hop bandwidth expected.  This is never measured, but rather is inferred
+     * from technology type and other link parameters.  It could be used to differentiate
+     * between very slow 1xRTT cellular links and other faster networks or even between
+     * 802.11b vs 802.11AC wifi technologies.  It should not be used to differentiate between
+     * fast backhauls and slow backhauls.
+     *
+     * @param upKbps the estimated first hop upstream (device to network) bandwidth.
+     */
     public void setLinkUpstreamBandwidthKbps(int upKbps) {
         mLinkUpBandwidthKbps = upKbps;
     }
+
+    /**
+     * Retrieves the upstream bandwidth for this network in Kbps.  This always only refers to
+     * the estimated first hop transport bandwidth.
+     *
+     * @return The estimated first hop upstream (device to network) bandwidth.
+     */
     public int getLinkUpstreamBandwidthKbps() {
         return mLinkUpBandwidthKbps;
     }
+
+    /**
+     * Sets the downstream bandwidth for this network in Kbps.  This always only refers to
+     * the estimated first hop transport bandwidth.
+     * <p>
+     * Note that when used to request a network, this specifies the minimum acceptable.
+     * When received as the state of an existing network this specifies the typical
+     * first hop bandwidth expected.  This is never measured, but rather is inferred
+     * from technology type and other link parameters.  It could be used to differentiate
+     * between very slow 1xRTT cellular links and other faster networks or even between
+     * 802.11b vs 802.11AC wifi technologies.  It should not be used to differentiate between
+     * fast backhauls and slow backhauls.
+     *
+     * @param downKbps the estimated first hop downstream (network to device) bandwidth.
+     */
     public void setLinkDownstreamBandwidthKbps(int downKbps) {
         mLinkDownBandwidthKbps = downKbps;
     }
+
+    /**
+     * Retrieves the downstream bandwidth for this network in Kbps.  This always only refers to
+     * the estimated first hop transport bandwidth.
+     *
+     * @return The estimated first hop downstream (network to device) bandwidth.
+     */
     public int getLinkDownstreamBandwidthKbps() {
         return mLinkDownBandwidthKbps;
     }
@@ -243,19 +438,6 @@
                 (mLinkDownBandwidthKbps * 13));
     }
 
-    public NetworkCapabilities() {
-    }
-
-    public NetworkCapabilities(NetworkCapabilities nc) {
-        if (nc != null) {
-            mNetworkCapabilities = nc.mNetworkCapabilities;
-            mTransportTypes = nc.mTransportTypes;
-            mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
-            mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
-        }
-    }
-
-    // Parcelable
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index b3ae3f5..480cb057 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -22,11 +22,19 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
- * @hide
+ * Defines a request for a network, made by calling {@link ConnectivityManager#requestNetwork}
+ * or {@link ConnectivityManager#listenForNetwork}.
+ *
+ * This token records the {@link NetworkCapabilities} used to make the request and identifies
+ * the request.  It should be used to release the request via
+ * {@link ConnectivityManager#releaseNetworkRequest} when the network is no longer desired.
  */
 public class NetworkRequest implements Parcelable {
     /**
-     * The NetworkCapabilities that define this request
+     * The {@link NetworkCapabilities} that define this request.  This should not be modified.
+     * The networkCapabilities of the request are set when
+     * {@link ConnectivityManager#requestNetwork} is called and the value is presented here
+     * as a convenient reminder of what was requested.
      */
     public final NetworkCapabilities networkCapabilities;
 
@@ -34,7 +42,7 @@
      * Identifies the request.  NetworkRequests should only be constructed by
      * the Framework and given out to applications as tokens to be used to identify
      * the request.
-     * TODO - make sure this input is checked whenever a NR is passed in a public API
+     * @hide
      */
     public final int requestId;
 
@@ -45,31 +53,18 @@
      */
     public final boolean needsBroadcasts;
 
-    private static final AtomicInteger sNextRequestId = new AtomicInteger(1);
-
     /**
      * @hide
      */
-    public NetworkRequest(NetworkCapabilities nc) {
-        this(nc, false, sNextRequestId.getAndIncrement());
-    }
-
-    /**
-     * @hide
-     */
-    public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts) {
-        this(nc, needsBroadcasts, sNextRequestId.getAndIncrement());
-    }
-
-    /**
-     * @hide
-     */
-    private NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) {
+    public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) {
         requestId = rId;
         networkCapabilities = nc;
         this.needsBroadcasts = needsBroadcasts;
     }
 
+    /**
+     * @hide
+     */
     public NetworkRequest(NetworkRequest that) {
         networkCapabilities = new NetworkCapabilities(that.networkCapabilities);
         requestId = that.requestId;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index e566549..ad8e4f7 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -25,21 +25,26 @@
 import java.net.Inet6Address;
 
 import java.util.Collection;
+import java.util.Objects;
 
 /**
- * A simple container for route information.
+ * Represents a network route.
  * <p>
  * This is used both to describe static network configuration and live network
- * configuration information.  In the static case the interface name (retrieved
- * via {@link #getInterface}) should be {@code null} as that information will not
- * yet be known.
+ * configuration information.
  *
- * A route may be configured with:
+ * A route contains three pieces of information:
  * <ul>
- * <li>a destination {@link LinkAddress} for directly-connected subnets,
- * <li>a gateway {@link InetAddress} for default routes,
- * <li>or both for a subnet.
+ * <li>a destination {@link LinkAddress} for directly-connected subnets.  If this is
+ *     {@code null} it indicates a default route of the address family (IPv4 or IPv6)
+ *     implied by the gateway IP address.
+ * <li>a gateway {@link InetAddress} for default routes.  If this is {@code null} it
+ *     indicates a directly-connected route.
+ * <li>an interface (which may be unspecified).
  * </ul>
+ * Either the destination or the gateway may be {@code null}, but not both.  If the
+ * destination and gateway are both specified, they must be of the same address family
+ * (IPv4 or IPv6).
  */
 public class RouteInfo implements Parcelable {
     /**
@@ -69,14 +74,12 @@
      * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
      * route <code>::/0</code> if gateway is an instance of
      * {@link Inet6Address}.
-     *
+     * <p>
      * destination and gateway may not both be null.
      *
      * @param destination the destination prefix
      * @param gateway the IP address to route packets through
      * @param iface the interface name to send packets on
-     *
-     * @hide
      */
     public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
         if (destination == null) {
@@ -103,6 +106,12 @@
 
         mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
                 destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
+        if ((destination.getAddress() instanceof Inet4Address &&
+                 (gateway instanceof Inet4Address == false)) ||
+                (destination.getAddress() instanceof Inet6Address &&
+                 (gateway instanceof Inet6Address == false))) {
+            throw new IllegalArgumentException("address family mismatch in RouteInfo constructor");
+        }
         mGateway = gateway;
         mInterface = iface;
         mIsDefault = isDefault();
@@ -138,10 +147,11 @@
     /**
      * Constructs a {@code RouteInfo} object representing a direct connected subnet.
      *
-     * @param host the {@link LinkAddress} describing the address and prefix length of the subnet.
+     * @param destination the {@link LinkAddress} describing the address and prefix
+     *                    length of the subnet.
      */
-    public RouteInfo(LinkAddress host) {
-        this(host, null, null);
+    public RouteInfo(LinkAddress destination) {
+        this(destination, null, null);
     }
 
     /**
@@ -186,7 +196,7 @@
     /**
      * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}.
      *
-     * @return {@link LinkAddress} specifying the destination.
+     * @return {@link LinkAddress} specifying the destination.  This is never {@code null}.
      */
     public LinkAddress getDestination() {
         return mDestination;
@@ -195,15 +205,15 @@
     /**
      * Retrieves the gateway or next hop {@link InetAddress} for this route.
      *
-     * @return {@link InetAddress} specifying the gateway or next hop.
+     * @return {@link InetAddress} specifying the gateway or next hop.  This may be
+     &                             {@code null} for a directly-connected route."
      */
     public InetAddress getGateway() {
         return mGateway;
     }
 
     /**
-     * Retrieves the interface used for this route, if known.  Note that for static
-     * network configurations, this won't be set.
+     * Retrieves the interface used for this route if specified, else {@code null}.
      *
      * @return The name of the interface used for this route.
      */
@@ -214,7 +224,7 @@
     /**
      * Indicates if this route is a default route (ie, has no destination specified).
      *
-     * @return {@code true} if the destination is null or has a prefix length of 0.
+     * @return {@code true} if the destination has a prefix length of 0.
      */
     public boolean isDefaultRoute() {
         return mIsDefault;
@@ -224,6 +234,7 @@
      * Indicates if this route is a host route (ie, matches only a single host address).
      *
      * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6.
+     * @hide
      */
     public boolean isHostRoute() {
         return mIsHost;
@@ -234,15 +245,20 @@
      * ({@code false}).
      *
      * @return {@code true} if a gateway is specified
+     * @hide
      */
     public boolean hasGateway() {
         return mHasGateway;
     }
 
     /**
-     * @hide
+     * Determines whether the destination and prefix of this route includes the specified
+     * address.
+     *
+     * @param destination A {@link InetAddress} to test to see if it would match this route.
+     * @return {@code true} if the destination and prefix length cover the given address.
      */
-    protected boolean matches(InetAddress destination) {
+    public boolean matches(InetAddress destination) {
         if (destination == null) return false;
 
         // match the route destination and destination with prefix length
@@ -293,20 +309,9 @@
 
         RouteInfo target = (RouteInfo) obj;
 
-        boolean sameDestination = ( mDestination == null) ?
-                target.getDestination() == null
-                : mDestination.equals(target.getDestination());
-
-        boolean sameAddress = (mGateway == null) ?
-                target.getGateway() == null
-                : mGateway.equals(target.getGateway());
-
-        boolean sameInterface = (mInterface == null) ?
-                target.getInterface() == null
-                : mInterface.equals(target.getInterface());
-
-        return sameDestination && sameAddress && sameInterface
-                && mIsDefault == target.mIsDefault;
+        return Objects.equals(mDestination, target.getDestination()) &&
+                Objects.equals(mGateway, target.getGateway()) &&
+                Objects.equals(mInterface, target.getInterface());
     }
 
     public int hashCode() {
diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java
index 10e2073..85f702b 100644
--- a/core/java/android/speech/tts/TextToSpeechClient.java
+++ b/core/java/android/speech/tts/TextToSpeechClient.java
@@ -25,7 +25,10 @@
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.speech.tts.ITextToSpeechCallback;
@@ -86,6 +89,8 @@
     private HashMap<String, Pair<UtteranceId, RequestCallbacks>> mCallbacks;
     // Guarded by mLock
 
+    private InternalHandler mMainHandler = new InternalHandler();
+
     /** Common voices parameters */
     public static final class Params {
         private Params() {}
@@ -300,6 +305,8 @@
     /**
      * Interface definition of callbacks that are called when the client is
      * connected or disconnected from the TTS service.
+     *
+     * The callbacks specified in this method will be called on the UI thread.
      */
     public static interface ConnectionCallbacks {
         /**
@@ -325,6 +332,9 @@
          * with the speech service (e.g. a crash or resource problem causes it to be killed by the
          * system). When called, all requests have been canceled and no outstanding listeners will
          * be executed. Applications should disable UI components that require the service.
+         *
+         * When the service is working again, the client will receive a callback to the
+         * {@link #onConnectionSuccess()} method.
          */
         public void onServiceDisconnected();
 
@@ -688,7 +698,8 @@
                 synchronized (mLock) {
                     mEngineStatus = new EngineStatus(mServiceConnection.getEngineName(),
                             voicesInfo);
-                    mConnectionCallbacks.onEngineStatusChange(mEngineStatus);
+                    mMainHandler.obtainMessage(InternalHandler.WHAT_ENGINE_STATUS_CHANGED,
+                            mEngineStatus).sendToTarget();
                 }
             }
         };
@@ -753,9 +764,11 @@
             Log.i(TAG, "Asked to disconnect from " + name);
 
             synchronized(mLock) {
+                mEstablished = false;
+                mService = null;
                 stopSetupConnectionTask();
             }
-            mConnectionCallbacks.onServiceDisconnected();
+            mMainHandler.obtainMessage(InternalHandler.WHAT_SERVICE_DISCONNECTED).sendToTarget();
         }
 
         private void startSetupConnectionTask(ComponentName name) {
@@ -830,9 +843,11 @@
     private boolean runAction(Action action) {
         synchronized (mLock) {
             if (mServiceConnection == null) {
+                Log.w(TAG, action.getName() + " failed: not bound to TTS engine");
                 return false;
             }
             if (!mServiceConnection.isEstablished()) {
+                Log.w(TAG, action.getName() + " failed: not fully bound to TTS engine");
                 return false;
             }
             mServiceConnection.runAction(action);
@@ -1044,4 +1059,21 @@
             }
         });
     }
+
+    class InternalHandler extends Handler {
+        final static int WHAT_ENGINE_STATUS_CHANGED = 1;
+        final static int WHAT_SERVICE_DISCONNECTED = 2;
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case WHAT_ENGINE_STATUS_CHANGED:
+                    mConnectionCallbacks.onEngineStatusChange((EngineStatus) msg.obj);
+                    return;
+                case WHAT_SERVICE_DISCONNECTED:
+                    mConnectionCallbacks.onServiceDisconnected();
+                    return;
+            }
+        }
+    }
 }
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index d7c51fc..6b899d9 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -255,7 +255,8 @@
         // V2 to V1 interface adapter. This allows using V2 client interface on V1-only services.
         Bundle defaultParams = new Bundle();
         defaultParams.putFloat(TextToSpeechClient.Params.SPEECH_PITCH, 1.0f);
-        defaultParams.putFloat(TextToSpeechClient.Params.SPEECH_SPEED, -1.0f);
+        // Speech speed <= 0 makes it use a system wide setting
+        defaultParams.putFloat(TextToSpeechClient.Params.SPEECH_SPEED, 0.0f);
 
         // Enumerate all locales and check if they are available
         ArrayList<VoiceInfo> voicesInfo = new ArrayList<VoiceInfo>();
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index ac12357..aaf0a75 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -30,6 +30,9 @@
     private static final String CHROMIUM_WEBVIEW_FACTORY =
             "com.android.webview.chromium.WebViewChromiumFactoryProvider";
 
+    private static final String NULL_WEBVIEW_FACTORY =
+            "com.android.webview.nullwebview.NullWebViewFactoryProvider";
+
     private static final String LOGTAG = "WebViewFactory";
 
     private static final boolean DEBUG = false;
@@ -88,6 +91,11 @@
     }
 
     private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
-        return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
+        try {
+            return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
+        } catch (ClassNotFoundException e) {
+            Log.e(LOGTAG, "Chromium WebView does not exist");
+            return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
+        }
     }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 75feb5d..8fa662d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -36,9 +36,12 @@
     void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher);
     void setHardKeyboardStatus(boolean available, boolean enabled);
+    void setWindowState(int window, int state);
+
+    void showRecentApps(boolean triggeredFromAltTab);
+    void hideRecentApps();
     void toggleRecentApps();
     void preloadRecentApps();
     void cancelPreloadRecentApps();
-    void setWindowState(int window, int state);
 }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index cf334c3..9ebfd78 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -52,8 +52,11 @@
             in String[] newlyVisibleKeys, in String[] noLongerVisibleKeys);
     void setSystemUiVisibility(int vis, int mask);
     void setHardKeyboardEnabled(boolean enabled);
+    void setWindowState(int window, int state);
+
+    void showRecentApps(boolean triggeredFromAltTab);
+    void hideRecentApps();
     void toggleRecentApps();
     void preloadRecentApps();
     void cancelPreloadRecentApps();
-    void setWindowState(int window, int state);
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f262a93..a97d5fc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2079,7 +2079,7 @@
 
     <!-- Must be required by a {@link android.media.routeprovider.RouteProviderService}
          to ensure that only the system can interact with it.
-         -->
+         @hide -->
     <permission android:name="android.permission.BIND_ROUTE_PROVIDER"
         android:label="@string/permlab_bindRouteProvider"
         android:description="@string/permdesc_bindRouteProvider"
diff --git a/docs/html/training/basics/supporting-devices/languages.jd b/docs/html/training/basics/supporting-devices/languages.jd
index 45e2ab2..aab1e38 100644
--- a/docs/html/training/basics/supporting-devices/languages.jd
+++ b/docs/html/training/basics/supporting-devices/languages.jd
@@ -40,10 +40,11 @@
 <h2 id="CreateDirs">Create Locale Directories and String Files</h2> 
 
 <p>To add support for more languages, create additional <code>values</code> directories inside
-<code>res/</code> that include a hyphen and the ISO country code at the end of the
+<code>res/</code> that include a hyphen and the ISO language code at the end of the
 directory name. For example, <code>values-es/</code> is the directory containing simple
 resourcess for the Locales with the language code "es".  Android loads the appropriate resources
-according to the locale settings of the device at run time.</p>
+according to the locale settings of the device at run time. For more information, see
+ <a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing Alternative Resources</a>.</p>
 
 <p>Once you’ve decided on the languages you will support, create the resource subdirectories and
 string resource files. For example:</p>
diff --git a/docs/html/wear/css/wear.css b/docs/html/wear/css/wear.css
index 40afeaa..fe9eef2 100644
--- a/docs/html/wear/css/wear.css
+++ b/docs/html/wear/css/wear.css
@@ -145,7 +145,7 @@
 .wear-hero {
   height: calc(100% - 70px);
   min-height: 504px;
-  margin-top: -4px;
+  margin-top: 0;
   padding-top: 0;
   padding-bottom: 0;
   background-image: url(/wear/images/hero.jpg);
diff --git a/docs/html/wear/notifications/creating.jd b/docs/html/wear/notifications/creating.jd
index ce9e117..a5d7da7 100644
--- a/docs/html/wear/notifications/creating.jd
+++ b/docs/html/wear/notifications/creating.jd
@@ -44,8 +44,8 @@
 you should include the following imports in your project code:</p>
 
 <pre>
-import android.preview.support.wearable.notifications.*;
-import android.preview.support.v4.app.NotificationManagerCompat;
+import android.support.wearable.notifications.*;
+import android.support.wearable.app.NotificationManagerCompat;
 import android.support.v4.app.NotificationCompat;
 </pre>
 
@@ -64,7 +64,7 @@
 
 <p>For example, here's some code that creates and issues a notification using the
 {@link android.support.v4.app.NotificationCompat} APIs combined with the new
-<a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html">
+<a href="{@docRoot}reference/android/support/wearable/app/NotificationManagerCompat.html">
 <code>NotificationManagerCompat</code></a> API:</p>
 
 
@@ -206,54 +206,70 @@
   you can add additional pages of content that users can view by swiping to the left, or add the ability
 for users to deliver your app a text response using voice input.</p>
 
-<p>To use these new APIs, pass your instance of
-{@link android.support.v4.app.NotificationCompat.Builder} to the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#WearableNotifications.Builder(android.content.Context)"> <code>WearableNotifications.Builder()</code></a> constructor. You can then add new
-features to your notification using the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
-  ><code>WearableNotifications.Builder</code></a> methods. For example:</p>
+<p>To use these new APIs:</p>
+
+<ol>
+  <li>Create an instance of
+{@link android.support.v4.app.NotificationCompat.Builder}, setting the
+desired properties for your notification.</li>
+  <li>Create a
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#WearableNotificationOptions.Builder(android.content.Context)"> <code>WearableNotificationOptions.Builder</code></a>, setting the wearable-specific options for the notication.</li>
+  <li>Call <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#WearableNotificationOptions.Builder#applyTo"><code>WearableNotificationOptions.Builder.applyTo()</code>
+  </a>, passing in the {@link android.support.v4.app.NotificationCompat.Builder}. This applies
+  the wearable options to the notification.</li>
+</ol>
+
+<p>
+For example, the following code calls the
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#setHintHideIcon(boolean)">
+  <code>setHintHideIcon()</code></a> method to remove the app icon from the notification card.
+</p>
 
 <pre>
 // Create a NotificationCompat.Builder for standard notification features
-NotificationCompat.Builder notificationBuilder =
-        new NotificationCompat.Builder(mContext)
-        .setContentTitle("New mail from " + sender.toString())
-        .setContentText(subject)
-        .setSmallIcon(R.drawable.new_mail);
-
-// Create a WearablesNotification.Builder to add special functionality for wearables
-Notification notification =
-        new WearableNotifications.Builder(notificationBuilder)
-        .setHintHideIcon(true)
-        .build();
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
+         .setContentTitle("New mail from " + sender)
+         .setContentText(subject)
+         .setSmallIcon(R.drawable.new_mail);
+// Create a WearablesNotificationOptions.Builder to add functionality for wearables
+ Notification notif = new WearableNotificationOptions.Builder()
+         <b>.setHintHideIcon(true)</b>
+         .build()
+         .applyTo(builder); //apply wearable options to to the original notification
+         .build()
 </pre>
 
-<p>The <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setBigActionIcon(int)">
-  <code>setHintHideIcon()</code></a> method removes your app icon from the notification card.
-  This method is just one example of new notification features available from the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
-  ><code>WearableNotifications.Builder</code></a> class.</p>
+<p>The
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#setHintHideIcon(boolean)">
+  <code>setHintHideIcon()</code></a> method is just one example of new notification features available with the
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html"
+  ><code>WearableNotificationOptions.Builder</code></a> class.
+</p>
 
-<p>When you want to deliver your notifications, be certain to always use the
-  <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html">
-    <code>NotificationManagerCompat</code></a> API:</p>
+
+<p>When you want to deliver your notifications, always use the
+  <a href="{@docRoot}reference/android/support/wearable/app/NotificationManagerCompat.html">
+  <code>NotificationManagerCompat</code></a> API instead of
+  {@link android.app.NotificationManager}:</p>
 
 <pre>
 // Get an instance of the NotificationManager service
 NotificationManagerCompat notificationManager =
         NotificationManagerCompat.from(this);
 
-// Build the notification and issues it with notification manager.
-notificationManager.notify(notificationId, notification);
+// Issue the notification with notification manager.
+notificationManager.notify(notificationId, notif);
 </pre>
 
-<p>If you instead use the framework's {@link android.app.NotificationManager}, some
-features from <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"><code>WearableNotifications.Builder</code></a>
-will not work.</p>
+
+<p>If you use the framework's {@link android.app.NotificationManager}, some
+features from <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html"><code>WearableNotificationOptions.Builder</code></a>
+do not work.</p>
+
 
 <p>To continue enhancing your notifications for wearables using
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
-  ><code>WearableNotifications.Builder</code></a> and other APIs in the
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html"
+  ><code>WearableNotificationOptions.Builder</code></a> and other APIs in the
   preview support library, see the following developer guides:</p>
 
   <dl>
diff --git a/docs/html/wear/notifications/pages.jd b/docs/html/wear/notifications/pages.jd
index 558f7b8..7d18b3f 100644
--- a/docs/html/wear/notifications/pages.jd
+++ b/docs/html/wear/notifications/pages.jd
@@ -15,14 +15,19 @@
 <a href="{@docRoot}wear/design/index.html#NotificationPages">Design Principles of Android
 Wear</a>.</p>
 
-
-<p>When creating a notification with multiple pages, start by creating the main notification
-(the first page) the way you'd like the notification to appear on a phone
-or tablet. Then, add pages one at a time with the
-<a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addPage(android.app.Notification)">
+<p>To create a notification with multiple pages:</p>
+<ol>
+    <li>Create the main notification (the first page) the way you'd like the notification to appear on a phone
+    or tablet.</li>
+    <li>Add pages one at a time with the
+<a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#addPage(android.app.Notification)">
 <code>addPage()</code></a> method, or add multiple pages in a {@link java.util.Collection} with the
-<a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addPages(java.util.Collection<android.app.Notification>)">
-<code>addPages()</code></a> method.</p>
+<a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#addPages(java.util.Collection<android.app.Notification>)">
+<code>addPages()</code></a> method.</li>
+    <li>Apply the pages to the main notification with the
+    <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.html#applyTo(android.support.v4.app.NotificationCompat.Builder)"
+    ><code>applyTo()</code></a> method.</li>
+</ol>
 
 
 <p>For example, here's some code that adds a second page to a notification:</p>
@@ -47,15 +52,14 @@
         .setStyle(secondPageStyle)
         .build();
 
-// Create main notification and add the second page
+// Add second page with wearable options and apply to main notification
 Notification twoPageNotification =
-        new WearableNotifications.Builder(notificationBuilder)
+        new WearableNotificationsOptions.Builder()
         .addPage(secondPageNotification)
+        .build()
+        .applyTo(notificationBuilder)
         .build();
 </pre>
 
-
-
-
 </body>
 </html>
diff --git a/docs/html/wear/notifications/remote-input.jd b/docs/html/wear/notifications/remote-input.jd
index 1668363..4db8274 100644
--- a/docs/html/wear/notifications/remote-input.jd
+++ b/docs/html/wear/notifications/remote-input.jd
@@ -25,16 +25,16 @@
 <h2 id="RemoteInput">Define the Remote Input</h2>
 
 <p>To create an action that supports voice input, first create an instance of
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html">
+  <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html">
 <code>RemoteInput</code></a> using the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> APIs.
+  <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> APIs.
     The
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor takes a string that the system
+  <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor takes a string that the system
     will use as a key for the {@link android.content.Intent} extra that carries the reply message
     to your app on the handheld.</p>
 
 <p>For example, here's how to create a new
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html">
+  <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html">
 <code>RemoteInput</code></a> object that provides a custom
     label for the voice input prompt:</p>
 
@@ -56,7 +56,7 @@
 
 <p>In addition to allowing voice input, you can
     provide up to five text responses that the user can select for quick replies. Call
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html#setChoices(java.lang.String[])"><code>setChoices()</code></a> and pass it a string array.</p>
+  <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.Builder.html#setChoices(java.lang.String[])"><code>setChoices()</code></a> and pass it a string array.</p>
 
 <p>For example, you may define some responses in a resource array:</p>
 
@@ -73,7 +73,7 @@
 </pre>
 
 <p>Then, inflate the string array and add it to the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a>:</p>
+  <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a>:</p>
 
 <pre>
 String replyLabel = getResources().getString(R.string.reply_label);
@@ -93,8 +93,8 @@
 <p>If "Reply" is your notification's primary action (defined by the {@link
 android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()}
 method), then you should attach the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the main action using
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addRemoteInputForContentIntent(android.preview.support.wearable.notifications.RemoteInput)">
+  <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the main action using
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#addRemoteInputForContentIntent(android.support.wearable.notifications.RemoteInput)">
 <code>addRemoteInputForContentIntent()</code></a>. For example:</p>
 
 <pre>
@@ -116,18 +116,19 @@
         .setLabel(replyLabel)
         .build();
 
-// Create wearable notification and add remote input
+// Add remote input to wearable options and apply to notification
 Notification replyNotification =
-        new WearableNotifications.Builder(replyNotificationBuilder)
+        new WearableNotificationOptions.Builder()
         .addRemoteInputForContentIntent(remoteInput)
+        .build()
+        .applyTo(replyNotificationBuilder)
         .build();
 </pre>
 
-
 <p>By using
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addRemoteInputForContentIntent(android.preview.support.wearable.notifications.RemoteInput)">
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#addRemoteInputForContentIntent(android.support.wearable.notifications.RemoteInput)">
 <code>addRemoteInputForContentIntent()</code></a> to add the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> object to the notification's primary action,
+  <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> object to the notification's primary action,
 the button that normally appears as an "Open" action becomes the "Reply" action
 and starts the voice input UI when users select it on Android Wear.</p>
 
@@ -137,14 +138,14 @@
 
 <p>If the "Reply" action is not your notification's primary action and you want to enable
 voice input for a secondary action, add the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to a new action button defined by an
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
+  <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to a new action button defined by an
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableAction.html">
 <code>Action</code></a> object.</p>
 
 <p>You should instantiate the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
-<code>Action</code></a> with the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html"><code>Action.Builder()</code></a>
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableAction.html">
+<code>WearableAction</code></a> with the
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableAction.Builder.html"><code>WearableAction.Builder()</code></a>
 constructor, which takes an icon and text label for the action button, plus the
 {@link android.app.PendingIntent}
 the system should use to invoke your app when the user selects the action. For example:</p>
@@ -161,7 +162,7 @@
         .build();
 
 // Create the notification action
-Action replyAction = new Action.Builder(R.drawable.ic_message,
+WearableAction replyAction = new WearableAction.Builder(R.drawable.ic_message,
         "Reply", pendingIntent)
         .addRemoteInput(remoteInput)
         .build();
@@ -169,45 +170,72 @@
 
 
 <p>After you add the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
-<code>Action</code></a>, add the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
-<code>Action</code></a> to the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"><code>WearableNotifications.Builder</code></a> using
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addAction(Action)"><code>addAction()</code></a>.
+  <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableAction.html">
+<code>Wearablection</code></a>, set the
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableAction.html">
+<code>WearableAction</code></a> on the
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html"><code>WearableNotifications.Builder</code></a> using
+  <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationsOptions.Builder.html#addAction(Action)"><code>addAction()</code></a>.
 For example:</p>
 
 <pre>
 // Create basic notification builder
 NotificationCompat.Builder replyNotificationBuilder =
         new NotificationCompat.Builder(this)
-        .setContentTitle("New message");
+                .setContentTitle("New message");
 
 // Create the notification action and add remote input
-Action replyAction = new Action.Builder(R.drawable.ic_message,
+WearableAction replyAction = new WearableAction.Builder(R.drawable.ic_message,
         "Reply", pendingIntent)
         .addRemoteInput(remoteInput)
         .build();
 
 // Create wearable notification and add action
 Notification replyNotification =
-        new WearableNotifications.Builder(replyNotificationBuilder)
-        .addAction(replyAction)
-        .build();
+        new WearableNotificationOptions.Builder()
+                .addAction(replyAction)
+                .build()
+                .applyTo(replyNotificationBuilder)
+                .build();
 </pre>
 
+
 <p>Now, when the user selects "Reply" from an Android wearable, the system prompts the user
     for voice input (and shows the list of pre-defined replies, if provided).
     Once the user completes a response, the system invokes
     the {@link android.content.Intent} attached to the action and adds the
 <code>EXTRA_VOICE_REPLY</code> extra (the string
     you passed to the
-  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor)
-    with the user's message as the string value.</p>
+  <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor)
+  with the user's message as the string value.</p>
 
-
-
+<h2 id="ObtainInput">Obtaining the Voice Input as a String</h2>
+<p>To obtain the user's voice input, call
+<a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html#getResultsFromIntent(Intent)"><code>getResultsFromIntent()</code></a>,
+passing in the "Reply" action's intent. This method returns
+a {@link android.os.Bundle} that represents the intent's extras. You can then query the
+{@link android.os.Bundle} to obtain the user's voice input string.
+</p>
+<p>
+The following code shows a method that accepts an intent and returns the voice input string,
+which is referenced by the <code>EXTRA_VOICE_REPLY</code> key that is used in the previous examples:
+</p>
+<pre>
+/**
+ * Obtain the intent that started this activity by calling
+ * Activity.getIntent() and pass it into this method to
+ * get the associated voice input string.
+ */
+private String getMessageText(Intent intent) {
+    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
+        if (remoteInput != null) {
+            return remoteInput.getString(Intent.EXTRA_VOICE_REPLY);
+        }
+    }
+    return null;
+}
+</pre>
 
 </body>
 </html>
diff --git a/docs/html/wear/notifications/stacks.jd b/docs/html/wear/notifications/stacks.jd
index a2d34ce..3c3dc09 100644
--- a/docs/html/wear/notifications/stacks.jd
+++ b/docs/html/wear/notifications/stacks.jd
@@ -16,7 +16,7 @@
 handheld to view more information). So for the wearable device, you should
 group all the notifications together in a stack. The stack of notifications appears as a single
 card, which users can expand to view the details from each notification separately. The new
-<a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
+<a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#setGroup(java.lang.String, int)">
 <code>setGroup()</code></a> method makes this possible while allowing you to still provide
 only one summary notification on the handheld device.</p>
 
@@ -28,21 +28,24 @@
 <h2 id="AddGroup">Add Each Notification to a Group</h2>
 
 <p>To create a stack, call <a
-href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
+href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#setGroup(java.lang.String, int)">
 <code>setGroup()</code></a> for each notification you want in the stack and specify a
-group key. Then call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a> to send it to the wearable.</p>
+group key. Then call <a href="{@docRoot}reference/android/support/wearable/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a> to send it to the wearable.</p>
 
 <pre style="clear:right">
 final static String GROUP_KEY_EMAILS = "group_key_emails";
 
-// Build the notification and pass this builder to WearableNotifications.Builder
+// Build the notification
 NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
          .setContentTitle("New mail from " + sender1)
          .setContentText(subject1)
          .setSmallIcon(R.drawable.new_mail);
 
-Notification notif1 = new WearableNotifications.Builder(builder)
+// Set the group with WearableNotificationOptions.Builder and apply to the notification
+Notification notif1 = new WearableNotificationOptions.Builder()
          .setGroup(GROUP_KEY_EMAILS)
+         .build()
+         .applyTo(builder)
          .build();
 
 // Issue the notification
@@ -52,8 +55,10 @@
 </pre>
 
 <p>Later on, when you create another notification, specify
-the same group key. When you call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a>, this notification appears
-in the same stack as the previous notification, instead of as a new card:</p>
+the same group key. When you call
+<a href="{@docRoot}reference/android/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a>,
+this notification appears in the same stack as the previous notification,
+instead of as a new card:</p>
 
 <pre style="clear:right">
 builder = new NotificationCompat.Builder(mContext)
@@ -62,8 +67,10 @@
          .setSmallIcon(R.drawable.new_mail);
 
 // Use the same group as the previous notification
-Notification notif2 = new WearableNotifications.Builder(builder)
+Notification notif2 = new WearableNotificationOptions.Builder()
          .setGroup(GROUP_KEY_EMAILS)
+         .build()
+         .applyTo(builder)
          .build();
 
 notificationManager.notify(notificationId2, notif);
@@ -72,7 +79,7 @@
 <p>By default, notifications appear in the order in which you added them, with the most recent
   notification visible at the top.  You can define a specific position in the group
   by passing an order position as the second parameter for <a
-href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
+href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#setGroup(java.lang.String, int)">
 <code>setGroup()</code></a>.</p>
 
 
@@ -83,7 +90,7 @@
 <p>It's important that you still provide a summary notification that appears on handheld devices.
 So in addition to adding each unique notification to the same stack group, also add a summary
 notification, but set its order position to be <a
-href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.html#GROUP_ORDER_SUMMARY"><code>GROUP_ORDER_SUMMARY</code></a>.</p>
+href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationsOptions.html#GROUP_ORDER_SUMMARY"><code>GROUP_ORDER_SUMMARY</code></a>.</p>
 
 <p>This notification does not appear in your stack of notifications on the wearable, but
 appears as the only notification on the handheld device.</p>
@@ -92,23 +99,22 @@
 Bitmap largeIcon = BitmapFactory.decodeResource(getResources(),
         R.drawable.ic_large_icon);
 
+// Create an InboxStyle notification
 builder = new NotificationCompat.Builder(this)
+        .setContentTitle("2 new messages")
         .setSmallIcon(R.drawable.ic_small_icon)
-        .setLargeIcon(largeIcon);
+        .setLargeIcon(largeIcon)
+        .setStyle(new NotificationCompat.InboxStyle()
+                .addLine("Alex Faaborg   Check this out")
+                .addLine("Jeff Chang   Launch Party")
+                .setBigContentTitle("2 new messages")
+                .setSummaryText("johndoe@gmail.com"));
 
-// Use the same group key and pass this builder to InboxStyle notification
-WearableNotifications.Builder wearableBuilder = new WearableNotifications
-        .Builder(builder)
-        .setGroup(GROUP_KEY_EMAILS,
-                WearableNotifications.GROUP_ORDER_SUMMARY);
-
-// Build the final notification to show on the handset
-Notification summaryNotification = new NotificationCompat.InboxStyle(
-        wearableBuilder.getCompatBuilder())
-        .addLine("Alex Faaborg   Check this out")
-        .addLine("Jeff Chang   Launch Party")
-        .setBigContentTitle("2 new messages")
-        .setSummaryText("johndoe@gmail.com")
+// Specify the notification to be the group summary
+Notification summaryNotification = new WearableNotificationOptions.Builder()
+        .setGroupSummary(GROUP_KEY_EMAILS)
+        .build()
+        .applyTo(builder)
         .build();
 
 notificationManager.notify(notificationId3, summaryNotification);
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index 9725a61..04225a2 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -175,6 +175,25 @@
         return 0;
     }
 
+    /**
+     * Returns the alpha channel offset in the specified format.
+     *
+     * Supported formats:
+     *      GL_ALPHA
+     *      GL_RGBA
+     */
+    static uint32_t formatAlphaOffset(GLenum format) {
+        switch (format) {
+            case GL_ALPHA:
+                return 0;
+            case GL_RGBA:
+                return 3;
+        }
+
+        ALOGE("unsupported format: %d",format);
+        return 0;
+    }
+
 protected:
     /**
      * Creates a new render buffer in the specified format and dimensions.
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 435736c..485dbf6 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -136,7 +136,7 @@
      * Returns the current clip in local coordinates. The clip rect is
      * transformed by the inverse transform matrix.
      */
-    const Rect& getLocalClip();
+    ANDROID_API const Rect& getLocalClip();
 
     /**
      * Returns the current clip in render target coordinates.
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 08e9a1a..a71db5b 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -217,6 +217,7 @@
     PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer();
 
     uint32_t formatSize = PixelBuffer::formatSize(pixelBuffer->getFormat());
+    uint32_t alpha_channel_offset = PixelBuffer::formatAlphaOffset(pixelBuffer->getFormat());
     uint32_t cacheWidth = cacheTexture->getWidth();
     uint32_t srcStride = formatSize * cacheWidth;
     uint32_t startY = glyph->mStartY * srcStride;
@@ -231,7 +232,7 @@
             memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth);
         } else {
             for (uint32_t i = 0; i < glyph->mBitmapWidth; ++i) {
-                bitmap[bitmapY + dstX + i] = cacheBuffer[cacheY + (glyph->mStartX + i)*formatSize];
+                bitmap[bitmapY + dstX + i] = cacheBuffer[cacheY + (glyph->mStartX + i)*formatSize + alpha_channel_offset];
             }
         }
     }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 1dcfcb8..3a3f76d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -428,7 +428,6 @@
     public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
 
     private static IAudioService sService;
-    private MediaSessionLegacyHelper mSessionHelper;
 
     /**
      * @hide
@@ -439,9 +438,6 @@
                 com.android.internal.R.bool.config_useMasterVolume);
         mUseVolumeKeySounds = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_useVolumeKeySounds);
-        if (USE_SESSIONS) {
-            mSessionHelper = MediaSessionLegacyHelper.getHelper(context);
-        }
     }
 
     private static IAudioService getService()
@@ -478,11 +474,16 @@
      *     or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
      */
     public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
-        IAudioService service = getService();
-        try {
-            service.dispatchMediaKeyEvent(keyEvent);
-        } catch (RemoteException e) {
-            Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
+        if (USE_SESSIONS) {
+            MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+            helper.sendMediaButtonEvent(keyEvent, false);
+        } else {
+            IAudioService service = getService();
+            try {
+                service.dispatchMediaKeyEvent(keyEvent);
+            } catch (RemoteException e) {
+                Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
+            }
         }
     }
 
@@ -2178,7 +2179,8 @@
             Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
         }
         if (USE_SESSIONS) {
-            mSessionHelper.addMediaButtonListener(pi, mContext);
+            MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+            helper.addMediaButtonListener(pi, mContext);
         }
     }
 
@@ -2254,7 +2256,8 @@
             Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
         }
         if (USE_SESSIONS) {
-            mSessionHelper.removeMediaButtonListener(pi);
+            MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+            helper.removeMediaButtonListener(pi);
         }
     }
 
@@ -2281,7 +2284,7 @@
             Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
         }
         if (USE_SESSIONS) {
-            rcClient.registerWithSession(mSessionHelper);
+            rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mContext));
         }
     }
 
@@ -2303,7 +2306,7 @@
             Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
         }
         if (USE_SESSIONS) {
-            rcClient.unregisterWithSession(mSessionHelper);
+            rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mContext));
         }
     }
 
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 724022b..bb8cfa6 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -46,6 +46,7 @@
 import android.hardware.usb.UsbManager;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
+import android.media.session.MediaSessionLegacyHelper;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Environment;
@@ -108,6 +109,10 @@
     /** Debug volumes */
     protected static final boolean DEBUG_VOL = false;
 
+    /** Reroute calls to media session apis */
+    private static final boolean USE_SESSIONS = true;
+    private static final boolean DEBUG_SESSIONS = true;
+
     /** How long to delay before persisting a change in volume/ringer mode. */
     private static final int PERSIST_DELAY = 500;
 
@@ -3472,7 +3477,7 @@
                 if (volume < 0) {
                     volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
                 } else {
-                    volFloat = (float) volume / 1000.0f;
+                    volFloat = volume / 1000.0f;
                 }
 
                 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
@@ -3554,7 +3559,7 @@
                     }
                     Settings.System.putFloatForUser(mContentResolver,
                                                     Settings.System.VOLUME_MASTER,
-                                                    (float)msg.arg1 / (float)1000.0,
+                                                    msg.arg1 / (float)1000.0,
                                                     UserHandle.USER_CURRENT);
                     break;
 
@@ -4325,11 +4330,27 @@
     }
 
     public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
-        mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
+        if (USE_SESSIONS) {
+            if (DEBUG_SESSIONS) {
+                int pid = getCallingPid();
+                Log.w(TAG, "Call to dispatchMediaKeyEvent from " + pid);
+            }
+            MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
+        } else {
+            mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
+        }
     }
 
     public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
-        mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
+        if (USE_SESSIONS) {
+            if (DEBUG_SESSIONS) {
+                int pid = getCallingPid();
+                Log.w(TAG, "Call to dispatchMediaKeyEventUnderWakelock from " + pid);
+            }
+            MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, true);
+        } else {
+            mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
+        }
     }
 
     //==========================================================================================
diff --git a/media/java/android/media/session/MediaMetadata.aidl b/media/java/android/media/MediaMetadata.aidl
similarity index 95%
rename from media/java/android/media/session/MediaMetadata.aidl
rename to media/java/android/media/MediaMetadata.aidl
index 4431d9d..66ee483 100644
--- a/media/java/android/media/session/MediaMetadata.aidl
+++ b/media/java/android/media/MediaMetadata.aidl
@@ -13,6 +13,6 @@
 ** limitations under the License.
 */
 
-package android.media.session;
+package android.media;
 
 parcelable MediaMetadata;
diff --git a/media/java/android/media/session/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
similarity index 98%
rename from media/java/android/media/session/MediaMetadata.java
rename to media/java/android/media/MediaMetadata.java
index 8a8af45..ff73a10 100644
--- a/media/java/android/media/session/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -13,12 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.session;
+package android.media;
 
 import android.graphics.Bitmap;
-import android.media.MediaMetadataEditor;
-import android.media.MediaMetadataRetriever;
-import android.media.Rating;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/media/java/android/media/MediaMetadataEditor.java b/media/java/android/media/MediaMetadataEditor.java
index 1a4e8da..ca44e9d 100644
--- a/media/java/android/media/MediaMetadataEditor.java
+++ b/media/java/android/media/MediaMetadataEditor.java
@@ -17,7 +17,6 @@
 package android.media;
 
 import android.graphics.Bitmap;
-import android.media.session.MediaMetadata;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.util.Log;
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 8368df94..37f45c2 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -24,10 +24,9 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.RectF;
-import android.media.session.MediaMetadata;
 import android.media.session.MediaSessionLegacyHelper;
 import android.media.session.PlaybackState;
-import android.media.session.Session;
+import android.media.session.MediaSession;
 import android.media.session.TransportPerformer;
 import android.os.Bundle;
 import android.os.Handler;
@@ -341,7 +340,7 @@
      */
     public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
 
-    private Session mSession;
+    private MediaSession mSession;
 
     /**
      * Class constructor.
diff --git a/media/java/android/media/routeprovider/RouteConnection.java b/media/java/android/media/routeprovider/RouteConnection.java
index 9214ff8..43692c1 100644
--- a/media/java/android/media/routeprovider/RouteConnection.java
+++ b/media/java/android/media/routeprovider/RouteConnection.java
@@ -40,6 +40,7 @@
  * interfaces. Use {@link #addRouteInterface(String)} to add an interface and
  * {@link #getRouteInterface(String)} to retrieve the interface's handle anytime
  * after it has been added.
+ * @hide
  */
 public final class RouteConnection {
     private static final String TAG = "RouteConnection";
diff --git a/media/java/android/media/routeprovider/RouteInterfaceHandler.java b/media/java/android/media/routeprovider/RouteInterfaceHandler.java
index 9693dc6..e7f8bbf 100644
--- a/media/java/android/media/routeprovider/RouteInterfaceHandler.java
+++ b/media/java/android/media/routeprovider/RouteInterfaceHandler.java
@@ -16,7 +16,7 @@
 package android.media.routeprovider;
 
 import android.media.session.Route;
-import android.media.session.Session;
+import android.media.session.MediaSession;
 import android.media.session.RouteInterface;
 import android.os.Bundle;
 import android.os.Handler;
@@ -33,7 +33,7 @@
  * connected media route.
  * <p>
  * A {@link RouteProviderService} may expose multiple interfaces on a
- * {@link RouteConnection} for a {@link Session} to interact with. A
+ * {@link RouteConnection} for a {@link MediaSession} to interact with. A
  * provider creates an interface with
  * {@link RouteConnection#addRouteInterface(String)} to allow messages to be
  * routed appropriately. Events are then sent through a specific interface and
@@ -47,6 +47,7 @@
  * It is recommended you wrap this interface with a standard implementation to
  * avoid errors, but for simple interfaces this class may be used directly. TODO
  * add link to sample code.
+ * @hide
  */
 public final class RouteInterfaceHandler {
     private static final String TAG = "RouteInterfaceHandler";
@@ -184,7 +185,7 @@
     public abstract static class CommandListener {
         /**
          * This is called when a command is received that matches this
-         * interface. Commands are sent by a {@link Session} that is
+         * interface. Commands are sent by a {@link MediaSession} that is
          * connected to the route this interface is registered with.
          *
          * @param iface The interface the command was received on.
@@ -197,7 +198,7 @@
          *         true may be returned if the command will be handled
          *         asynchronously.
          * @see Route
-         * @see Session
+         * @see MediaSession
          */
         public abstract boolean onCommand(RouteInterfaceHandler iface, String command, Bundle args,
                 ResultReceiver cb);
diff --git a/media/java/android/media/routeprovider/RoutePlaybackControlsHandler.java b/media/java/android/media/routeprovider/RoutePlaybackControlsHandler.java
index dcef79a..f2c40d2 100644
--- a/media/java/android/media/routeprovider/RoutePlaybackControlsHandler.java
+++ b/media/java/android/media/routeprovider/RoutePlaybackControlsHandler.java
@@ -28,6 +28,7 @@
  * Standard wrapper for using playback controls over a {@link RouteInterfaceHandler}.
  * This is the provider half of the interface. Sessions should use
  * {@link RoutePlaybackControls} to interact with this interface.
+ * @hide
  */
 public final class RoutePlaybackControlsHandler {
     private static final String TAG = "RoutePlaybackControls";
diff --git a/media/java/android/media/routeprovider/RouteProviderService.java b/media/java/android/media/routeprovider/RouteProviderService.java
index 6ebfb5b..a6ef0bb 100644
--- a/media/java/android/media/routeprovider/RouteProviderService.java
+++ b/media/java/android/media/routeprovider/RouteProviderService.java
@@ -64,6 +64,7 @@
  *       &lt;/intent-filter>
  *   &lt;/service>
  * </pre>
+ * @hide
  */
 public abstract class RouteProviderService extends Service {
     private static final String TAG = "RouteProvider";
diff --git a/media/java/android/media/routeprovider/RouteRequest.java b/media/java/android/media/routeprovider/RouteRequest.java
index 68475c0..2ba75de 100644
--- a/media/java/android/media/routeprovider/RouteRequest.java
+++ b/media/java/android/media/routeprovider/RouteRequest.java
@@ -16,7 +16,7 @@
 package android.media.routeprovider;
 
 import android.media.session.RouteOptions;
-import android.media.session.SessionInfo;
+import android.media.session.MediaSessionInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -30,16 +30,17 @@
  * provides the full set of connection parameters they would like to use for a
  * connection. An app that can connect in multiple ways will be represented by
  * multiple requests.
+ * @hide
  */
 public final class RouteRequest implements Parcelable {
-    private final SessionInfo mSessionInfo;
+    private final MediaSessionInfo mSessionInfo;
     private final RouteOptions mOptions;
     private final boolean mActive;
 
     /**
      * @hide
      */
-    public RouteRequest(SessionInfo info, RouteOptions connRequest,
+    public RouteRequest(MediaSessionInfo info, RouteOptions connRequest,
             boolean active) {
         mSessionInfo = info;
         mOptions = connRequest;
@@ -47,7 +48,7 @@
     }
 
     private RouteRequest(Parcel in) {
-        mSessionInfo = SessionInfo.CREATOR.createFromParcel(in);
+        mSessionInfo = MediaSessionInfo.CREATOR.createFromParcel(in);
         mOptions = RouteOptions.CREATOR.createFromParcel(in);
         mActive = in.readInt() != 0;
     }
@@ -57,7 +58,7 @@
      *
      * @return Info on the session making the request
      */
-    public SessionInfo getSessionInfo() {
+    public MediaSessionInfo getSessionInfo() {
         return mSessionInfo;
     }
 
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 096550f..c4233c3 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -15,8 +15,8 @@
 
 package android.media.session;
 
+import android.media.MediaMetadata;
 import android.media.session.ISessionController;
-import android.media.session.MediaMetadata;
 import android.media.session.RouteOptions;
 import android.media.session.RouteCommand;
 import android.media.session.RouteInfo;
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 1552513..7b0412e 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -28,7 +28,7 @@
  */
 oneway interface ISessionCallback {
     void onCommand(String command, in Bundle extras, in ResultReceiver cb);
-    void onMediaButton(in Intent mediaButtonIntent);
+    void onMediaButton(in Intent mediaButtonIntent, in ResultReceiver cb);
     void onRequestRouteChange(in RouteInfo route);
     void onRouteConnected(in RouteInfo route, in RouteOptions options);
     void onRouteDisconnected(in RouteInfo route, int reason);
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index e2e046f..5ddb6db 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -16,9 +16,9 @@
 package android.media.session;
 
 import android.content.Intent;
+import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.session.ISessionControllerCallback;
-import android.media.session.MediaMetadata;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.os.ResultReceiver;
diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
index bc1ae05..e823153 100644
--- a/media/java/android/media/session/ISessionControllerCallback.aidl
+++ b/media/java/android/media/session/ISessionControllerCallback.aidl
@@ -15,7 +15,7 @@
 
 package android.media.session;
 
-import android.media.session.MediaMetadata;
+import android.media.MediaMetadata;
 import android.media.session.RouteInfo;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index e341647..38b92932 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -19,6 +19,7 @@
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
 import android.os.Bundle;
+import android.view.KeyEvent;
 
 /**
  * Interface to the MediaSessionManagerService
@@ -27,4 +28,5 @@
 interface ISessionManager {
     ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
     List<IBinder> getSessions(in ComponentName compName, int userId);
+    void dispatchMediaKeyEvent(in KeyEvent keyEvent, boolean needWakeLock);
 }
\ No newline at end of file
diff --git a/media/java/android/media/session/SessionController.java b/media/java/android/media/session/MediaController.java
similarity index 90%
rename from media/java/android/media/session/SessionController.java
rename to media/java/android/media/session/MediaController.java
index dc4f7d9..642ac2f 100644
--- a/media/java/android/media/session/SessionController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -16,6 +16,7 @@
 
 package android.media.session;
 
+import android.media.MediaMetadata;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -34,13 +35,13 @@
  * other commands can be sent to the session. A callback may be registered to
  * receive updates from the session, such as metadata and play state changes.
  * <p>
- * A MediaController can be created through {@link SessionManager} if you
+ * A MediaController can be created through {@link MediaSessionManager} if you
  * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or directly if
- * you have a {@link SessionToken} from the session owner.
+ * you have a {@link MediaSessionToken} from the session owner.
  * <p>
  * MediaController objects are thread-safe.
  */
-public final class SessionController {
+public final class MediaController {
     private static final String TAG = "SessionController";
 
     private static final int MSG_EVENT = 1;
@@ -58,15 +59,15 @@
 
     private TransportController mTransportController;
 
-    private SessionController(ISessionController sessionBinder) {
+    private MediaController(ISessionController sessionBinder) {
         mSessionBinder = sessionBinder;
     }
 
     /**
      * @hide
      */
-    public static SessionController fromBinder(ISessionController sessionBinder) {
-        SessionController controller = new SessionController(sessionBinder);
+    public static MediaController fromBinder(ISessionController sessionBinder) {
+        MediaController controller = new MediaController(sessionBinder);
         try {
             controller.mSessionBinder.registerCallbackListener(controller.mCbStub);
             if (controller.mSessionBinder.isTransportControlEnabled()) {
@@ -87,7 +88,7 @@
      * @param token The session token to use
      * @return A controller for the session or null
      */
-    public static SessionController fromToken(SessionToken token) {
+    public static MediaController fromToken(MediaSessionToken token) {
         return fromBinder(token.getBinder());
     }
 
@@ -184,6 +185,8 @@
     /**
      * Request that the route picker be shown for this session. This should
      * generally be called in response to a user action.
+     *
+     * @hide
      */
     public void showRoutePicker() {
         try {
@@ -285,22 +288,23 @@
         /**
          * Override to handle route changes for this session.
          *
-         * @param route
+         * @param route The new route
+         * @hide
          */
         public void onRouteChanged(RouteInfo route) {
         }
     }
 
     private final static class CallbackStub extends ISessionControllerCallback.Stub {
-        private final WeakReference<SessionController> mController;
+        private final WeakReference<MediaController> mController;
 
-        public CallbackStub(SessionController controller) {
-            mController = new WeakReference<SessionController>(controller);
+        public CallbackStub(MediaController controller) {
+            mController = new WeakReference<MediaController>(controller);
         }
 
         @Override
         public void onEvent(String event, Bundle extras) {
-            SessionController controller = mController.get();
+            MediaController controller = mController.get();
             if (controller != null) {
                 controller.postEvent(event, extras);
             }
@@ -308,7 +312,7 @@
 
         @Override
         public void onRouteChanged(RouteInfo route) {
-            SessionController controller = mController.get();
+            MediaController controller = mController.get();
             if (controller != null) {
                 controller.postRouteChanged(route);
             }
@@ -316,7 +320,7 @@
 
         @Override
         public void onPlaybackStateChanged(PlaybackState state) {
-            SessionController controller = mController.get();
+            MediaController controller = mController.get();
             if (controller != null) {
                 TransportController tc = controller.getTransportController();
                 if (tc != null) {
@@ -327,7 +331,7 @@
 
         @Override
         public void onMetadataChanged(MediaMetadata metadata) {
-            SessionController controller = mController.get();
+            MediaController controller = mController.get();
             if (controller != null) {
                 TransportController tc = controller.getTransportController();
                 if (tc != null) {
@@ -339,9 +343,9 @@
     }
 
     private final static class MessageHandler extends Handler {
-        private final SessionController.Callback mCallback;
+        private final MediaController.Callback mCallback;
 
-        public MessageHandler(Looper looper, SessionController.Callback cb) {
+        public MessageHandler(Looper looper, MediaController.Callback cb) {
             super(looper, null, true);
             mCallback = cb;
         }
diff --git a/media/java/android/media/session/Session.java b/media/java/android/media/session/MediaSession.java
similarity index 89%
rename from media/java/android/media/session/Session.java
rename to media/java/android/media/session/MediaSession.java
index 2ffced6..5b9adaa 100644
--- a/media/java/android/media/session/Session.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -36,21 +36,21 @@
 import java.util.List;
 
 /**
- * Allows interaction with media controllers, media routes, volume keys, media
- * buttons, and transport controls.
+ * Allows interaction with media controllers, volume keys, media buttons, and
+ * transport controls.
  * <p>
  * A MediaSession should be created when an app wants to publish media playback
- * information or negotiate with a media route. In general an app only needs one
- * session for all playback, though multiple sessions can be created for sending
- * media to multiple routes or to provide finer grain controls of media.
+ * information or handle media keys. In general an app only needs one session
+ * for all playback, though multiple sessions can be created to provide finer
+ * grain controls of media.
  * <p>
  * A MediaSession is created by calling
- * {@link SessionManager#createSession(String)}. Once a session is created apps
- * that have the MEDIA_CONTENT_CONTROL permission can interact with the session
- * through
- * {@link SessionManager#getActiveSessions(android.content.ComponentName)}. The
- * owner of the session may also use {@link #getSessionToken()} to allow apps
- * without this permission to create a {@link SessionController} to interact
+ * {@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.
  * <p>
  * To receive commands, media keys, and other events a Callback must be set with
@@ -61,7 +61,7 @@
  * <p>
  * MediaSession objects are thread safe
  */
-public final class Session {
+public final class MediaSession {
     private static final String TAG = "Session";
 
     /**
@@ -89,31 +89,43 @@
     /**
      * Indicates the session was disconnected because the user that the session
      * belonged to is stopping.
+     * @hide
      */
     public static final int DISCONNECT_REASON_USER_STOPPING = 1;
 
     /**
      * Indicates the session was disconnected because the provider disconnected
      * the route.
+     * @hide
      */
     public static final int DISCONNECT_REASON_PROVIDER_DISCONNECTED = 2;
 
     /**
      * Indicates the session was disconnected because the route has changed.
+     * @hide
      */
     public static final int DISCONNECT_REASON_ROUTE_CHANGED = 3;
 
     /**
      * Indicates the session was disconnected because the session owner
      * requested it disconnect.
+     * @hide
      */
     public static final int DISCONNECT_REASON_SESSION_DISCONNECTED = 4;
 
     /**
      * Indicates the session was disconnected because it was destroyed.
+     * @hide
      */
     public static final int DISCONNECT_REASON_SESSION_DESTROYED = 5;
 
+    /**
+     * Status code indicating the call was handled.
+     *
+     * @hide
+     */
+    public static final int RESULT_SUCCESS = 0;
+
     private static final int MSG_MEDIA_BUTTON = 1;
     private static final int MSG_COMMAND = 2;
     private static final int MSG_ROUTE_CHANGE = 3;
@@ -126,7 +138,7 @@
 
     private final Object mLock = new Object();
 
-    private final SessionToken mSessionToken;
+    private final MediaSessionToken mSessionToken;
     private final ISession mBinder;
     private final CallbackStub mCbStub;
 
@@ -143,7 +155,7 @@
     /**
      * @hide
      */
-    public Session(ISession binder, CallbackStub cbStub) {
+    public MediaSession(ISession binder, CallbackStub cbStub) {
         mBinder = binder;
         mCbStub = cbStub;
         ISessionController controllerBinder = null;
@@ -152,7 +164,7 @@
         } catch (RemoteException e) {
             throw new RuntimeException("Dead object in MediaSessionController constructor: ", e);
         }
-        mSessionToken = new SessionToken(controllerBinder);
+        mSessionToken = new MediaSessionToken(controllerBinder);
         mPerformer = new TransportPerformer(mBinder);
     }
 
@@ -167,7 +179,7 @@
 
     /**
      * Add a callback to receive updates for the MediaSession. This includes
-     * events like route updates, media buttons, and focus changes.
+     * media button and volume events.
      *
      * @param callback The callback to receive updates on.
      * @param handler The handler that events should be posted on.
@@ -288,13 +300,13 @@
 
     /**
      * Retrieve a token object that can be used by apps to create a
-     * {@link SessionController} for interacting with this session. The owner of
+     * {@link MediaController} for interacting with this session. The owner of
      * the session is responsible for deciding how to distribute these tokens.
      *
      * @return A token that can be used to create a MediaController for this
      *         session
      */
-    public SessionToken getSessionToken() {
+    public MediaSessionToken getSessionToken() {
         return mSessionToken;
     }
 
@@ -304,8 +316,8 @@
      * Connection updates will be sent to the callback's
      * {@link Callback#onRouteConnected(Route)} and
      * {@link Callback#onRouteDisconnected(Route, int)} methods. If the
-     * connection fails {@link Callback#onRouteDisconnected(Route, int)}
-     * will be called.
+     * connection fails {@link Callback#onRouteDisconnected(Route, int)} will be
+     * called.
      * <p>
      * If you already have a connection to this route it will be disconnected
      * before the new connection is established. TODO add an easy way to compare
@@ -313,6 +325,7 @@
      *
      * @param route The route the app is trying to connect to.
      * @param request The connection request to use.
+     * @hide
      */
     public void connect(RouteInfo route, RouteOptions request) {
         if (route == null) {
@@ -331,6 +344,8 @@
     /**
      * Disconnect from the current route. After calling you will be switched
      * back to the default route.
+     *
+     * @hide
      */
     public void disconnect() {
         if (mRoute != null) {
@@ -347,6 +362,7 @@
      * will be used for picking valid routes.
      *
      * @param options The set of route options your app may use to connect.
+     * @hide
      */
     public void setRouteOptions(List<RouteOptions> options) {
         try {
@@ -491,6 +507,7 @@
          * ongoing playback if necessary.
          *
          * @param route
+         * @hide
          */
         public void onRequestRouteChange(RouteInfo route) {
         }
@@ -500,6 +517,7 @@
          * are now valid.
          *
          * @param route The route that was connected
+         * @hide
          */
         public void onRouteConnected(Route route) {
         }
@@ -519,6 +537,7 @@
          *
          * @param route The route that disconnected
          * @param reason The reason for the disconnect
+         * @hide
          */
         public void onRouteDisconnected(Route route, int reason) {
         }
@@ -528,32 +547,36 @@
      * @hide
      */
     public static class CallbackStub extends ISessionCallback.Stub {
-        private WeakReference<Session> mMediaSession;
+        private WeakReference<MediaSession> mMediaSession;
 
-        public void setMediaSession(Session session) {
-            mMediaSession = new WeakReference<Session>(session);
+        public void setMediaSession(MediaSession session) {
+            mMediaSession = new WeakReference<MediaSession>(session);
         }
 
         @Override
         public void onCommand(String command, Bundle extras, ResultReceiver cb)
                 throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.postCommand(command, extras, cb);
             }
         }
 
         @Override
-        public void onMediaButton(Intent mediaButtonIntent) throws RemoteException {
-            Session session = mMediaSession.get();
+        public void onMediaButton(Intent mediaButtonIntent, ResultReceiver cb)
+                throws RemoteException {
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.postMediaButton(mediaButtonIntent);
             }
+            if (cb != null) {
+                cb.send(RESULT_SUCCESS, null);
+            }
         }
 
         @Override
         public void onRequestRouteChange(RouteInfo route) throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.postRequestRouteChange(route);
             }
@@ -561,7 +584,7 @@
 
         @Override
         public void onRouteConnected(RouteInfo route, RouteOptions options) {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.postRouteConnected(route, options);
             }
@@ -569,7 +592,7 @@
 
         @Override
         public void onRouteDisconnected(RouteInfo route, int reason) {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.postRouteDisconnected(route, reason);
             }
@@ -577,7 +600,7 @@
 
         @Override
         public void onPlay() throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 TransportPerformer tp = session.getTransportPerformer();
                 if (tp != null) {
@@ -588,7 +611,7 @@
 
         @Override
         public void onPause() throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 TransportPerformer tp = session.getTransportPerformer();
                 if (tp != null) {
@@ -599,7 +622,7 @@
 
         @Override
         public void onStop() throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 TransportPerformer tp = session.getTransportPerformer();
                 if (tp != null) {
@@ -610,7 +633,7 @@
 
         @Override
         public void onNext() throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 TransportPerformer tp = session.getTransportPerformer();
                 if (tp != null) {
@@ -621,7 +644,7 @@
 
         @Override
         public void onPrevious() throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 TransportPerformer tp = session.getTransportPerformer();
                 if (tp != null) {
@@ -632,7 +655,7 @@
 
         @Override
         public void onFastForward() throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 TransportPerformer tp = session.getTransportPerformer();
                 if (tp != null) {
@@ -643,7 +666,7 @@
 
         @Override
         public void onRewind() throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 TransportPerformer tp = session.getTransportPerformer();
                 if (tp != null) {
@@ -654,7 +677,7 @@
 
         @Override
         public void onSeekTo(long pos) throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 TransportPerformer tp = session.getTransportPerformer();
                 if (tp != null) {
@@ -665,7 +688,7 @@
 
         @Override
         public void onRate(Rating rating) throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 TransportPerformer tp = session.getTransportPerformer();
                 if (tp != null) {
@@ -676,7 +699,7 @@
 
         @Override
         public void onRouteEvent(RouteEvent event) throws RemoteException {
-            Session session = mMediaSession.get();
+            MediaSession session = mMediaSession.get();
             if (session != null) {
                 RouteInterface.EventListener iface
                         = session.mInterfaceListeners.get(event.getIface());
@@ -697,9 +720,9 @@
     }
 
     private class MessageHandler extends Handler {
-        private Session.Callback mCallback;
+        private MediaSession.Callback mCallback;
 
-        public MessageHandler(Looper looper, Session.Callback callback) {
+        public MessageHandler(Looper looper, MediaSession.Callback callback) {
             super(looper, null, true);
             mCallback = callback;
         }
diff --git a/media/java/android/media/session/SessionInfo.java b/media/java/android/media/session/MediaSessionInfo.java
similarity index 78%
rename from media/java/android/media/session/SessionInfo.java
rename to media/java/android/media/session/MediaSessionInfo.java
index 2b65528..3d8d33f 100644
--- a/media/java/android/media/session/SessionInfo.java
+++ b/media/java/android/media/session/MediaSessionInfo.java
@@ -21,19 +21,19 @@
 /**
  * Information about a media session, including the owner's package name.
  */
-public final class SessionInfo implements Parcelable {
+public final class MediaSessionInfo implements Parcelable {
     private final String mId;
     private final String mPackageName;
 
     /**
      * @hide
      */
-    public SessionInfo(String id, String packageName) {
+    public MediaSessionInfo(String id, String packageName) {
         mId = id;
         mPackageName = packageName;
     }
 
-    private SessionInfo(Parcel in) {
+    private MediaSessionInfo(Parcel in) {
         mId = in.readString();
         mPackageName = in.readString();
     }
@@ -72,16 +72,16 @@
         dest.writeString(mPackageName);
     }
 
-    public static final Parcelable.Creator<SessionInfo> CREATOR
-            = new Parcelable.Creator<SessionInfo>() {
+    public static final Parcelable.Creator<MediaSessionInfo> CREATOR
+            = new Parcelable.Creator<MediaSessionInfo>() {
         @Override
-        public SessionInfo createFromParcel(Parcel in) {
-            return new SessionInfo(in);
+        public MediaSessionInfo createFromParcel(Parcel in) {
+            return new MediaSessionInfo(in);
         }
 
         @Override
-        public SessionInfo[] newArray(int size) {
-            return new SessionInfo[size];
+        public MediaSessionInfo[] newArray(int size) {
+            return new MediaSessionInfo[size];
         }
     };
 }
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index c07229d..2e02a66 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -35,11 +35,12 @@
  */
 public class MediaSessionLegacyHelper {
     private static final String TAG = "MediaSessionHelper";
+    private static final boolean DEBUG = true;
 
     private static final Object sLock = new Object();
     private static MediaSessionLegacyHelper sInstance;
 
-    private SessionManager mSessionManager;
+    private MediaSessionManager mSessionManager;
     private Handler mHandler = new Handler(Looper.getMainLooper());
     // The legacy APIs use PendingIntents to register/unregister media button
     // receivers and these are associated with RCC.
@@ -47,11 +48,14 @@
             = new ArrayMap<PendingIntent, SessionHolder>();
 
     private MediaSessionLegacyHelper(Context context) {
-        mSessionManager = (SessionManager) context
+        mSessionManager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
     }
 
     public static MediaSessionLegacyHelper getHelper(Context context) {
+        if (DEBUG) {
+            Log.d(TAG, "Attempting to get helper with context " + context);
+        }
         synchronized (sLock) {
             if (sInstance == null) {
                 sInstance = new MediaSessionLegacyHelper(context);
@@ -60,17 +64,30 @@
         return sInstance;
     }
 
-    public Session getSession(PendingIntent pi) {
+    public MediaSession getSession(PendingIntent pi) {
         SessionHolder holder = mSessions.get(pi);
         return holder == null ? null : holder.mSession;
     }
 
-    public void addRccListener(PendingIntent pi, TransportPerformer.Listener listener) {
+    public void sendMediaButtonEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        mSessionManager.dispatchMediaKeyEvent(keyEvent, needWakeLock);
+        if (DEBUG) {
+            Log.d(TAG, "dispatched media key " + keyEvent);
+        }
+    }
 
+    public void addRccListener(PendingIntent pi, TransportPerformer.Listener 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) {
+                    Log.d(TAG, "addRccListener listener already added.");
+                }
                 // This is already the registered listener, ignore
                 return;
             }
@@ -79,50 +96,82 @@
         }
         performer.addListener(listener, mHandler);
         holder.mRccListener = listener;
-        holder.mFlags |= Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
+        holder.mFlags |= MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS;
         holder.mSession.setFlags(holder.mFlags);
         holder.update();
+        if (DEBUG) {
+            Log.d(TAG, "Added rcc listener for " + pi + ".");
+        }
     }
 
     public void removeRccListener(PendingIntent pi) {
+        if (pi == null) {
+            return;
+        }
         SessionHolder holder = getHolder(pi, false);
         if (holder != null && holder.mRccListener != null) {
             holder.mSession.getTransportPerformer().removeListener(holder.mRccListener);
             holder.mRccListener = null;
-            holder.mFlags &= ~Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
+            holder.mFlags &= ~MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS;
             holder.mSession.setFlags(holder.mFlags);
             holder.update();
+            if (DEBUG) {
+                Log.d(TAG, "Removed rcc listener for " + pi + ".");
+            }
         }
     }
 
     public void addMediaButtonListener(PendingIntent pi,
             Context context) {
+        if (pi == null) {
+            Log.w(TAG, "Pending intent was null, can't addMediaButtonListener.");
+            return;
+        }
         SessionHolder holder = getHolder(pi, true);
         if (holder.mMediaButtonListener != null) {
-            // Already have this listener registered
+            // Already have this listener registered, but update it anyway as
+            // the extras may have changed.
+            if (DEBUG) {
+                Log.d(TAG, "addMediaButtonListener already added " + pi);
+            }
             return;
         }
         holder.mMediaButtonListener = new MediaButtonListener(pi, context);
-        holder.mFlags |= Session.FLAG_HANDLES_MEDIA_BUTTONS;
+        holder.mFlags |= MediaSession.FLAG_HANDLES_MEDIA_BUTTONS;
         holder.mSession.setFlags(holder.mFlags);
         holder.mSession.getTransportPerformer().addListener(holder.mMediaButtonListener, mHandler);
+
+        holder.mMediaButtonReceiver = new MediaButtonReceiver(pi, context);
+        holder.mSession.addCallback(holder.mMediaButtonReceiver, mHandler);
+        if (DEBUG) {
+            Log.d(TAG, "addMediaButtonListener added " + pi);
+        }
     }
 
     public void removeMediaButtonListener(PendingIntent pi) {
+        if (pi == null) {
+            return;
+        }
         SessionHolder holder = getHolder(pi, false);
         if (holder != null && holder.mMediaButtonListener != null) {
             holder.mSession.getTransportPerformer().removeListener(holder.mMediaButtonListener);
-            holder.mFlags &= ~Session.FLAG_HANDLES_MEDIA_BUTTONS;
+            holder.mFlags &= ~MediaSession.FLAG_HANDLES_MEDIA_BUTTONS;
             holder.mSession.setFlags(holder.mFlags);
             holder.mMediaButtonListener = null;
+
+            holder.mSession.removeCallback(holder.mMediaButtonReceiver);
+            holder.mMediaButtonReceiver = null;
             holder.update();
+            if (DEBUG) {
+                Log.d(TAG, "removeMediaButtonListener removed " + pi);
+            }
         }
     }
 
     private SessionHolder getHolder(PendingIntent pi, boolean createIfMissing) {
         SessionHolder holder = mSessions.get(pi);
         if (holder == null && createIfMissing) {
-            Session session = mSessionManager.createSession(TAG);
+            MediaSession session = mSessionManager.createSession(TAG);
             session.setActive(true);
             holder = new SessionHolder(session, pi);
             mSessions.put(pi, holder);
@@ -130,7 +179,32 @@
         return holder;
     }
 
-    public static class MediaButtonListener extends TransportPerformer.Listener {
+    private static void sendKeyEvent(PendingIntent pi, Context context, Intent intent) {
+        try {
+            pi.send(context, 0, intent);
+        } catch (CanceledException e) {
+            Log.e(TAG, "Error sending media key down event:", e);
+            // Don't bother sending up if down failed
+            return;
+        }
+    }
+
+    private static final class MediaButtonReceiver extends MediaSession.Callback {
+        private final PendingIntent mPendingIntent;
+        private final Context mContext;
+
+        public MediaButtonReceiver(PendingIntent pi, Context context) {
+            mPendingIntent = pi;
+            mContext = context;
+        }
+
+        @Override
+        public void onMediaButton(Intent mediaButtonIntent) {
+            MediaSessionLegacyHelper.sendKeyEvent(mPendingIntent, mContext, mediaButtonIntent);
+        }
+    }
+
+    private static final class MediaButtonListener extends TransportPerformer.Listener {
         private final PendingIntent mPendingIntent;
         private final Context mContext;
 
@@ -179,32 +253,27 @@
             Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
 
             intent.putExtra(Intent.EXTRA_KEY_EVENT, ke);
-            try {
-                mPendingIntent.send(mContext, 0, intent);
-            } catch (CanceledException e) {
-                Log.e(TAG, "Error sending media key down event:", e);
-                // Don't bother sending up if down failed
-                return;
-            }
+            MediaSessionLegacyHelper.sendKeyEvent(mPendingIntent, mContext, intent);
 
             ke = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
             intent.putExtra(Intent.EXTRA_KEY_EVENT, ke);
-            try {
-                mPendingIntent.send(mContext, 0, intent);
-            } catch (CanceledException e) {
-                Log.e(TAG, "Error sending media key up event:", e);
+            MediaSessionLegacyHelper.sendKeyEvent(mPendingIntent, mContext, intent);
+
+            if (DEBUG) {
+                Log.d(TAG, "Sent " + keyCode + " to pending intent " + mPendingIntent);
             }
         }
     }
 
     private class SessionHolder {
-        public final Session mSession;
+        public final MediaSession mSession;
         public final PendingIntent mPi;
         public MediaButtonListener mMediaButtonListener;
+        public MediaButtonReceiver mMediaButtonReceiver;
         public TransportPerformer.Listener mRccListener;
         public int mFlags;
 
-        public SessionHolder(Session session, PendingIntent pi) {
+        public SessionHolder(MediaSession session, PendingIntent pi) {
             mSession = session;
             mPi = pi;
         }
@@ -213,10 +282,6 @@
             if (mMediaButtonListener == null && mRccListener == null) {
                 mSession.release();
                 mSessions.remove(mPi);
-            } else if (mMediaButtonListener != null && mRccListener != null) {
-                // TODO set session to active
-            } else {
-                // TODO set session to inactive
             }
         }
     }
diff --git a/media/java/android/media/session/SessionManager.java b/media/java/android/media/session/MediaSessionManager.java
similarity index 72%
rename from media/java/android/media/session/SessionManager.java
rename to media/java/android/media/session/MediaSessionManager.java
index 1eb3b7a..0589a7d 100644
--- a/media/java/android/media/session/SessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -25,6 +25,7 @@
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.util.Log;
+import android.view.KeyEvent;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -38,10 +39,10 @@
  * get an instance of this class.
  * <p>
  *
- * @see Session
- * @see SessionController
+ * @see MediaSession
+ * @see MediaController
  */
-public final class SessionManager {
+public final class MediaSessionManager {
     private static final String TAG = "SessionManager";
 
     private final ISessionManager mService;
@@ -51,7 +52,7 @@
     /**
      * @hide
      */
-    public SessionManager(Context context) {
+    public MediaSessionManager(Context context) {
         // Consider rewriting like DisplayManagerGlobal
         // Decide if we need context
         mContext = context;
@@ -63,9 +64,9 @@
      * Creates a new session.
      *
      * @param tag A short name for debugging purposes
-     * @return a {@link Session} for the new session
+     * @return a {@link MediaSession} for the new session
      */
-    public Session createSession(String tag) {
+    public MediaSession createSession(String tag) {
         return createSessionAsUser(tag, UserHandle.myUserId());
     }
 
@@ -77,13 +78,13 @@
      *
      * @param tag A short name for debugging purposes
      * @param userId The user id to create the session as.
-     * @return a {@link Session} for the new session
+     * @return a {@link MediaSession} for the new session
      * @hide
      */
-    public Session createSessionAsUser(String tag, int userId) {
+    public MediaSession createSessionAsUser(String tag, int userId) {
         try {
-            Session.CallbackStub cbStub = new Session.CallbackStub();
-            Session session = new Session(mService
+            MediaSession.CallbackStub cbStub = new MediaSession.CallbackStub();
+            MediaSession session = new MediaSession(mService
                     .createSession(mContext.getPackageName(), cbStub, tag, userId), cbStub);
             cbStub.setMediaSession(session);
 
@@ -106,7 +107,7 @@
      *            May be null.
      * @return A list of controllers for ongoing sessions
      */
-    public List<SessionController> getActiveSessions(ComponentName notificationListener) {
+    public List<MediaController> getActiveSessions(ComponentName notificationListener) {
         return getActiveSessionsForUser(notificationListener, UserHandle.myUserId());
     }
 
@@ -123,13 +124,13 @@
      * @return A list of controllers for ongoing sessions.
      * @hide
      */
-    public List<SessionController> getActiveSessionsForUser(ComponentName notificationListener,
+    public List<MediaController> getActiveSessionsForUser(ComponentName notificationListener,
             int userId) {
-        ArrayList<SessionController> controllers = new ArrayList<SessionController>();
+        ArrayList<MediaController> controllers = new ArrayList<MediaController>();
         try {
             List<IBinder> binders = mService.getSessions(notificationListener, userId);
             for (int i = binders.size() - 1; i >= 0; i--) {
-                SessionController controller = SessionController.fromBinder(ISessionController.Stub
+                MediaController controller = MediaController.fromBinder(ISessionController.Stub
                         .asInterface(binders.get(i)));
                 controllers.add(controller);
             }
@@ -138,4 +139,30 @@
         }
         return controllers;
     }
+
+    /**
+     * Send a media key event. The receiver will be selected automatically.
+     *
+     * @param keyEvent The KeyEvent to send.
+     * @hide
+     */
+    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+        dispatchMediaKeyEvent(keyEvent, false);
+    }
+
+    /**
+     * Send a media key event. The receiver will be selected automatically.
+     *
+     * @param keyEvent The KeyEvent to send
+     * @param needWakeLock true if a wake lock should be held while sending the
+     *            key
+     * @hide
+     */
+    public void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        try {
+            mService.dispatchMediaKeyEvent(keyEvent, needWakeLock);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to send key event.", e);
+        }
+    }
 }
diff --git a/media/java/android/media/session/SessionToken.aidl b/media/java/android/media/session/MediaSessionToken.aidl
similarity index 95%
rename from media/java/android/media/session/SessionToken.aidl
rename to media/java/android/media/session/MediaSessionToken.aidl
index db35f85..5812682 100644
--- a/media/java/android/media/session/SessionToken.aidl
+++ b/media/java/android/media/session/MediaSessionToken.aidl
@@ -15,4 +15,4 @@
 
 package android.media.session;
 
-parcelable SessionToken;
+parcelable MediaSessionToken;
diff --git a/media/java/android/media/session/SessionToken.java b/media/java/android/media/session/MediaSessionToken.java
similarity index 72%
rename from media/java/android/media/session/SessionToken.java
rename to media/java/android/media/session/MediaSessionToken.java
index 59486f6..f5569a4 100644
--- a/media/java/android/media/session/SessionToken.java
+++ b/media/java/android/media/session/MediaSessionToken.java
@@ -20,17 +20,17 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-public class SessionToken implements Parcelable {
+public class MediaSessionToken implements Parcelable {
     private ISessionController mBinder;
 
     /**
      * @hide
      */
-    SessionToken(ISessionController binder) {
+    MediaSessionToken(ISessionController binder) {
         mBinder = binder;
     }
 
-    private SessionToken(Parcel in) {
+    private MediaSessionToken(Parcel in) {
         mBinder = ISessionController.Stub.asInterface(in.readStrongBinder());
     }
 
@@ -51,16 +51,16 @@
         dest.writeStrongBinder(mBinder.asBinder());
     }
 
-    public static final Parcelable.Creator<SessionToken> CREATOR
-            = new Parcelable.Creator<SessionToken>() {
+    public static final Parcelable.Creator<MediaSessionToken> CREATOR
+            = new Parcelable.Creator<MediaSessionToken>() {
         @Override
-        public SessionToken createFromParcel(Parcel in) {
-            return new SessionToken(in);
+        public MediaSessionToken createFromParcel(Parcel in) {
+            return new MediaSessionToken(in);
         }
 
         @Override
-        public SessionToken[] newArray(int size) {
-            return new SessionToken[size];
+        public MediaSessionToken[] newArray(int size) {
+            return new MediaSessionToken[size];
         }
     };
 }
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 3254e5d..7ef38eaa 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -21,7 +21,7 @@
 import android.os.SystemClock;
 
 /**
- * Playback state for a {@link Session}. This includes a state like
+ * Playback state for a {@link MediaSession}. This includes a state like
  * {@link PlaybackState#PLAYSTATE_PLAYING}, the current playback position,
  * and the current control capabilities.
  */
@@ -160,6 +160,7 @@
      * 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.
+     * @hide
      */
     public final static int PLAYSTATE_CONNECTING = 8;
 
diff --git a/media/java/android/media/session/Route.java b/media/java/android/media/session/Route.java
index c9530a6..935eb5b 100644
--- a/media/java/android/media/session/Route.java
+++ b/media/java/android/media/session/Route.java
@@ -28,17 +28,18 @@
  * to. The MediaRoute must be used to get {@link RouteInterface}
  * instances which can be used to communicate over a specific interface on the
  * route.
+ * @hide
  */
 public final class Route {
     private static final String TAG = "Route";
     private final RouteInfo mInfo;
-    private final Session mSession;
+    private final MediaSession mSession;
     private final RouteOptions mOptions;
 
     /**
      * @hide
      */
-    public Route(RouteInfo info, RouteOptions options, Session session) {
+    public Route(RouteInfo info, RouteOptions options, MediaSession session) {
         if (info == null || options == null) {
             throw new IllegalStateException("Route info was not valid!");
         }
@@ -93,7 +94,7 @@
     /**
      * @hide
      */
-    Session getSession() {
+    MediaSession getSession() {
         return mSession;
     }
 }
diff --git a/media/java/android/media/session/RouteInfo.java b/media/java/android/media/session/RouteInfo.java
index 17df969..02f78f9 100644
--- a/media/java/android/media/session/RouteInfo.java
+++ b/media/java/android/media/session/RouteInfo.java
@@ -25,6 +25,7 @@
 /**
  * Information about a route, including its display name, a way to identify it,
  * and the ways it can be connected to.
+ * @hide
  */
 public final class RouteInfo implements Parcelable {
     private final String mName;
diff --git a/media/java/android/media/session/RouteInterface.java b/media/java/android/media/session/RouteInterface.java
index e9c9fd3..8de4d89 100644
--- a/media/java/android/media/session/RouteInterface.java
+++ b/media/java/android/media/session/RouteInterface.java
@@ -25,7 +25,7 @@
 import java.util.ArrayList;
 
 /**
- * A route can support multiple interfaces for a {@link Session} to
+ * A route can support multiple interfaces for a {@link MediaSession} to
  * interact with. To use a specific interface with a route a
  * MediaSessionRouteInterface needs to be retrieved from the route. An
  * implementation of the specific interface, like
@@ -33,6 +33,7 @@
  * and reduce errors on that interface.
  *
  * @see RoutePlaybackControls for an example
+ * @hide
  */
 public final class RouteInterface {
     private static final String TAG = "RouteInterface";
@@ -67,7 +68,7 @@
 
     private final Route mRoute;
     private final String mIface;
-    private final Session mSession;
+    private final MediaSession mSession;
 
     private final Object mLock = new Object();
     private final ArrayList<EventHandler> mListeners = new ArrayList<EventHandler>();
@@ -75,7 +76,7 @@
     /**
      * @hide
      */
-    RouteInterface(Route route, String iface, Session session) {
+    RouteInterface(Route route, String iface, MediaSession session) {
         mRoute = route;
         mIface = iface;
         mSession = session;
diff --git a/media/java/android/media/session/RouteOptions.java b/media/java/android/media/session/RouteOptions.java
index 5105867..b4fb341 100644
--- a/media/java/android/media/session/RouteOptions.java
+++ b/media/java/android/media/session/RouteOptions.java
@@ -34,6 +34,7 @@
  * appropriate route options when it is ready to connect to the route. Each
  * route options instance must specify a complete set of capabilities to request
  * when the connection is established.
+ * @hide
  */
 public final class RouteOptions implements Parcelable {
     private static final String TAG = "RouteOptions";
diff --git a/media/java/android/media/session/RoutePlaybackControls.java b/media/java/android/media/session/RoutePlaybackControls.java
index a3ffb58..8211983 100644
--- a/media/java/android/media/session/RoutePlaybackControls.java
+++ b/media/java/android/media/session/RoutePlaybackControls.java
@@ -15,6 +15,7 @@
  */
 package android.media.session;
 
+import android.media.MediaMetadata;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.ResultReceiver;
@@ -23,6 +24,7 @@
  * A standard media control interface for Routes that support queueing and
  * transport controls. Routes may support multiple interfaces for MediaSessions
  * to interact with.
+ * @hide
  */
 public final class RoutePlaybackControls {
     private static final String TAG = "RoutePlaybackControls";
diff --git a/media/java/android/media/session/TransportController.java b/media/java/android/media/session/TransportController.java
index 9574df6..090489b 100644
--- a/media/java/android/media/session/TransportController.java
+++ b/media/java/android/media/session/TransportController.java
@@ -15,6 +15,7 @@
  */
 package android.media.session;
 
+import android.media.MediaMetadata;
 import android.media.Rating;
 import android.os.Handler;
 import android.os.Looper;
diff --git a/media/java/android/media/session/TransportPerformer.java b/media/java/android/media/session/TransportPerformer.java
index 187f48d..1588d8f 100644
--- a/media/java/android/media/session/TransportPerformer.java
+++ b/media/java/android/media/session/TransportPerformer.java
@@ -16,6 +16,7 @@
 package android.media.session;
 
 import android.media.AudioManager;
+import android.media.MediaMetadata;
 import android.media.Rating;
 import android.os.Handler;
 import android.os.Looper;
diff --git a/packages/InputDevices/res/raw/keyboard_layout_danish.kcm b/packages/InputDevices/res/raw/keyboard_layout_danish.kcm
index 9386a45..9168d12 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_danish.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_danish.kcm
@@ -13,13 +13,11 @@
 # limitations under the License.
 
 #
-# Danish keyboard layout.
+# Danish (EU based + Sami) keyboard layout.
 #
 
 type OVERLAY
 
-map key 12 SLASH
-map key 53 MINUS
 map key 86 PLUS
 
 ### ROW 1
@@ -61,6 +59,7 @@
     label:                              '5'
     base:                               '5'
     shift:                              '%'
+    ralt:                               '\u20ac'
 }
 
 key 6 {
@@ -97,7 +96,7 @@
     ralt:                               '}'
 }
 
-key SLASH {
+key MINUS {
     label:                              '+'
     base:                               '+'
     shift:                              '?'
@@ -116,6 +115,8 @@
     label:                              'Q'
     base:                               'q'
     shift, capslock:                    'Q'
+    ralt:                               '\u00e2'
+    ralt+capslock, shift+ralt:          '\u00c2'
 }
 
 key W {
@@ -129,6 +130,7 @@
     base:                               'e'
     shift, capslock:                    'E'
     ralt:                               '\u20ac'
+    ralt+capslock:                      '\u20ac'
 }
 
 key R {
@@ -141,6 +143,8 @@
     label:                              'T'
     base:                               't'
     shift, capslock:                    'T'
+    ralt:                               '\u0167'
+    ralt+capslock, shift+ralt:          '\u0166'
 }
 
 key Y {
@@ -159,12 +163,16 @@
     label:                              'I'
     base:                               'i'
     shift, capslock:                    'I'
+    ralt:                               '\u00ef'
+    ralt+capslock, shift+ralt:          '\u00cf'
 }
 
 key O {
     label:                              'O'
     base:                               'o'
     shift, capslock:                    'O'
+    ralt:                               '\u00f5'
+    ralt+capslock, shift+ralt:          '\u00d5'
 }
 
 key P {
@@ -192,36 +200,48 @@
     label:                              'A'
     base:                               'a'
     shift, capslock:                    'A'
+    ralt:                               '\u00e1'
+    ralt+capslock, shift+ralt:          '\u00c1'
 }
 
 key S {
     label:                              'S'
     base:                               's'
     shift, capslock:                    'S'
+    ralt:                               '\u0161'
+    ralt+capslock, shift+ralt:          '\u0160'
 }
 
 key D {
     label:                              'D'
     base:                               'd'
     shift, capslock:                    'D'
+    ralt:                               '\u0111'
+    ralt+capslock, shift+ralt:          '\u0110'
 }
 
 key F {
     label:                              'F'
     base:                               'f'
     shift, capslock:                    'F'
+    ralt:                               '\u01e5'
+    ralt+capslock, shift+ralt:          '\u01e4'
 }
 
 key G {
     label:                              'G'
     base:                               'g'
     shift, capslock:                    'G'
+    ralt:                               '\u01e7'
+    ralt+capslock, shift+ralt:          '\u01e6'
 }
 
 key H {
     label:                              'H'
     base:                               'h'
     shift, capslock:                    'H'
+    ralt:                               '\u021f'
+    ralt+capslock, shift+ralt:          '\u021e'
 }
 
 key J {
@@ -234,6 +254,8 @@
     label:                              'K'
     base:                               'k'
     shift, capslock:                    'K'
+    ralt:                               '\u01e9'
+    ralt+capslock, shift+ralt:          '\u01e8'
 }
 
 key L {
@@ -246,12 +268,16 @@
     label:                              '\u00c6'
     base:                               '\u00e6'
     shift, capslock:                    '\u00c6'
+    ralt:                               '\u00e4'
+    ralt+capslock, shift+ralt:          '\u00c4'
 }
 
 key APOSTROPHE {
     label:                              '\u00d8'
     base:                               '\u00f8'
     shift, capslock:                    '\u00d8'
+    ralt:                               '\u00f6'
+    ralt+capslock, shift+ralt:          '\u00d6'
 }
 
 key BACKSLASH {
@@ -273,6 +299,8 @@
     label:                              'Z'
     base:                               'z'
     shift, capslock:                    'Z'
+    ralt:                               '\u017e'
+    ralt+capslock, shift+ralt:          '\u017d'
 }
 
 key X {
@@ -285,31 +313,39 @@
     label:                              'C'
     base:                               'c'
     shift, capslock:                    'C'
+    ralt:                               '\u010d'
+    ralt+capslock, shift+ralt:          '\u010c'
 }
 
 key V {
     label:                              'V'
     base:                               'v'
     shift, capslock:                    'V'
+    ralt:                               '\u01ef'
+    ralt+capslock, shift+ralt:          '\u01ee'
 }
 
 key B {
     label:                              'B'
     base:                               'b'
     shift, capslock:                    'B'
+    ralt:                               '\u0292'
+    ralt+capslock, shift+ralt:          '\u01b7'
 }
 
 key N {
     label:                              'N'
     base:                               'n'
     shift, capslock:                    'N'
+    ralt:                               '\u014b'
+    ralt+capslock, shift+ralt:          '\u014a'
 }
 
 key M {
     label:                              'M'
     base:                               'm'
     shift, capslock:                    'M'
-    ralt:                               '\u00b5'
+    ralt, ralt+capslock:                '\u00b5'
 }
 
 key COMMA {
@@ -324,7 +360,7 @@
     shift:                              ':'
 }
 
-key MINUS {
+key SLASH {
     label:                              '-'
     base:                               '-'
     shift:                              '_'
diff --git a/packages/InputDevices/res/raw/keyboard_layout_finnish.kcm b/packages/InputDevices/res/raw/keyboard_layout_finnish.kcm
index c6e5ac4..b4deed4 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_finnish.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_finnish.kcm
@@ -13,13 +13,11 @@
 # limitations under the License.
 
 #
-# Finnish multilingual keyboard layout.
+# Finnish (& Swedish)(EU based + Sami) keyboard layout.
 #
 
 type OVERLAY
 
-map key 12 SLASH
-map key 53 MINUS
 map key 86 PLUS
 
 ### ROW 1
@@ -28,14 +26,12 @@
     label:                              '\u00a7'
     base:                               '\u00a7'
     shift:                              '\u00bd'
-    ralt:                               '\u0335'
 }
 
 key 1 {
     label:                              '1'
     base:                               '1'
     shift:                              '!'
-    ralt+shift:                         '\u00a1'
 }
 
 key 2 {
@@ -43,7 +39,6 @@
     base:                               '2'
     shift:                              '"'
     ralt:                               '@'
-    ralt+shift:                         '\u201d'
 }
 
 key 3 {
@@ -51,7 +46,6 @@
     base:                               '3'
     shift:                              '#'
     ralt:                               '\u00a3'
-    ralt+shift:                         '\u00bb'
 }
 
 key 4 {
@@ -59,23 +53,19 @@
     base:                               '4'
     shift:                              '\u00a4'
     ralt:                               '$'
-    ralt+shift:                         '\u00ab'
 }
 
 key 5 {
     label:                              '5'
     base:                               '5'
     shift:                              '%'
-    ralt:                               '\u2030'
-    ralt+shift:                         '\u201c'
+    ralt:                               '\u20ac'
 }
 
 key 6 {
     label:                              '6'
     base:                               '6'
     shift:                              '&'
-    ralt:                               '\u201a'
-    ralt+shift:                         '\u201e'
 }
 
 key 7 {
@@ -104,23 +94,19 @@
     base:                               '0'
     shift:                              '='
     ralt:                               '}'
-    ralt+shift:                         '\u00b0'
 }
 
-key SLASH {
+key MINUS {
     label:                              '+'
     base:                               '+'
     shift:                              '?'
     ralt:                               '\\'
-    ralt+shift:                         '\u00bf'
 }
 
 key EQUALS {
     label:                              '\u00b4'
     base:                               '\u0301'
     shift:                              '\u0300'
-    ralt:                               '\u0327'
-    ralt+shift:                         '\u0328'
 }
 
 ### ROW 2
@@ -129,6 +115,8 @@
     label:                              'Q'
     base:                               'q'
     shift, capslock:                    'Q'
+    ralt:                               '\u00e2'
+    ralt+capslock, shift+ralt:          '\u00c2'
 }
 
 key W {
@@ -142,6 +130,7 @@
     base:                               'e'
     shift, capslock:                    'E'
     ralt:                               '\u20ac'
+    ralt+capslock:                      '\u20ac'
 }
 
 key R {
@@ -154,8 +143,8 @@
     label:                              'T'
     base:                               't'
     shift, capslock:                    'T'
-    ralt:                               '\u00fe'
-    ralt+shift, ralt+capslock:          '\u00de'
+    ralt:                               '\u0167'
+    ralt+capslock, shift+ralt:          '\u0166'
 }
 
 key Y {
@@ -174,31 +163,28 @@
     label:                              'I'
     base:                               'i'
     shift, capslock:                    'I'
-    ralt:                               '\u0131'
+    ralt:                               '\u00ef'
+    ralt+capslock, shift+ralt:          '\u00cf'
 }
 
 key O {
     label:                              'O'
     base:                               'o'
     shift, capslock:                    'O'
-    ralt:                               '\u0153'
-    ralt+shift, ralt+capslock:          '\u0152'
+    ralt:                               '\u00f5'
+    ralt+capslock, shift+ralt:          '\u00d5'
 }
 
 key P {
     label:                              'P'
     base:                               'p'
     shift, capslock:                    'P'
-    ralt:                               '\u031b'
-    ralt+shift:                         '\u0309'
 }
 
 key LEFT_BRACKET {
     label:                              '\u00c5'
     base:                               '\u00e5'
     shift, capslock:                    '\u00c5'
-    ralt:                               '\u030b'
-    ralt+shift:                         '\u030a'
 }
 
 key RIGHT_BRACKET {
@@ -206,7 +192,6 @@
     base:                               '\u0308'
     shift:                              '\u0302'
     ralt:                               '\u0303'
-    ralt+shift:                         '\u0304'
 }
 
 ### ROW 3
@@ -215,41 +200,48 @@
     label:                              'A'
     base:                               'a'
     shift, capslock:                    'A'
-    ralt:                               '\u0259'
-    ralt+shift, ralt+capslock:          '\u018f'
+    ralt:                               '\u00e1'
+    ralt+capslock, shift+ralt:          '\u00c1'
 }
 
 key S {
     label:                              'S'
     base:                               's'
     shift, capslock:                    'S'
-    ralt:                               '\u00df'
+    ralt:                               '\u0161'
+    ralt+capslock, shift+ralt:          '\u0160'
 }
 
 key D {
     label:                              'D'
     base:                               'd'
     shift, capslock:                    'D'
-    ralt:                               '\u00f0'
-    ralt+shift, ralt+capslock:          '\u00d0'
+    ralt:                               '\u0111'
+    ralt+capslock, shift+ralt:          '\u0110'
 }
 
 key F {
     label:                              'F'
     base:                               'f'
     shift, capslock:                    'F'
+    ralt:                               '\u01e5'
+    ralt+capslock, shift+ralt:          '\u01e4'
 }
 
 key G {
     label:                              'G'
     base:                               'g'
     shift, capslock:                    'G'
+    ralt:                               '\u01e7'
+    ralt+capslock, shift+ralt:          '\u01e6'
 }
 
 key H {
     label:                              'H'
     base:                               'h'
     shift, capslock:                    'H'
+    ralt:                               '\u021f'
+    ralt+capslock, shift+ralt:          '\u021e'
 }
 
 key J {
@@ -262,14 +254,14 @@
     label:                              'K'
     base:                               'k'
     shift, capslock:                    'K'
-    ralt:                               '\u0138'
+    ralt:                               '\u01e9'
+    ralt+capslock, shift+ralt:          '\u01e8'
 }
 
 key L {
     label:                              'L'
     base:                               'l'
     shift, capslock:                    'L'
-    ralt:                               '\u0335'
 }
 
 key SEMICOLON {
@@ -277,7 +269,7 @@
     base:                               '\u00f6'
     shift, capslock:                    '\u00d6'
     ralt:                               '\u00f8'
-    ralt+shift, ralt+capslock:          '\u00d8'
+    ralt+capslock, shift+ralt:          '\u00d8'
 }
 
 key APOSTROPHE {
@@ -285,15 +277,13 @@
     base:                               '\u00e4'
     shift, capslock:                    '\u00c4'
     ralt:                               '\u00e6'
-    ralt+shift, ralt+capslock:          '\u00c6'
+    ralt+capslock, shift+ralt:          '\u00c6'
 }
 
 key BACKSLASH {
     label:                              '\''
     base:                               '\''
     shift:                              '*'
-    ralt:                               '\u030c'
-    ralt+shift:                         '\u0306'
 }
 
 ### ROW 4
@@ -309,34 +299,38 @@
     label:                              'Z'
     base:                               'z'
     shift, capslock:                    'Z'
-    ralt:                               '\u0292'
-    ralt+shift, ralt+capslock:          '\u01b7'
+    ralt:                               '\u017e'
+    ralt+capslock, shift+ralt:          '\u017d'
 }
 
 key X {
     label:                              'X'
     base:                               'x'
     shift, capslock:                    'X'
-    ralt:                               '\u00d7'
-    ralt+shift:                         '\u00b7'
 }
 
 key C {
     label:                              'C'
     base:                               'c'
     shift, capslock:                    'C'
+    ralt:                               '\u010d'
+    ralt+capslock, shift+ralt:          '\u010c'
 }
 
 key V {
     label:                              'V'
     base:                               'v'
     shift, capslock:                    'V'
+    ralt:                               '\u01ef'
+    ralt+capslock, shift+ralt:          '\u01ee'
 }
 
 key B {
     label:                              'B'
     base:                               'b'
     shift, capslock:                    'B'
+    ralt:                               '\u0292'
+    ralt+capslock, shift+ralt:          '\u01b7'
 }
 
 key N {
@@ -344,37 +338,30 @@
     base:                               'n'
     shift, capslock:                    'N'
     ralt:                               '\u014b'
-    ralt+shift, ralt+capslock:          '\u014a'
+    ralt+capslock, shift+ralt:          '\u014a'
 }
 
 key M {
     label:                              'M'
     base:                               'm'
     shift, capslock:                    'M'
-    ralt:                               '\u00b5'
-    ralt+shift:                         '\u2014'
+    ralt, ralt+capslock:                '\u00b5'
 }
 
 key COMMA {
     label:                              ','
     base:                               ','
     shift:                              ';'
-    ralt:                               '\u2019'
-    ralt+shift:                         '\u2018'
 }
 
 key PERIOD {
     label:                              '.'
     base:                               '.'
     shift:                              ':'
-    ralt:                               '\u0323'
-    ralt+shift:                         '\u0307'
 }
 
-key MINUS {
+key SLASH {
     label:                              '-'
     base:                               '-'
     shift:                              '_'
-    ralt:                               '\u2013'
-    ralt+shift:                         '\u0307'
 }
diff --git a/packages/InputDevices/res/raw/keyboard_layout_norwegian.kcm b/packages/InputDevices/res/raw/keyboard_layout_norwegian.kcm
index d1be485..560dd16 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_norwegian.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_norwegian.kcm
@@ -13,13 +13,11 @@
 # limitations under the License.
 
 #
-# Norwegian keyboard layout.
+# Norwegian (EU based + Sami) keyboard layout.
 #
 
 type OVERLAY
 
-map key 12 SLASH
-map key 53 MINUS
 map key 86 PLUS
 
 ### ROW 1
@@ -61,6 +59,7 @@
     label:                              '5'
     base:                               '5'
     shift:                              '%'
+    ralt:                               '\u20ac'
 }
 
 key 6 {
@@ -97,7 +96,7 @@
     ralt:                               '}'
 }
 
-key SLASH {
+key MINUS {
     label:                              '+'
     base:                               '+'
     shift:                              '?'
@@ -116,6 +115,8 @@
     label:                              'Q'
     base:                               'q'
     shift, capslock:                    'Q'
+    ralt:                               '\u00e2'
+    ralt+capslock, shift+ralt:          '\u00c2'
 }
 
 key W {
@@ -129,6 +130,7 @@
     base:                               'e'
     shift, capslock:                    'E'
     ralt:                               '\u20ac'
+    ralt+capslock:                      '\u20ac'
 }
 
 key R {
@@ -141,6 +143,8 @@
     label:                              'T'
     base:                               't'
     shift, capslock:                    'T'
+    ralt:                               '\u0167'
+    ralt+capslock, shift+ralt:          '\u0166'
 }
 
 key Y {
@@ -159,12 +163,16 @@
     label:                              'I'
     base:                               'i'
     shift, capslock:                    'I'
+    ralt:                               '\u00ef'
+    ralt+capslock, shift+ralt:          '\u00cf'
 }
 
 key O {
     label:                              'O'
     base:                               'o'
     shift, capslock:                    'O'
+    ralt:                               '\u00f5'
+    ralt+capslock, shift+ralt:          '\u00d5'
 }
 
 key P {
@@ -192,36 +200,48 @@
     label:                              'A'
     base:                               'a'
     shift, capslock:                    'A'
+    ralt:                               '\u00e1'
+    ralt+capslock, shift+ralt:          '\u00c1'
 }
 
 key S {
     label:                              'S'
     base:                               's'
     shift, capslock:                    'S'
+    ralt:                               '\u0161'
+    ralt+capslock, shift+ralt:          '\u0160'
 }
 
 key D {
     label:                              'D'
     base:                               'd'
     shift, capslock:                    'D'
+    ralt:                               '\u0111'
+    ralt+capslock, shift+ralt:          '\u0110'
 }
 
 key F {
     label:                              'F'
     base:                               'f'
     shift, capslock:                    'F'
+    ralt:                               '\u01e5'
+    ralt+capslock, shift+ralt:          '\u01e4'
 }
 
 key G {
     label:                              'G'
     base:                               'g'
     shift, capslock:                    'G'
+    ralt:                               '\u01e7'
+    ralt+capslock, shift+ralt:          '\u01e6'
 }
 
 key H {
     label:                              'H'
     base:                               'h'
     shift, capslock:                    'H'
+    ralt:                               '\u021f'
+    ralt+capslock, shift+ralt:          '\u021e'
 }
 
 key J {
@@ -234,6 +254,8 @@
     label:                              'K'
     base:                               'k'
     shift, capslock:                    'K'
+    ralt:                               '\u01e9'
+    ralt+capslock, shift+ralt:          '\u01e8'
 }
 
 key L {
@@ -246,12 +268,16 @@
     label:                              '\u00d8'
     base:                               '\u00f8'
     shift, capslock:                    '\u00d8'
+    ralt:                               '\u00f6'
+    ralt+capslock, shift+ralt:          '\u00d6'
 }
 
 key APOSTROPHE {
     label:                              '\u00c6'
     base:                               '\u00e6'
     shift, capslock:                    '\u00c6'
+    ralt:                               '\u00e4'
+    ralt+capslock, shift+ralt:          '\u00c4'
 }
 
 key BACKSLASH {
@@ -272,6 +298,8 @@
     label:                              'Z'
     base:                               'z'
     shift, capslock:                    'Z'
+    ralt:                               '\u017e'
+    ralt+capslock, shift+ralt:          '\u017d'
 }
 
 key X {
@@ -284,31 +312,39 @@
     label:                              'C'
     base:                               'c'
     shift, capslock:                    'C'
+    ralt:                               '\u010d'
+    ralt+capslock, shift+ralt:          '\u010c'
 }
 
 key V {
     label:                              'V'
     base:                               'v'
     shift, capslock:                    'V'
+    ralt:                               '\u01ef'
+    ralt+capslock, shift+ralt:          '\u01ee'
 }
 
 key B {
     label:                              'B'
     base:                               'b'
     shift, capslock:                    'B'
+    ralt:                               '\u0292'
+    ralt+capslock, shift+ralt:          '\u01b7'
 }
 
 key N {
     label:                              'N'
     base:                               'n'
     shift, capslock:                    'N'
+    ralt:                               '\u014b'
+    ralt+capslock, shift+ralt:          '\u014a'
 }
 
 key M {
     label:                              'M'
     base:                               'm'
     shift, capslock:                    'M'
-    ralt:                               '\u00b5'
+    ralt, ralt+capslock:                '\u00b5'
 }
 
 key COMMA {
@@ -323,7 +359,7 @@
     shift:                              ':'
 }
 
-key MINUS {
+key SLASH {
     label:                              '-'
     base:                               '-'
     shift:                              '_'
diff --git a/packages/InputDevices/res/raw/keyboard_layout_swedish.kcm b/packages/InputDevices/res/raw/keyboard_layout_swedish.kcm
index e42bd6c..8a4e9a5 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_swedish.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_swedish.kcm
@@ -13,13 +13,11 @@
 # limitations under the License.
 
 #
-# Swedish keyboard layout.
+# Swedish (Finnish) (EU based + Sami) keyboard layout.
 #
 
 type OVERLAY
 
-map key 12 SLASH
-map key 53 MINUS
 map key 86 PLUS
 
 ### ROW 1
@@ -61,6 +59,7 @@
     label:                              '5'
     base:                               '5'
     shift:                              '%'
+    ralt:                               '\u20ac'
 }
 
 key 6 {
@@ -97,7 +96,7 @@
     ralt:                               '}'
 }
 
-key SLASH {
+key MINUS {
     label:                              '+'
     base:                               '+'
     shift:                              '?'
@@ -116,6 +115,8 @@
     label:                              'Q'
     base:                               'q'
     shift, capslock:                    'Q'
+    ralt:                               '\u00e2'
+    ralt+capslock, shift+ralt:          '\u00c2'
 }
 
 key W {
@@ -129,6 +130,7 @@
     base:                               'e'
     shift, capslock:                    'E'
     ralt:                               '\u20ac'
+    ralt+capslock:                      '\u20ac'
 }
 
 key R {
@@ -141,6 +143,8 @@
     label:                              'T'
     base:                               't'
     shift, capslock:                    'T'
+    ralt:                               '\u0167'
+    ralt+capslock, shift+ralt:          '\u0166'
 }
 
 key Y {
@@ -159,12 +163,16 @@
     label:                              'I'
     base:                               'i'
     shift, capslock:                    'I'
+    ralt:                               '\u00ef'
+    ralt+capslock, shift+ralt:          '\u00cf'
 }
 
 key O {
     label:                              'O'
     base:                               'o'
     shift, capslock:                    'O'
+    ralt:                               '\u00f5'
+    ralt+capslock, shift+ralt:          '\u00d5'
 }
 
 key P {
@@ -192,36 +200,48 @@
     label:                              'A'
     base:                               'a'
     shift, capslock:                    'A'
+    ralt:                               '\u00e1'
+    ralt+capslock, shift+ralt:          '\u00c1'
 }
 
 key S {
     label:                              'S'
     base:                               's'
     shift, capslock:                    'S'
+    ralt:                               '\u0161'
+    ralt+capslock, shift+ralt:          '\u0160'
 }
 
 key D {
     label:                              'D'
     base:                               'd'
     shift, capslock:                    'D'
+    ralt:                               '\u0111'
+    ralt+capslock, shift+ralt:          '\u0110'
 }
 
 key F {
     label:                              'F'
     base:                               'f'
     shift, capslock:                    'F'
+    ralt:                               '\u01e5'
+    ralt+capslock, shift+ralt:          '\u01e4'
 }
 
 key G {
     label:                              'G'
     base:                               'g'
     shift, capslock:                    'G'
+    ralt:                               '\u01e7'
+    ralt+capslock, shift+ralt:          '\u01e6'
 }
 
 key H {
     label:                              'H'
     base:                               'h'
     shift, capslock:                    'H'
+    ralt:                               '\u021f'
+    ralt+capslock, shift+ralt:          '\u021e'
 }
 
 key J {
@@ -234,6 +254,8 @@
     label:                              'K'
     base:                               'k'
     shift, capslock:                    'K'
+    ralt:                               '\u01e9'
+    ralt+capslock, shift+ralt:          '\u01e8'
 }
 
 key L {
@@ -246,12 +268,16 @@
     label:                              '\u00d6'
     base:                               '\u00f6'
     shift, capslock:                    '\u00d6'
+    ralt:                               '\u00f8'
+    ralt+capslock, shift+ralt:          '\u00d8'
 }
 
 key APOSTROPHE {
     label:                              '\u00c4'
     base:                               '\u00e4'
     shift, capslock:                    '\u00c4'
+    ralt:                               '\u00e6'
+    ralt+capslock, shift+ralt:          '\u00c6'
 }
 
 key BACKSLASH {
@@ -273,6 +299,8 @@
     label:                              'Z'
     base:                               'z'
     shift, capslock:                    'Z'
+    ralt:                               '\u017e'
+    ralt+capslock, shift+ralt:          '\u017d'
 }
 
 key X {
@@ -285,31 +313,39 @@
     label:                              'C'
     base:                               'c'
     shift, capslock:                    'C'
+    ralt:                               '\u010d'
+    ralt+capslock, shift+ralt:          '\u010c'
 }
 
 key V {
     label:                              'V'
     base:                               'v'
     shift, capslock:                    'V'
+    ralt:                               '\u01ef'
+    ralt+capslock, shift+ralt:          '\u01ee'
 }
 
 key B {
     label:                              'B'
     base:                               'b'
     shift, capslock:                    'B'
+    ralt:                               '\u0292'
+    ralt+capslock, shift+ralt:          '\u01b7'
 }
 
 key N {
     label:                              'N'
     base:                               'n'
     shift, capslock:                    'N'
+    ralt:                               '\u014b'
+    ralt+capslock, shift+ralt:          '\u014a'
 }
 
 key M {
     label:                              'M'
     base:                               'm'
     shift, capslock:                    'M'
-    ralt:                               '\u00b5'
+    ralt, ralt+capslock:                '\u00b5'
 }
 
 key COMMA {
@@ -324,7 +360,7 @@
     shift:                              ':'
 }
 
-key MINUS {
+key SLASH {
     label:                              '-'
     base:                               '-'
     shift:                              '_'
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 8425c48..94edc07 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -42,6 +42,8 @@
     private boolean mIsBouncing;
     private SecurityCallback mSecurityCallback;
 
+    private final KeyguardUpdateMonitor mUpdateMonitor;
+
     // Used to notify the container when something interesting happens.
     public interface SecurityCallback {
         public boolean dismiss(boolean authenticated);
@@ -62,6 +64,7 @@
         super(context, attrs, defStyle);
         mSecurityModel = new KeyguardSecurityModel(context);
         mLockPatternUtils = new LockPatternUtils(context);
+        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
     }
 
     public void setSecurityCallback(SecurityCallback callback) {
@@ -303,7 +306,9 @@
     boolean showNextSecurityScreenOrFinish(boolean authenticated) {
         if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
         boolean finish = false;
-        if (SecurityMode.None == mCurrentSecuritySelection) {
+        if (mUpdateMonitor.getUserHasTrust(mLockPatternUtils.getCurrentUser())) {
+            finish = true;
+        } else if (SecurityMode.None == mCurrentSecuritySelection) {
             SecurityMode securityMode = mSecurityModel.getSecurityMode();
             // Allow an alternate, such as biometric unlock
             securityMode = mSecurityModel.getAlternateFor(securityMode);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 2d492db..5ef41c9 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -83,8 +83,6 @@
         } else if (simState == IccCardConstants.State.PUK_REQUIRED
                 && mLockPatternUtils.isPukUnlockScreenEnable()) {
             mode = SecurityMode.SimPuk;
-        } else if (updateMonitor.getUserHasTrust(mLockPatternUtils.getCurrentUser())) {
-            mode = SecurityMode.None;
         } else {
             final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality();
             switch (security) {
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 58f67d0..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index b794c9a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index f3e9da2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index a90aef9..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index b05bf78..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index 2f782cf..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 8299301..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index e171d53..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 1c847da2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index d0ab910..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 1e05a91..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index f4afa52..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 662d062..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index 18be9c0..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index aabf0aa..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index 654c2a5..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
index 45b5548..3a20c58 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
@@ -24,5 +24,5 @@
 
     <path
         android:fill="#FFFFFFFF"
-        android:pathData="M3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0L12.0,4.0L7.0,9.0L3.0,9.0zM16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0L14.0,16.0C15.5,15.3 16.5,13.8 16.5,12.0zM14.0,3.2l0.0,2.1c2.9,0.9 5.0,3.5 5.0,6.7s-2.1,5.8 -5.0,6.7l0.0,2.1c4.0,-0.9 7.0,-4.5 7.0,-8.8S18.0,4.1 14.0,3.2z"/>
+        android:pathData="M6.6,3.6L5.2,2.2C2.8,4.0 1.2,6.8 1.0,10.0l2.0,0.0C3.2,7.3 4.5,5.0 6.6,3.6zM20.0,10.0l2.0,0.0c-0.2,-3.2 -1.7,-6.0 -4.1,-7.8l-1.4,1.4C18.5,5.0 19.8,7.3 20.0,10.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0l-2.0,-2.0L18.0,10.5zM11.5,22.0c0.1,0.0 0.3,0.0 0.4,0.0c0.7,-0.1 1.2,-0.6 1.4,-1.2c0.1,-0.2 0.2,-0.5 0.2,-0.8l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
index 6d44406..dd6be76 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
@@ -24,5 +24,5 @@
 
     <path
         android:fill="#FFFFFFFF"
-        android:pathData="M16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0l0.0,2.2l2.5,2.5C16.5,12.4 16.5,12.2 16.5,12.0zM19.0,12.0c0.0,0.9 -0.2,1.8 -0.5,2.6l1.5,1.5c0.7,-1.2 1.0,-2.7 1.0,-4.2c0.0,-4.3 -3.0,-7.9 -7.0,-8.8l0.0,2.1C16.9,6.2 19.0,8.8 19.0,12.0zM4.3,3.0L3.0,4.3L7.7,9.0L3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0l0.0,-6.7l4.3,4.3c-0.7,0.5 -1.4,0.9 -2.3,1.2l0.0,2.1c1.4,-0.3 2.6,-0.9 3.7,-1.8l2.0,2.0l1.3,-1.3l-9.0,-9.0L4.3,3.0zM12.0,4.0L9.9,6.1L12.0,8.2L12.0,4.0z"/>
+        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
new file mode 100644
index 0000000..5efd8ec
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="19dp"
+        android:height="19dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
new file mode 100644
index 0000000..e1d63c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="20dp"
+        android:height="20dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml
new file mode 100644
index 0000000..afab88f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="19dp"
+        android:height="19dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
+</vector>
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index bda6431..a68ad2f 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -16,7 +16,8 @@
 <com.android.systemui.recents.views.TaskView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent" 
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:focusable="true">
     <com.android.systemui.recents.views.TaskThumbnailView
         android:id="@+id/task_view_thumbnail"
         android:layout_width="match_parent"
@@ -69,7 +70,7 @@
             android:layout_height="@dimen/recents_task_view_application_icon_size"
             android:layout_gravity="center_vertical|end"
             android:padding="23dp"
-            android:src="@drawable/recents_dismiss_dark" />
+            android:src="@drawable/recents_dismiss_light" />
     </com.android.systemui.recents.views.TaskBarView>
 </com.android.systemui.recents.views.TaskView>
 
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 585658e..eaa2558 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -61,11 +61,6 @@
                 android:src="@drawable/stat_notify_more"
                 android:visibility="gone"
                 />
-            <com.android.systemui.statusbar.StatusBarIconView android:id="@+id/modeIcon"
-                android:layout_width="@dimen/status_bar_icon_size"
-                android:layout_height="match_parent"
-                android:visibility="gone"
-                />
             <com.android.systemui.statusbar.phone.IconMerger android:id="@+id/notificationIcons"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b3829a3..f5bc353 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -561,4 +561,6 @@
 
     <!-- Shows when people have pressed the unlock icon to explain how to unlock. [CHAR LIMIT=60] -->
     <string name="keyguard_unlock">Swipe up to unlock</string>
+
+    <string name="bugreport_tile_extended" translatable="false">%s\n%s (%s)</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 323905f..105f70e 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -20,11 +20,9 @@
 import android.view.View;
 
 public interface RecentsComponent {
+    void showRecents(boolean triggeredFromAltTab, View statusBarView);
+    void hideRecents();
     void toggleRecents(Display display, int layoutDirection, View statusBarView);
-
-    void preloadRecentTasksList();
-
-    void cancelPreloadingRecentTasksList();
-
-    void closeRecents();
+    void preloadRecents();
+    void cancelPreloadingRecents();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
index bfd416d..fa41837 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
@@ -21,6 +21,7 @@
 import android.app.Dialog;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
+import android.os.Build;
 import android.os.RemoteException;
 import android.provider.Settings.Global;
 import android.view.WindowManager;
@@ -70,7 +71,11 @@
     protected void handleUpdateState(State state, Object pushArg) {
         state.visible = mSetting.getValue() != 0;
         state.iconId = R.drawable.ic_qs_bugreport;
-        state.label = mContext.getString(com.android.internal.R.string.bugreport_title);
+        state.label = mContext.getString(
+                R.string.bugreport_tile_extended,
+                mContext.getString(com.android.internal.R.string.bugreport_title),
+                Build.VERSION.RELEASE,
+                Build.ID);
     }
 
     private final Runnable mShowDialog = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
index ae18aa8..00c43e8 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -27,7 +27,6 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -44,14 +43,12 @@
     private static final boolean DEBUG = true;
 
     // Which recents to use
-    boolean mUseAlternateRecents;
+    boolean mUseAlternateRecents = true;
     AlternateRecentsComponent mAlternateRecents;
     boolean mBootCompleted = false;
 
     @Override
     public void start() {
-        Configuration config = mContext.getResources().getConfiguration();
-        mUseAlternateRecents = (config.smallestScreenWidthDp < 600);
         if (mUseAlternateRecents) {
             if (mAlternateRecents == null) {
                 mAlternateRecents = new AlternateRecentsComponent(mContext);
@@ -68,10 +65,30 @@
     }
 
     @Override
+    public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
+        if (mUseAlternateRecents) {
+            mAlternateRecents.onShowRecents(triggeredFromAltTab, statusBarView);
+        }
+    }
+
+    @Override
+    public void hideRecents() {
+        if (mUseAlternateRecents) {
+            mAlternateRecents.onHideRecents();
+        } else {
+            Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
+            intent.setPackage("com.android.systemui");
+            sendBroadcastSafely(intent);
+
+            RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
+        }
+    }
+
+    @Override
     public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
         if (mUseAlternateRecents) {
             // Launch the alternate recents if required
-            mAlternateRecents.onToggleRecents(display, layoutDirection, statusBarView);
+            mAlternateRecents.onToggleRecents(statusBarView);
             return;
         }
 
@@ -224,7 +241,7 @@
     }
 
     @Override
-    public void preloadRecentTasksList() {
+    public void preloadRecents() {
         if (mUseAlternateRecents) {
             mAlternateRecents.onPreloadRecents();
         } else {
@@ -238,7 +255,7 @@
     }
 
     @Override
-    public void cancelPreloadingRecentTasksList() {
+    public void cancelPreloadingRecents() {
         if (mUseAlternateRecents) {
             mAlternateRecents.onCancelPreloadingRecents();
         } else {
@@ -251,19 +268,6 @@
         }
     }
 
-    @Override
-    public void closeRecents() {
-        if (mUseAlternateRecents) {
-            mAlternateRecents.onCloseRecents();
-        } else {
-            Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
-            intent.setPackage("com.android.systemui");
-            sendBroadcastSafely(intent);
-
-            RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
-        }
-    }
-
     /**
      * Send broadcast only if BOOT_COMPLETED
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 19a1b11..ec50bfa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -44,9 +44,9 @@
 import android.view.WindowManager;
 import com.android.systemui.R;
 
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /** A proxy implementation for the recents component */
 public class AlternateRecentsComponent {
@@ -72,7 +72,7 @@
                 // If we had the update the animation rects as a result of onServiceConnected, then
                 // we check for whether we need to toggle the recents here.
                 if (mToggleRecentsUponServiceBound) {
-                    startAlternateRecentsActivity();
+                    startRecentsActivity();
                     mToggleRecentsUponServiceBound = false;
                 }
             }
@@ -90,9 +90,9 @@
             mServiceIsBound = true;
 
             if (hasValidTaskRects()) {
-                // Toggle recents if this new service connection was triggered by hitting recents
+                // Start recents if this new service connection was triggered by hitting recents
                 if (mToggleRecentsUponServiceBound) {
-                    startAlternateRecentsActivity();
+                    startRecentsActivity();
                     mToggleRecentsUponServiceBound = false;
                 }
             } else {
@@ -114,10 +114,12 @@
     final public static int MSG_UPDATE_TASK_THUMBNAIL = 1;
     final public static int MSG_PRELOAD_TASKS = 2;
     final public static int MSG_CANCEL_PRELOAD_TASKS = 3;
-    final public static int MSG_CLOSE_RECENTS = 4;
-    final public static int MSG_TOGGLE_RECENTS = 5;
+    final public static int MSG_SHOW_RECENTS = 4;
+    final public static int MSG_HIDE_RECENTS = 5;
+    final public static int MSG_TOGGLE_RECENTS = 6;
 
     final public static String EXTRA_ANIMATING_WITH_THUMBNAIL = "recents.animatingWithThumbnail";
+    final public static String EXTRA_FROM_ALT_TAB = "recents.triggeredFromAltTab";
     final public static String KEY_CONFIGURATION_DATA = "recents.data.updateForConfiguration";
     final public static String KEY_WINDOW_RECT = "recents.windowRect";
     final public static String KEY_SYSTEM_INSETS = "recents.systemInsets";
@@ -142,7 +144,10 @@
     boolean mToggleRecentsUponServiceBound;
     RecentsServiceConnection mConnection = new RecentsServiceConnection();
 
+    // Variables to keep track of if we need to start recents after binding
     View mStatusBarView;
+    boolean mTriggeredFromAltTab;
+
     Rect mSingleCountFirstTaskRect = new Rect();
     Rect mMultipleCountFirstTaskRect = new Rect();
     long mLastToggleTime;
@@ -160,15 +165,11 @@
         bindToRecentsService(false);
     }
 
-    /** Toggles the alternate recents activity */
-    public void onToggleRecents(Display display, int layoutDirection, View statusBarView) {
-        Console.logStartTracingTime(Constants.Log.App.TimeRecentsStartup,
-                Constants.Log.App.TimeRecentsStartupKey);
-        Console.logStartTracingTime(Constants.Log.App.TimeRecentsLaunchTask,
-                Constants.Log.App.TimeRecentsLaunchKey);
-        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
-                "serviceIsBound: " + mServiceIsBound);
+    /** Shows the recents */
+    public void onShowRecents(boolean triggeredFromAltTab, View statusBarView) {
+        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|showRecents]");
         mStatusBarView = statusBarView;
+        mTriggeredFromAltTab = triggeredFromAltTab;
         if (!mServiceIsBound) {
             // Try to create a long-running connection to the recents service before toggling
             // recents
@@ -177,7 +178,47 @@
         }
 
         try {
-            startAlternateRecentsActivity();
+            startRecentsActivity();
+        } catch (ActivityNotFoundException e) {
+            Console.logRawError("Failed to launch RecentAppsIntent", e);
+        }
+    }
+
+    /** Hides the recents */
+    public void onHideRecents() {
+        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|hideRecents]");
+        if (mServiceIsBound) {
+            // Notify recents to close it
+            try {
+                Bundle data = new Bundle();
+                Message msg = Message.obtain(null, MSG_HIDE_RECENTS, 0, 0);
+                msg.setData(data);
+                mService.send(msg);
+            } catch (RemoteException re) {
+                re.printStackTrace();
+            }
+        }
+    }
+
+    /** Toggles the alternate recents activity */
+    public void onToggleRecents(View statusBarView) {
+        Console.logStartTracingTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey);
+        Console.logStartTracingTime(Constants.Log.App.TimeRecentsLaunchTask,
+                Constants.Log.App.TimeRecentsLaunchKey);
+        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
+                "serviceIsBound: " + mServiceIsBound);
+        mStatusBarView = statusBarView;
+        mTriggeredFromAltTab = false;
+        if (!mServiceIsBound) {
+            // Try to create a long-running connection to the recents service before toggling
+            // recents
+            bindToRecentsService(true);
+            return;
+        }
+
+        try {
+            toggleRecentsActivity();
         } catch (ActivityNotFoundException e) {
             Console.logRawError("Failed to launch RecentAppsIntent", e);
         }
@@ -191,21 +232,6 @@
         // Do nothing
     }
 
-    public void onCloseRecents() {
-        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|closeRecents]");
-        if (mServiceIsBound) {
-            // Try and update the recents configuration
-            try {
-                Bundle data = new Bundle();
-                Message msg = Message.obtain(null, MSG_CLOSE_RECENTS, 0, 0);
-                msg.setData(data);
-                mService.send(msg);
-            } catch (RemoteException re) {
-                re.printStackTrace();
-            }
-        }
-    }
-
     public void onConfigurationChanged(Configuration newConfig) {
         updateAnimationRects();
     }
@@ -355,8 +381,32 @@
                 taskRect.left, taskRect.top, null);
     }
 
-    /** Starts the recents activity */
-    void startAlternateRecentsActivity() {
+    /** Returns whether the recents is currently running */
+    boolean isRecentsTopMost(AtomicBoolean isHomeTopMost) {
+        SystemServicesProxy ssp = mSystemServicesProxy;
+        List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
+        if (!tasks.isEmpty()) {
+            ActivityManager.RunningTaskInfo topTask = tasks.get(0);
+            ComponentName topActivity = topTask.topActivity;
+
+            // Check if the front most activity is recents
+            if (topActivity.getPackageName().equals(sRecentsPackage) &&
+                    topActivity.getClassName().equals(sRecentsActivity)) {
+                if (isHomeTopMost != null) {
+                    isHomeTopMost.set(false);
+                }
+                return true;
+            }
+
+            if (isHomeTopMost != null) {
+                isHomeTopMost.set(ssp.isInHomeStack(topTask.id));
+            }
+        }
+        return false;
+    }
+
+    /** Toggles the recents activity */
+    void toggleRecentsActivity() {
         // If the user has toggled it too quickly, then just eat up the event here (it's better than
         // showing a janky screenshot).
         // NOTE: Ideally, the screenshot mechanism would take the window transform into account
@@ -366,43 +416,47 @@
 
         // If Recents is the front most activity, then we should just communicate with it directly
         // to launch the first task or dismiss itself
-        SystemServicesProxy ssp = mSystemServicesProxy;
-        List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
-        boolean isTopTaskHome = false;
-        if (!tasks.isEmpty()) {
-            ActivityManager.RunningTaskInfo topTask = tasks.get(0);
-            ComponentName topActivity = topTask.topActivity;
+        AtomicBoolean isTopTaskHome = new AtomicBoolean();
+        if (isRecentsTopMost(isTopTaskHome)) {
+            // Notify recents to close itself
+            try {
+                Bundle data = new Bundle();
+                Message msg = Message.obtain(null, MSG_TOGGLE_RECENTS, 0, 0);
+                msg.setData(data);
+                mService.send(msg);
 
-            // Check if the front most activity is recents
-            if (topActivity.getPackageName().equals(sRecentsPackage) &&
-                    topActivity.getClassName().equals(sRecentsActivity)) {
-                // Notify Recents to toggle itself
-                try {
-                    Bundle data = new Bundle();
-                    Message msg = Message.obtain(null, MSG_TOGGLE_RECENTS, 0, 0);
-                    msg.setData(data);
-                    mService.send(msg);
-
-                    // Time this path
-                    Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                            Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents");
-                    Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
-                            Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents");
-                } catch (RemoteException re) {
-                    re.printStackTrace();
-                }
-                mLastToggleTime = System.currentTimeMillis();
-                return;
+                // Time this path
+                Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                        Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents");
+                Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                        Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents");
+            } catch (RemoteException re) {
+                re.printStackTrace();
             }
-
-            // Determine whether the top task is currently home
-            isTopTaskHome = ssp.isInHomeStack(topTask.id);
+            mLastToggleTime = System.currentTimeMillis();
+            return;
+        } else {
+            // Otherwise, start the recents activity
+            startRecentsActivity(isTopTaskHome.get());
         }
+    }
 
-        // Otherwise, Recents is not the front-most activity and we should animate into it.  If
+    /** Starts the recents activity if it is not already running */
+    void startRecentsActivity() {
+        // Check if the top task is in the home stack, and start the recents activity
+        AtomicBoolean isTopTaskHome = new AtomicBoolean();
+        if (!isRecentsTopMost(isTopTaskHome)) {
+            startRecentsActivity(isTopTaskHome.get());
+        }
+    }
+
+    /** Starts the recents activity */
+    void startRecentsActivity(boolean isTopTaskHome) {
+        // If Recents is not the front-most activity and we should animate into it.  If
         // the activity at the root of the top task stack in the home stack, then we just do a
         // simple transition.  Otherwise, we animate to the rects defined by the Recents service,
         // which can differ depending on the number of items in the list.
+        SystemServicesProxy ssp = mSystemServicesProxy;
         List<ActivityManager.RecentTaskInfo> recentTasks =
                 ssp.getRecentTasks(2, UserHandle.CURRENT.getIdentifier());
         Rect taskRect = hasMultipleRecentsTask(recentTasks) ? mMultipleCountFirstTaskRect :
@@ -422,9 +476,6 @@
         }
 
         // If there is no thumbnail transition, then just use a generic transition
-        // XXX: This should be different between home and from a recents-excluded app, perhaps the
-        //      recents-excluded app should still show up in recents, when the app is in the
-        //      foreground
         if (!useThumbnailTransition) {
             ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
                     R.anim.recents_from_launcher_enter,
@@ -444,6 +495,7 @@
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
         intent.putExtra(EXTRA_ANIMATING_WITH_THUMBNAIL, animatingWithThumbnail);
+        intent.putExtra(EXTRA_FROM_ALT_TAB, mTriggeredFromAltTab);
         if (opts != null) {
             mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
                     UserHandle.USER_CURRENT));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 90998da..9390b0d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -69,6 +69,7 @@
             public static final boolean TouchEvents = false;
             public static final boolean MeasureAndLayout = false;
             public static final boolean HwLayers = false;
+            public static final boolean Focus = false;
         }
 
         public static class TaskStack {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index b74f6ac..325e4b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -28,6 +28,7 @@
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.util.Pair;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
@@ -81,7 +82,10 @@
             String action = intent.getAction();
             Console.log(Constants.Log.App.SystemUIHandshake,
                     "[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed);
-            if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
+            if (action.equals(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY)) {
+                // Dismiss recents, launching the focused task
+                dismissRecentsIfVisible();
+            } else if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
                 // Try and unfilter and filtered stacks
                 if (!mRecentsView.unfilterFilteredStacks()) {
                     // If there are no filtered stacks, dismiss recents and launch the first task
@@ -105,6 +109,8 @@
         RecentsConfiguration config = RecentsConfiguration.getInstance();
         config.launchedWithThumbnailAnimation = launchIntent.getBooleanExtra(
                 AlternateRecentsComponent.EXTRA_ANIMATING_WITH_THUMBNAIL, false);
+        config.launchedFromAltTab = launchIntent.getBooleanExtra(
+                AlternateRecentsComponent.EXTRA_FROM_ALT_TAB, false);
 
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         SpaceNode root = loader.reload(this, Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount);
@@ -184,7 +190,7 @@
             int appWidgetId = config.searchBarAppWidgetId;
             if (appWidgetId >= 0) {
                 Console.log(Constants.Log.App.SystemUIHandshake,
-                        "[RecentsActivity|onCreate|addSearchAppWidgetView]",
+                "[RecentsActivity|onCreate|addSearchAppWidgetView]",
                         "Id: " + appWidgetId,
                         Console.AnsiBlue);
                 mSearchAppWidgetHostView = mAppWidgetHost.createView(this, appWidgetId,
@@ -205,8 +211,10 @@
     /** Dismisses recents if we are already visible and the intent is to toggle the recents view */
     boolean dismissRecentsIfVisible() {
         if (mVisible) {
-            if (!mRecentsView.launchFirstTask()) {
-                finish();
+            if (!mRecentsView.launchFocusedTask()) {
+                if (!mRecentsView.launchFirstTask()) {
+                    finish();
+                }
             }
             return true;
         }
@@ -303,6 +311,7 @@
 
         // Register the broadcast receiver to handle messages from our service
         IntentFilter filter = new IntentFilter();
+        filter.addAction(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY);
         filter.addAction(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY);
         registerReceiver(mServiceBroadcastReceiver, filter);
 
@@ -362,6 +371,18 @@
     }
 
     @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_TAB) {
+            // Focus the next task in the stack
+            final boolean backward = event.isShiftPressed();
+            mRecentsView.focusNextTask(!backward);
+            return true;
+        }
+
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
     public void onBackPressed() {
         boolean interceptedByInfoPanelClose = false;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 9afc1cb..8399551 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -65,6 +65,7 @@
     public int taskBarViewLightTextColor;
     public int taskBarViewDarkTextColor;
 
+    public boolean launchedFromAltTab;
     public boolean launchedWithThumbnailAnimation;
 
     /** Private constructor */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 837cb34..601b382 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -106,8 +106,11 @@
             } catch (RemoteException re) {
                 re.printStackTrace();
             }
-        } else if (msg.what == AlternateRecentsComponent.MSG_CLOSE_RECENTS) {
-            // Do nothing
+        } else if (msg.what == AlternateRecentsComponent.MSG_HIDE_RECENTS) {
+            // Send a broadcast to hide recents
+            Intent intent = new Intent(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY);
+            intent.setPackage(context.getPackageName());
+            context.sendBroadcast(intent);
         } else if (msg.what == AlternateRecentsComponent.MSG_TOGGLE_RECENTS) {
             // Send a broadcast to toggle recents
             Intent intent = new Intent(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY);
@@ -125,6 +128,7 @@
 
 /* Service */
 public class RecentsService extends Service {
+    final static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity";
     final static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
 
     Messenger mSystemUIMessenger = new Messenger(new SystemUIMessageHandler(this));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index a6d7e67..2821052 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -94,6 +94,34 @@
         }
     }
 
+    /** Launches the focused task from the first stack if possible */
+    public boolean launchFocusedTask() {
+        // Get the first stack view
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child instanceof TaskStackView) {
+                TaskStackView stackView = (TaskStackView) child;
+                TaskStack stack = stackView.mStack;
+                // Iterate the stack views and try and find the focused task
+                int taskCount = stackView.getChildCount();
+                for (int j = 0; j < taskCount; j++) {
+                    TaskView tv = (TaskView) stackView.getChildAt(j);
+                    Task task = tv.getTask();
+                    if (tv.isFocusedTask()) {
+                        Console.log(Constants.Log.UI.Focus, "[RecentsView|launchFocusedTask]",
+                                "Found focused Task");
+                        onTaskLaunched(stackView, tv, stack, task);
+                        return true;
+                    }
+                }
+            }
+        }
+        Console.log(Constants.Log.UI.Focus, "[RecentsView|launchFocusedTask]",
+                "No Tasks focused");
+        return false;
+    }
+
     /** Launches the first task from the first stack if possible */
     public boolean launchFirstTask() {
         // Get the first stack view
@@ -234,6 +262,24 @@
         }
     }
 
+    /** Focuses the next task in the first stack view */
+    public void focusNextTask(boolean forward) {
+        // Get the first stack view
+        TaskStackView stackView = null;
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child instanceof TaskStackView) {
+                stackView = (TaskStackView) child;
+                break;
+            }
+        }
+
+        if (stackView != null) {
+            stackView.focusNextTask(forward);
+        }
+    }
+
     @Override
     protected void dispatchDraw(Canvas canvas) {
         Console.log(Constants.Log.UI.Draw, "[RecentsView|dispatchDraw]", "",
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index b64225e..37c3c35 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -80,6 +80,7 @@
     int mMaxScroll;
     int mStashedScroll;
     int mLastInfoPaneStackScroll;
+    int mFocusedTaskIndex = -1;
     OverScroller mScroller;
     ObjectAnimator mScrollAnimator;
 
@@ -306,6 +307,15 @@
         mStackScroll = value;
     }
 
+    /**
+     * Returns the scroll to such that the task transform at that index will have t=0. (If the scroll
+     * is not bounded)
+     */
+    int getStackScrollForTaskIndex(int i) {
+        int taskHeight = mTaskRect.height();
+        return (int) (i * Constants.Values.TaskStackView.StackOverlapPct * taskHeight);
+    }
+
     /** Gets the current stack scroll */
     public int getStackScroll() {
         return mStackScroll;
@@ -460,6 +470,64 @@
         return false;
     }
 
+    /** Focuses the task at the specified index in the stack */
+    void focusTask(int taskIndex, boolean scrollToNewPosition) {
+        Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]", "" + taskIndex);
+        if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) {
+            mFocusedTaskIndex = taskIndex;
+
+            // Focus the view if possible, otherwise, focus the view after we scroll into position
+            Task t = mStack.getTasks().get(taskIndex);
+            TaskView tv = getChildViewForTask(t);
+            Runnable postScrollRunnable = null;
+            if (tv != null) {
+                tv.setFocusedTask();
+                Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]", "Requesting focus");
+            } else {
+                postScrollRunnable = new Runnable() {
+                    @Override
+                    public void run() {
+                        Task t = mStack.getTasks().get(mFocusedTaskIndex);
+                        TaskView tv = getChildViewForTask(t);
+                        if (tv != null) {
+                            tv.setFocusedTask();
+                            Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]",
+                                    "Requesting focus after scroll animation");
+                        }
+                    }
+                };
+            }
+
+            if (scrollToNewPosition) {
+                // Scroll the view into position
+                int newScroll = Math.max(mMinScroll, Math.min(mMaxScroll,
+                        getStackScrollForTaskIndex(taskIndex)));
+
+                animateScroll(getStackScroll(), newScroll, postScrollRunnable);
+            } else {
+                if (postScrollRunnable != null) {
+                    postScrollRunnable.run();
+                }
+            }
+        }
+    }
+
+    /** Focuses the next task in the stack */
+    void focusNextTask(boolean forward) {
+        Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusNextTask]", "" + mFocusedTaskIndex);
+
+        // Find the next index to focus
+        int numTasks = mStack.getTaskCount();
+        if (mFocusedTaskIndex < 0) {
+            mFocusedTaskIndex = numTasks - 1;
+        }
+        if (0 <= mFocusedTaskIndex && mFocusedTaskIndex < numTasks) {
+            mFocusedTaskIndex = Math.max(0, Math.min(numTasks - 1,
+                    mFocusedTaskIndex + (forward ? -1 : 1)));
+        }
+        focusTask(mFocusedTaskIndex, true);
+    }
+
     /** Enables the hw layers and increments the hw layer requirement ref count */
     void addHwLayersRefCount(String reason) {
         Console.log(Constants.Log.UI.HwLayers,
@@ -631,6 +699,11 @@
             requestSynchronizeStackViewsWithModel();
             synchronizeStackViewsWithModel();
 
+            // Update the focused task index to be the next item to the top task
+            if (config.launchedFromAltTab) {
+                focusTask(Math.max(0, mStack.getTaskCount() - 2), false);
+            }
+
             // Animate the task bar of the first task view
             if (config.launchedWithThumbnailAnimation) {
                 TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 5fad629..ffcb82b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -18,6 +18,7 @@
 
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Outline;
@@ -57,6 +58,7 @@
     Task mTask;
     boolean mTaskDataLoaded;
     boolean mTaskInfoPaneVisible;
+    boolean mIsFocused;
     Point mLastTouchDown = new Point();
     Path mRoundedRectClipPath = new Path();
 
@@ -367,6 +369,34 @@
         }
     }
 
+    /**
+     * Sets the focused task explicitly. We need a separate flag because requestFocus() won't happen
+     * if the view is not currently visible, or we are in touch state (where we still want to keep
+     * track of focus).
+     */
+    public void setFocusedTask() {
+        mIsFocused = true;
+        requestFocus();
+    }
+
+    /**
+     * Updates the explicitly focused state when the view focus changes.
+     */
+    @Override
+    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        if (!gainFocus) {
+            mIsFocused = false;
+        }
+    }
+
+    /**
+     * Returns whether we have explicitly been focused.
+     */
+    public boolean isFocusedTask() {
+        return mIsFocused || isFocused();
+    }
+
     /**** TaskCallbacks Implementation ****/
 
     /** Binds this task view to the task */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index c1228d9..7918dec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -87,8 +87,9 @@
     public static final boolean DEBUG = false;
     public static final boolean MULTIUSER_DEBUG = false;
 
-    protected static final int MSG_TOGGLE_RECENTS_PANEL = 1020;
-    protected static final int MSG_CLOSE_RECENTS_PANEL = 1021;
+    protected static final int MSG_SHOW_RECENT_APPS = 1019;
+    protected static final int MSG_HIDE_RECENT_APPS = 1020;
+    protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
     protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
     protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
     protected static final int MSG_OPEN_SEARCH_PANEL = 1024;
@@ -496,8 +497,22 @@
     }
 
     @Override
+    public void showRecentApps(boolean triggeredFromAltTab) {
+        int msg = MSG_SHOW_RECENT_APPS;
+        mHandler.removeMessages(msg);
+        mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, 0).sendToTarget();
+    }
+
+    @Override
+    public void hideRecentApps() {
+        int msg = MSG_HIDE_RECENT_APPS;
+        mHandler.removeMessages(msg);
+        mHandler.sendEmptyMessage(msg);
+    }
+
+    @Override
     public void toggleRecentApps() {
-        int msg = MSG_TOGGLE_RECENTS_PANEL;
+        int msg = MSG_TOGGLE_RECENTS_APPS;
         mHandler.removeMessages(msg);
         mHandler.sendEmptyMessage(msg);
     }
@@ -580,12 +595,12 @@
         public boolean onTouch(View v, MotionEvent event) {
             int action = event.getAction() & MotionEvent.ACTION_MASK;
             if (action == MotionEvent.ACTION_DOWN) {
-                preloadRecentTasksList();
+                preloadRecents();
             } else if (action == MotionEvent.ACTION_CANCEL) {
-                cancelPreloadingRecentTasksList();
+                cancelPreloadingRecents();
             } else if (action == MotionEvent.ACTION_UP) {
                 if (!v.isPressed()) {
-                    cancelPreloadingRecentTasksList();
+                    cancelPreloadingRecents();
                 }
 
             }
@@ -593,28 +608,38 @@
         }
     };
 
-    protected void toggleRecentsActivity() {
+    /** Proxy for RecentsComponent */
+
+    protected void showRecents(boolean triggeredFromAltTab) {
+        if (mRecents != null) {
+            sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
+            mRecents.showRecents(triggeredFromAltTab, getStatusBarView());
+        }
+    }
+
+    protected void hideRecents() {
+        if (mRecents != null) {
+            sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
+            mRecents.hideRecents();
+        }
+    }
+
+    protected void toggleRecents() {
         if (mRecents != null) {
             sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
             mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
         }
     }
 
-    protected void preloadRecentTasksList() {
+    protected void preloadRecents() {
         if (mRecents != null) {
-            mRecents.preloadRecentTasksList();
+            mRecents.preloadRecents();
         }
     }
 
-    protected void cancelPreloadingRecentTasksList() {
+    protected void cancelPreloadingRecents() {
         if (mRecents != null) {
-            mRecents.cancelPreloadingRecentTasksList();
-        }
-    }
-
-    protected void closeRecents() {
-        if (mRecents != null) {
-            mRecents.closeRecents();
+            mRecents.cancelPreloadingRecents();
         }
     }
 
@@ -655,17 +680,20 @@
         public void handleMessage(Message m) {
             Intent intent;
             switch (m.what) {
-             case MSG_TOGGLE_RECENTS_PANEL:
-                 toggleRecentsActivity();
+             case MSG_SHOW_RECENT_APPS:
+                 showRecents(m.arg1 > 0);
                  break;
-             case MSG_CLOSE_RECENTS_PANEL:
-                 closeRecents();
+             case MSG_HIDE_RECENT_APPS:
+                 hideRecents();
+                 break;
+             case MSG_TOGGLE_RECENTS_APPS:
+                 toggleRecents();
                  break;
              case MSG_PRELOAD_RECENT_APPS:
-                  preloadRecentTasksList();
+                  preloadRecents();
                   break;
              case MSG_CANCEL_PRELOAD_RECENT_APPS:
-                  cancelPreloadingRecentTasksList();
+                  cancelPreloadingRecents();
                   break;
              case MSG_OPEN_SEARCH_PANEL:
                  if (DEBUG) Log.d(TAG, "opening search panel");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 5362af5..ebab7fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -57,6 +57,8 @@
     private static final int MSG_PRELOAD_RECENT_APPS        = 14 << MSG_SHIFT;
     private static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 15 << MSG_SHIFT;
     private static final int MSG_SET_WINDOW_STATE           = 16 << MSG_SHIFT;
+    private static final int MSG_SHOW_RECENT_APPS           = 17 << MSG_SHIFT;
+    private static final int MSG_HIDE_RECENT_APPS           = 18 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -96,11 +98,13 @@
         public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
                 boolean showImeSwitcher);
         public void setHardKeyboardStatus(boolean available, boolean enabled);
+        public void showRecentApps(boolean triggeredFromAltTab);
+        public void hideRecentApps();
         public void toggleRecentApps();
         public void preloadRecentApps();
+        public void cancelPreloadRecentApps();
         public void showSearchPanel();
         public void hideSearchPanel();
-        public void cancelPreloadRecentApps();
         public void setWindowState(int window, int state);
 
     }
@@ -211,6 +215,21 @@
         }
     }
 
+    public void showRecentApps(boolean triggeredFromAltTab) {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_SHOW_RECENT_APPS);
+            mHandler.obtainMessage(MSG_SHOW_RECENT_APPS,
+                    triggeredFromAltTab ? 1 : 0, 0, null).sendToTarget();
+        }
+    }
+
+    public void hideRecentApps() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
+            mHandler.obtainMessage(MSG_HIDE_RECENT_APPS, 0, 0, null).sendToTarget();
+        }
+    }
+
     public void toggleRecentApps() {
         synchronized (mList) {
             mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
@@ -309,6 +328,12 @@
                 case MSG_SET_HARD_KEYBOARD_STATUS:
                     mCallbacks.setHardKeyboardStatus(msg.arg1 != 0, msg.arg2 != 0);
                     break;
+                case MSG_SHOW_RECENT_APPS:
+                    mCallbacks.showRecentApps(msg.arg1 != 0);
+                    break;
+                case MSG_HIDE_RECENT_APPS:
+                    mCallbacks.hideRecentApps();
+                    break;
                 case MSG_TOGGLE_RECENT_APPS:
                     mCallbacks.toggleRecentApps();
                     break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 869edff..0a3fdef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -60,7 +60,8 @@
         } else if (mDemoMode && command.equals(COMMAND_STATUS)) {
             String volume = args.getString("volume");
             if (volume != null) {
-                int iconId = volume.equals("silent") ? R.drawable.stat_sys_ringer_silent
+                int iconId = volume.equals("zen") ? R.drawable.stat_sys_ringer_zen
+                        : volume.equals("silent") ? R.drawable.stat_sys_ringer_silent
                         : volume.equals("vibrate") ? R.drawable.stat_sys_ringer_vibrate
                         : 0;
                 updateSlot("volume", null, iconId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index a685073..1072e49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -223,8 +223,6 @@
     IconMerger mNotificationIcons;
     // [+>
     View mMoreIcon;
-    // mode indicator icon
-    ImageView mModeIcon;
 
     // expanded notifications
     NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -488,13 +486,14 @@
     @Override
     public void setZenMode(int mode) {
         super.setZenMode(mode);
-        if (mModeIcon == null) return;
         if (!isDeviceProvisioned()) return;
         final boolean zen = mode != Settings.Global.ZEN_MODE_OFF;
-        mModeIcon.setVisibility(zen ? View.VISIBLE : View.GONE);
         if (!zen) {
             mIntercepted.releaseIntercepted();
         }
+        if (mIconPolicy != null) {
+            mIconPolicy.setZenMode(zen);
+        }
     }
 
     @Override
@@ -618,8 +617,6 @@
         mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
         mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
         mNotificationIcons.setOverflowIndicator(mMoreIcon);
-        mModeIcon = (ImageView)mStatusBarView.findViewById(R.id.modeIcon);
-        mModeIcon.setImageResource(R.drawable.ic_qs_zen_on);
         mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
         mTickerView = mStatusBarView.findViewById(R.id.ticker);
 
@@ -1396,8 +1393,8 @@
 
             if ((state & StatusBarManager.DISABLE_RECENT) != 0) {
                 // close recents if it's visible
-                mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
-                mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
+                mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
+                mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
             }
         }
 
@@ -1548,8 +1545,8 @@
         }
 
         if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
-            mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
-            mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
+            mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
+            mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
         }
 
         if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 194774d..b6f5ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -63,6 +63,9 @@
     // ringer volume
     private boolean mVolumeVisible;
 
+    // zen mode
+    private boolean mZen;
+
     // bluetooth device status
     private boolean mBluetoothEnabled = false;
 
@@ -152,6 +155,11 @@
         updateVolume();
     }
 
+    public void setZenMode(boolean zen) {
+        mZen = zen;
+        updateVolume();
+    }
+
     private final void updateAlarm(Intent intent) {
         boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
         mService.setIconVisibility("alarm_clock", alarmSet);
@@ -195,11 +203,15 @@
         AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         final int ringerMode = audioManager.getRingerMode();
         final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
-                ringerMode == AudioManager.RINGER_MODE_VIBRATE;
+                ringerMode == AudioManager.RINGER_MODE_VIBRATE ||
+                mZen;
 
         final int iconId;
         String contentDescription = null;
-        if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+        if (mZen) {
+            iconId = R.drawable.stat_sys_ringer_zen;
+            contentDescription = mContext.getString(R.string.zen_mode_title);
+        } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
             iconId = R.drawable.stat_sys_ringer_vibrate;
             contentDescription = mContext.getString(R.string.accessibility_ringer_vibrate);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 58ada75..3ef998e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -798,9 +798,29 @@
     }
 
     @Override
-    protected int computeVerticalScrollRange() {
-        // needed for the overScroller
-        return mContentHeight;
+    protected boolean overScrollBy(int deltaX, int deltaY,
+            int scrollX, int scrollY,
+            int scrollRangeX, int scrollRangeY,
+            int maxOverScrollX, int maxOverScrollY,
+            boolean isTouchEvent) {
+
+        int newScrollY = scrollY + deltaY;
+
+        final int top = -maxOverScrollY;
+        final int bottom = maxOverScrollY + scrollRangeY;
+
+        boolean clampedY = false;
+        if (newScrollY > bottom) {
+            newScrollY = bottom;
+            clampedY = true;
+        } else if (newScrollY < top) {
+            newScrollY = top;
+            clampedY = true;
+        }
+
+        onOverScrolled(0, newScrollY, false, clampedY);
+
+        return clampedY;
     }
 
     /**
@@ -1023,8 +1043,7 @@
      */
     private void fling(int velocityY) {
         if (getChildCount() > 0) {
-            int height = (int) getLayoutHeight();
-            int bottom = getContentHeight();
+            int scrollRange = getScrollRange();
 
             float topAmount = getCurrentOverScrollAmount(true);
             float bottomAmount = getCurrentOverScrollAmount(false);
@@ -1043,7 +1062,7 @@
                 mMaxOverScroll = 0.0f;
             }
             mScroller.fling(mScrollX, mOwnScrollY, 1, velocityY, 0, 0, 0,
-                    Math.max(0, bottom - height), 0, height/2);
+                    Math.max(0, scrollRange), 0, Integer.MAX_VALUE / 2);
 
             postInvalidateOnAnimation();
         }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8eed414..7c89d23 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -46,6 +46,7 @@
 import android.media.IAudioService;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
+import android.media.session.MediaSessionLegacyHelper;
 import android.os.Bundle;
 import android.os.FactoryTest;
 import android.os.Handler;
@@ -137,6 +138,9 @@
     static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
     static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
 
+    // Whether to use the new Session APIs
+    static final boolean USE_SESSIONS = true;
+
     static final int LONG_PRESS_POWER_NOTHING = 0;
     static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
     static final int LONG_PRESS_POWER_SHUT_OFF = 2;
@@ -261,13 +265,7 @@
     WindowState mLastInputMethodWindow = null;
     WindowState mLastInputMethodTargetWindow = null;
 
-    static final int RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS = 0;
-    static final int RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW = 1;
-    static final int RECENT_APPS_BEHAVIOR_DISMISS = 2;
-    static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 3;
-
-    RecentApplicationsDialog mRecentAppsDialog;
-    int mRecentAppsDialogHeldModifiers;
+    int mRecentAppsHeldModifiers;
     boolean mLanguageSwitchKeyPressed;
 
     int mLidState = LID_ABSENT;
@@ -807,52 +805,6 @@
         }
     };
 
-    /**
-     * Create (if necessary) and show or dismiss the recent apps dialog according
-     * according to the requested behavior.
-     */
-    void showOrHideRecentAppsDialog(final int behavior) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                if (mRecentAppsDialog == null) {
-                    mRecentAppsDialog = new RecentApplicationsDialog(mContext);
-                }
-                if (mRecentAppsDialog.isShowing()) {
-                    switch (behavior) {
-                        case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS:
-                        case RECENT_APPS_BEHAVIOR_DISMISS:
-                            mRecentAppsDialog.dismiss();
-                            break;
-                        case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
-                            mRecentAppsDialog.dismissAndSwitch();
-                            break;
-                        case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW:
-                        default:
-                            break;
-                    }
-                } else {
-                    switch (behavior) {
-                        case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS:
-                            mRecentAppsDialog.show();
-                            break;
-                        case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW:
-                            try {
-                                mWindowManager.setInTouchMode(false);
-                            } catch (RemoteException e) {
-                            }
-                            mRecentAppsDialog.show();
-                            break;
-                        case RECENT_APPS_BEHAVIOR_DISMISS:
-                        case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
-                        default:
-                            break;
-                    }
-                }
-            }
-        });
-    }
-
     /** {@inheritDoc} */
     @Override
     public void init(Context context, IWindowManager windowManager,
@@ -1377,11 +1329,11 @@
                     | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
         }
     }
-    
+
     void readLidState() {
         mLidState = mWindowManagerFuncs.getLidState();
     }
-    
+
     private boolean isHidden(int accessibilityMode) {
         switch (accessibilityMode) {
             case 1:
@@ -1728,16 +1680,16 @@
 
     /**
      * Preflight adding a window to the system.
-     * 
+     *
      * Currently enforces that three window types are singletons:
      * <ul>
      * <li>STATUS_BAR_TYPE</li>
      * <li>KEYGUARD_TYPE</li>
      * </ul>
-     * 
+     *
      * @param win The window to be added
      * @param attrs Information about the window to be added
-     * 
+     *
      * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons,
      * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
      */
@@ -1810,7 +1762,7 @@
     }
 
     static final boolean PRINT_ANIM = false;
-    
+
     /** {@inheritDoc} */
     @Override
     public int selectAnimationLw(WindowState win, int transit) {
@@ -2261,21 +2213,20 @@
 
         // Display task switcher for ALT-TAB or Meta-TAB.
         if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) {
-            if (mRecentAppsDialogHeldModifiers == 0 && !keyguardOn) {
+            if (mRecentAppsHeldModifiers == 0 && !keyguardOn) {
                 final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
                 if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
                         || KeyEvent.metaStateHasModifiers(
                                 shiftlessModifiers, KeyEvent.META_META_ON)) {
-                    mRecentAppsDialogHeldModifiers = shiftlessModifiers;
-                    showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW);
+                    mRecentAppsHeldModifiers = shiftlessModifiers;
+                    showRecentApps(true);
                     return -1;
                 }
             }
-        } else if (!down && mRecentAppsDialogHeldModifiers != 0
-                && (metaState & mRecentAppsDialogHeldModifiers) == 0) {
-            mRecentAppsDialogHeldModifiers = 0;
-            showOrHideRecentAppsDialog(keyguardOn ? RECENT_APPS_BEHAVIOR_DISMISS :
-                    RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH);
+        } else if (!down && mRecentAppsHeldModifiers != 0
+                && (metaState & mRecentAppsHeldModifiers) == 0) {
+            mRecentAppsHeldModifiers = 0;
+            hideRecentApps();
         }
 
         // Handle keyboard language switching.
@@ -2390,7 +2341,7 @@
         Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         try {
-            // TODO: This only stops the factory-installed search manager.  
+            // TODO: This only stops the factory-installed search manager.
             // Need to formalize an API to handle others
             SearchManager searchManager = getSearchManager();
             if (searchManager != null) {
@@ -2448,7 +2399,7 @@
                     statusbar.cancelPreloadRecentApps();
                 }
             } catch (RemoteException e) {
-                Slog.e(TAG, "RemoteException when showing recent apps", e);
+                Slog.e(TAG, "RemoteException when cancelling recent apps preload", e);
                 // re-acquire status bar service next time it is needed.
                 mStatusBarService = null;
             }
@@ -2457,19 +2408,46 @@
 
     private void toggleRecentApps() {
         mPreloadedRecentApps = false; // preloading no longer needs to be canceled
-        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
         try {
             IStatusBarService statusbar = getStatusBarService();
             if (statusbar != null) {
                 statusbar.toggleRecentApps();
             }
         } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException when toggling recent apps", e);
+            // re-acquire status bar service next time it is needed.
+            mStatusBarService = null;
+        }
+    }
+
+    private void showRecentApps(boolean triggeredFromAltTab) {
+        mPreloadedRecentApps = false; // preloading no longer needs to be canceled
+        try {
+            IStatusBarService statusbar = getStatusBarService();
+            if (statusbar != null) {
+                statusbar.showRecentApps(triggeredFromAltTab);
+            }
+        } catch (RemoteException e) {
             Slog.e(TAG, "RemoteException when showing recent apps", e);
             // re-acquire status bar service next time it is needed.
             mStatusBarService = null;
         }
     }
 
+    private void hideRecentApps() {
+        mPreloadedRecentApps = false; // preloading no longer needs to be canceled
+        try {
+            IStatusBarService statusbar = getStatusBarService();
+            if (statusbar != null) {
+                statusbar.hideRecentApps();
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException when closing recent apps", e);
+            // re-acquire status bar service next time it is needed.
+            mStatusBarService = null;
+        }
+    }
+
     /**
      * A home key -> launch home action was detected.  Take the appropriate action
      * given the situation with the keyguard.
@@ -3058,7 +3036,7 @@
 
             if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
                     == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
-                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() 
+                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
                             + "): IN_SCREEN, INSET_DECOR");
                 // This is the case for a normal activity window: we want it
                 // to cover all of the screen space, and it can take care of
@@ -3342,7 +3320,7 @@
 
         if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
                 + ": sim=#" + Integer.toHexString(sim)
-                + " attach=" + attached + " type=" + attrs.type 
+                + " attach=" + attached + " type=" + attrs.type
                 + String.format(" flags=0x%08x", fl)
                 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
                 + " of=" + of.toShortString()
@@ -3391,7 +3369,7 @@
         mForceStatusBarFromKeyguard = false;
         mForcingShowNavBar = false;
         mForcingShowNavBarLayer = -1;
-        
+
         mHideLockScreen = false;
         mAllowLockscreenWhenOn = false;
         mDismissKeyguard = DISMISS_KEYGUARD_NONE;
@@ -4235,12 +4213,16 @@
 
     void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) {
         if (ActivityManagerNative.isSystemReady()) {
-            IAudioService audioService = getAudioService();
-            if (audioService != null) {
-                try {
-                    audioService.dispatchMediaKeyEventUnderWakelock(event);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
+            if (USE_SESSIONS) {
+                MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true);
+            } else {
+                IAudioService audioService = getAudioService();
+                if (audioService != null) {
+                    try {
+                        audioService.dispatchMediaKeyEventUnderWakelock(event);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
+                    }
                 }
             }
         }
@@ -4466,7 +4448,7 @@
     }
 
     public void dismissKeyguardLw() {
-        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { 
+        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
             mHandler.post(new Runnable() {
                 public void run() {
                     if (mKeyguardDelegate.isDismissable()) {
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
index 2f0d7d6..bc55ed1 100644
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
+++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
@@ -123,7 +123,7 @@
     }
 
     @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
+      public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_TAB) {
             // Ignore all meta keys other than SHIFT.  The app switch key could be a
             // fallback action chorded with ALT, META or even CTRL depending on the key map.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5f53e49..cc132be 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -20,7 +20,7 @@
 import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
-import static android.net.ConnectivityManager.NetworkCallbacks;
+import static android.net.ConnectivityManager.NetworkCallbackListener;
 import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
 import static android.net.ConnectivityManager.TYPE_DUMMY;
 import static android.net.ConnectivityManager.TYPE_ETHERNET;
@@ -507,10 +507,14 @@
 
     TelephonyManager mTelephonyManager;
 
+    // sequence number for Networks
     private final static int MIN_NET_ID = 10; // some reserved marks
     private final static int MAX_NET_ID = 65535;
     private int mNextNetId = MIN_NET_ID;
 
+    // sequence number of NetworkRequests
+    private int mNextNetworkRequestId = 1;
+
     public ConnectivityService(Context context, INetworkManagementService netd,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
         // Currently, omitting a NetworkFactory will create one internally
@@ -526,7 +530,7 @@
         NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
         netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
-        mDefaultRequest = new NetworkRequest(netCap, true);
+        mDefaultRequest = new NetworkRequest(netCap, true, nextNetworkRequestId());
         NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(),
                 NetworkRequestInfo.REQUEST);
         mNetworkRequests.put(mDefaultRequest, nri);
@@ -773,6 +777,10 @@
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
     }
 
+    private synchronized int nextNetworkRequestId() {
+        return mNextNetworkRequestId++;
+    }
+
     private synchronized int nextNetId() {
         int netId = mNextNetId;
         if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID;
@@ -5271,7 +5279,7 @@
             throw new IllegalArgumentException("Bad timeout specified");
         }
         NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
-                networkCapabilities));
+                networkCapabilities), false, nextNetworkRequestId());
         if (DBG) log("requestNetwork for " + networkRequest);
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
                 NetworkRequestInfo.REQUEST);
@@ -5297,7 +5305,7 @@
         enforceAccessPermission();
 
         NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
-                networkCapabilities));
+                networkCapabilities), false, nextNetworkRequestId());
         if (DBG) log("listenForNetwork for " + networkRequest);
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
                 NetworkRequestInfo.LISTEN);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 0b9570d..50553ee 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -2369,20 +2369,20 @@
 
     void setEnabledSessionInMainThread(SessionState session) {
         if (mEnabledSession != session) {
-            if (mEnabledSession != null) {
+            if (mEnabledSession != null && mEnabledSession.session != null) {
                 try {
                     if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
-                    mEnabledSession.method.setSessionEnabled(
-                            mEnabledSession.session, false);
+                    mEnabledSession.method.setSessionEnabled(mEnabledSession.session, false);
                 } catch (RemoteException e) {
                 }
             }
             mEnabledSession = session;
-            try {
-                if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
-                session.method.setSessionEnabled(
-                        session.session, true);
-            } catch (RemoteException e) {
+            if (mEnabledSession != null && mEnabledSession.session != null) {
+                try {
+                    if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
+                    mEnabledSession.method.setSessionEnabled(mEnabledSession.session, true);
+                } catch (RemoteException e) {
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index e54e5d0..11fc941 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1847,10 +1847,10 @@
             return true;
         }
         if (mGeocodeProvider != null) {
-            if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
+            if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
         }
         for (LocationProviderProxy proxy : mProxyProviders) {
-            if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
+            if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
         }
         return false;
     }
@@ -1876,19 +1876,23 @@
                 "or UID of a currently bound location provider");
     }
 
-    private boolean doesPackageHaveUid(int uid, String packageName) {
+    /**
+     * Returns true if the given package belongs to the given uid.
+     */
+    private boolean doesUidHavePackage(int uid, String packageName) {
         if (packageName == null) {
             return false;
         }
-        try {
-            ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
-            if (appInfo.uid != uid) {
-                return false;
-            }
-        } catch (NameNotFoundException e) {
+        String[] packageNames = mPackageManager.getPackagesForUid(uid);
+        if (packageNames == null) {
             return false;
         }
-        return true;
+        for (String name : packageNames) {
+            if (packageName.equals(name)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index c1e5e5b..33e59a7 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -742,19 +742,10 @@
         int w = mThumbnailWidth;
         int h = mThumbnailHeight;
         if (w < 0) {
-            Configuration config = res.getConfiguration();
-            boolean useAlternateRecents = (config.smallestScreenWidthDp < 600);
-            if (useAlternateRecents) {
-                mThumbnailWidth = w =
-                   res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width);
-                mThumbnailHeight = h =
-                   res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height);
-            } else {
-                mThumbnailWidth = w =
-                    res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
-                mThumbnailHeight = h =
-                    res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
-            }
+            mThumbnailWidth = w =
+               res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width);
+            mThumbnailHeight = h =
+               res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height);
         }
 
         if (w > 0) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 3d5fb57..bc264fa 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -421,6 +421,7 @@
         final boolean mustNotify;
         boolean mustInitialize = false;
         boolean wasDimOrDoze = false;
+        boolean autoBrightnessAdjustmentChanged = false;
 
         synchronized (mLock) {
             mPendingUpdatePowerStateLocked = false;
@@ -437,6 +438,8 @@
             } else if (mPendingRequestChangedLocked) {
                 wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM
                         || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE);
+                autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment
+                        != mPendingRequestLocked.screenAutoBrightnessAdjustment);
                 mPowerRequest.copyFrom(mPendingRequestLocked);
                 mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
                 mPendingWaitForNegativeProximityLocked = false;
@@ -494,7 +497,7 @@
             if (screenAutoBrightness >= 0 && mPowerRequest.useAutoBrightness) {
                 // Use current auto-brightness value.
                 target = screenAutoBrightness;
-                slow = mUsingScreenAutoBrightness;
+                slow = mUsingScreenAutoBrightness && !autoBrightnessAdjustmentChanged;
                 mUsingScreenAutoBrightness = true;
             } else {
                 // Light sensor is disabled or not ready yet.
diff --git a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
index 1c5cacd..b31153b 100644
--- a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
@@ -26,7 +26,7 @@
 import android.media.routeprovider.RouteRequest;
 import android.media.session.RouteEvent;
 import android.media.session.RouteInfo;
-import android.media.session.Session;
+import android.media.session.MediaSession;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 9677577..00d364b 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -24,16 +24,16 @@
 import android.media.session.ISessionControllerCallback;
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
-import android.media.session.SessionController;
-import android.media.session.MediaMetadata;
+import android.media.session.MediaController;
 import android.media.session.RouteCommand;
 import android.media.session.RouteInfo;
 import android.media.session.RouteOptions;
 import android.media.session.RouteEvent;
-import android.media.session.Session;
-import android.media.session.SessionInfo;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionInfo;
 import android.media.session.RouteInterface;
 import android.media.session.PlaybackState;
+import android.media.MediaMetadata;
 import android.media.Rating;
 import android.os.Bundle;
 import android.os.Handler;
@@ -85,7 +85,7 @@
     private final int mOwnerPid;
     private final int mOwnerUid;
     private final int mUserId;
-    private final SessionInfo mSessionInfo;
+    private final MediaSessionInfo mSessionInfo;
     private final String mTag;
     private final ControllerStub mController;
     private final SessionStub mSession;
@@ -120,7 +120,7 @@
         mOwnerPid = ownerPid;
         mOwnerUid = ownerUid;
         mUserId = userId;
-        mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), ownerPackageName);
+        mSessionInfo = new MediaSessionInfo(UUID.randomUUID().toString(), ownerPackageName);
         mTag = tag;
         mController = new ControllerStub();
         mSession = new SessionStub();
@@ -130,7 +130,7 @@
     }
 
     /**
-     * Get the binder for the {@link Session}.
+     * Get the binder for the {@link MediaSession}.
      *
      * @return The session binder apps talk to.
      */
@@ -139,7 +139,7 @@
     }
 
     /**
-     * Get the binder for the {@link SessionController}.
+     * Get the binder for the {@link MediaController}.
      *
      * @return The controller binder apps talk to.
      */
@@ -170,7 +170,7 @@
      *
      * @return Info that identifies this session.
      */
-    public SessionInfo getSessionInfo() {
+    public MediaSessionInfo getSessionInfo() {
         return mSessionInfo;
     }
 
@@ -209,7 +209,7 @@
      * @return True if this is a system priority session, false otherwise
      */
     public boolean isSystemPriority() {
-        return (mFlags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0;
+        return (mFlags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0;
     }
 
     /**
@@ -221,7 +221,7 @@
     public void selectRoute(RouteInfo route) {
         synchronized (mLock) {
             if (route != mRoute) {
-                disconnect(Session.DISCONNECT_REASON_ROUTE_CHANGED);
+                disconnect(MediaSession.DISCONNECT_REASON_ROUTE_CHANGED);
             }
             mRoute = route;
         }
@@ -335,7 +335,7 @@
     }
 
     public boolean isTransportControlEnabled() {
-        return hasFlag(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
+        return hasFlag(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
     }
 
     @Override
@@ -353,7 +353,7 @@
                 return;
             }
             if (isConnected()) {
-                disconnectLocked(Session.DISCONNECT_REASON_SESSION_DESTROYED);
+                disconnectLocked(MediaSession.DISCONNECT_REASON_SESSION_DESTROYED);
             }
             mRoute = null;
             mRequest = null;
@@ -365,6 +365,10 @@
         return mSessionCb.mCb;
     }
 
+    public void sendMediaButton(KeyEvent ke, ResultReceiver cb) {
+        mSessionCb.sendMediaButton(ke, cb);
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + mTag + " " + this);
 
@@ -536,7 +540,7 @@
 
         @Override
         public void disconnect() {
-            MediaSessionRecord.this.disconnect(Session.DISCONNECT_REASON_PROVIDER_DISCONNECTED);
+            MediaSessionRecord.this.disconnect(MediaSession.DISCONNECT_REASON_PROVIDER_DISCONNECTED);
         }
     };
 
@@ -565,7 +569,7 @@
 
         @Override
         public void setFlags(int flags) {
-            if ((flags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+            if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
                 int pid = getCallingPid();
                 int uid = getCallingUid();
                 mService.enforcePhoneStatePermission(pid, uid);
@@ -623,7 +627,7 @@
         public void disconnectFromRoute(RouteInfo route) {
             if (route != null && mRoute != null
                     && TextUtils.equals(route.getId(), mRoute.getId())) {
-                disconnect(Session.DISCONNECT_REASON_SESSION_DISCONNECTED);
+                disconnect(MediaSession.DISCONNECT_REASON_SESSION_DISCONNECTED);
             }
         }
 
@@ -645,11 +649,11 @@
             mCb = cb;
         }
 
-        public void sendMediaButton(KeyEvent keyEvent) {
+        public void sendMediaButton(KeyEvent keyEvent, ResultReceiver cb) {
             Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
             mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
             try {
-                mCb.onMediaButton(mediaButtonIntent);
+                mCb.onMediaButton(mediaButtonIntent, cb);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
             }
@@ -785,7 +789,7 @@
 
         @Override
         public void sendMediaButton(KeyEvent mediaButtonIntent) {
-            mSessionCb.sendMediaButton(mediaButtonIntent);
+            mSessionCb.sendMediaButton(mediaButtonIntent, null);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 78f3b5f..d9e45f5ba 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -17,9 +17,12 @@
 package com.android.server.media;
 
 import android.Manifest;
+import android.app.Activity;
 import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.media.routeprovider.RouteRequest;
 import android.media.session.ISession;
@@ -27,16 +30,20 @@
 import android.media.session.ISessionManager;
 import android.media.session.RouteInfo;
 import android.media.session.RouteOptions;
-import android.media.session.Session;
+import android.media.session.MediaSession;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
+import android.view.KeyEvent;
 
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
@@ -64,6 +71,7 @@
     // = new ArrayList<MediaRouteProviderProxy>();
     private final Object mLock = new Object();
     private final Handler mHandler = new Handler();
+    private final PowerManager.WakeLock mMediaEventWakeLock;
 
     private MediaSessionRecord mPrioritySession;
     private int mCurrentUserId = -1;
@@ -79,6 +87,8 @@
         super(context);
         mSessionManagerImpl = new SessionManagerImpl();
         mPriorityStack = new MediaSessionStack();
+        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
     }
 
     @Override
@@ -377,7 +387,7 @@
 
     /*
      * When a session is created the following things need to happen.
-     * 1. It's callback binder needs a link to death
+     * 1. Its callback binder needs a link to death
      * 2. It needs to be added to all sessions.
      * 3. It needs to be added to the priority stack.
      * 4. It needs to be added to the relevant user record.
@@ -493,7 +503,7 @@
                 MediaSessionRecord session = mSessions.get(i);
                 MediaSessionService.this.destroySessionLocked(session);
                 if (session.isConnected()) {
-                    session.disconnect(Session.DISCONNECT_REASON_USER_STOPPING);
+                    session.disconnect(MediaSession.DISCONNECT_REASON_USER_STOPPING);
                 }
             }
         }
@@ -585,9 +595,10 @@
     }
 
     class SessionManagerImpl extends ISessionManager.Stub {
-        // TODO add createSessionAsUser, pass user-id to
-        // ActivityManagerNative.handleIncomingUser and stash result for use
-        // when starting services on that session's behalf.
+        private static final String EXTRA_WAKELOCK_ACQUIRED =
+                "android.media.AudioService.WAKELOCK_ACQUIRED";
+        private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
+
         @Override
         public ISession createSession(String packageName, ISessionCallback cb, String tag,
                 int userId) throws RemoteException {
@@ -644,6 +655,59 @@
             }
         }
 
+        /**
+         * Handles the dispatching of the media button events to one of the
+         * registered listeners, or if there was none, broadcast an
+         * ACTION_MEDIA_BUTTON intent to the rest of the system.
+         *
+         * @param keyEvent a non-null KeyEvent whose key code is one of the
+         *            supported media buttons
+         * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
+         *            while this key event is dispatched.
+         */
+        @Override
+        public void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+            if (keyEvent == null || !KeyEvent.isMediaKey(keyEvent.getKeyCode())) {
+                Log.w(TAG, "Attempted to dispatch null or non-media key event.");
+                return;
+            }
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                if (needWakeLock) {
+                    mMediaEventWakeLock.acquire();
+                }
+                synchronized (mLock) {
+                    MediaSessionRecord mbSession = mPriorityStack
+                            .getDefaultMediaButtonSession(mCurrentUserId);
+                    if (mbSession != null) {
+                        if (DEBUG) {
+                            Log.d(TAG, "Sending media key to " + mbSession.getSessionInfo());
+                        }
+                        mbSession.sendMediaButton(keyEvent,
+                                needWakeLock ? mKeyEventDoneReceiver : null);
+                    } else {
+                        if (DEBUG) {
+                            Log.d(TAG, "Sending media key ordered broadcast");
+                        }
+                        // Fallback to legacy behavior
+                        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+                        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+                        if (needWakeLock) {
+                            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED,
+                                    WAKELOCK_RELEASE_ON_FINISHED);
+                        }
+                        getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
+                                null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
         @Override
         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
             if (getContext().checkCallingOrSelfPermission(Manifest.permission.DUMP)
@@ -678,6 +742,36 @@
                 }
             }
         }
+
+        ResultReceiver mKeyEventDoneReceiver = new ResultReceiver(mHandler) {
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                synchronized (mLock) {
+                    if (mMediaEventWakeLock.isHeld()) {
+                        mMediaEventWakeLock.release();
+                    }
+                }
+            }
+        };
+
+        BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent == null) {
+                    return;
+                }
+                Bundle extras = intent.getExtras();
+                if (extras == null) {
+                    return;
+                }
+                synchronized (mLock) {
+                    if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)
+                            && mMediaEventWakeLock.isHeld()) {
+                        mMediaEventWakeLock.release();
+                    }
+                }
+            }
+        };
     }
 
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index f89b14a..7ba9212 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -17,7 +17,7 @@
 package com.android.server.media;
 
 import android.media.session.PlaybackState;
-import android.media.session.Session;
+import android.media.session.MediaSession;
 import android.os.UserHandle;
 
 import java.io.PrintWriter;
@@ -62,7 +62,7 @@
      */
     public void addSession(MediaSessionRecord record) {
         mSessions.add(record);
-        if ((record.getFlags() & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+        if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
             mGlobalPrioritySession = record;
         }
         clearCache();
@@ -134,7 +134,7 @@
     public ArrayList<MediaSessionRecord> getTransportControlSessions(int userId) {
         if (mCachedTransportControlList == null) {
             mCachedTransportControlList = getPriorityListLocked(true,
-                    Session.FLAG_HANDLES_TRANSPORT_CONTROLS, userId);
+                    MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS, userId);
         }
         return mCachedTransportControlList;
     }
@@ -170,7 +170,7 @@
             return mCachedButtonReceiver;
         }
         ArrayList<MediaSessionRecord> records = getPriorityListLocked(true,
-                Session.FLAG_HANDLES_MEDIA_BUTTONS, userId);
+                MediaSession.FLAG_HANDLES_MEDIA_BUTTONS, userId);
         if (records.size() > 0) {
             mCachedButtonReceiver = records.get(0);
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f9eabcd..61b3a89 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1663,7 +1663,10 @@
             updateAllSharedLibrariesLPw();
 
             for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
-                adjustCpuAbisForSharedUserLPw(setting.packages, true /* do dexopt */,
+                // NOTE: We ignore potential failures here during a system scan (like
+                // the rest of the commands above) because there's precious little we
+                // can do about it. A settings error is reported, though.
+                adjustCpuAbisForSharedUserLPw(setting.packages, null,
                         false /* force dexopt */, false /* defer dexopt */);
             }
 
@@ -5613,8 +5616,12 @@
             if ((scanMode&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
                 // We don't do this here during boot because we can do it all
                 // at once after scanning all existing packages.
-                adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
-                        true, forceDex, (scanMode & SCAN_DEFER_DEX) != 0);
+                if (!adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
+                        pkg.applicationInfo.cpuAbi,
+                        forceDex, (scanMode & SCAN_DEFER_DEX) != 0)) {
+                    mLastScanError = PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE;
+                    return null;
+                }
             }
             // We don't expect installation to fail beyond this point,
             if ((scanMode&SCAN_MONITOR) != 0) {
@@ -5960,9 +5967,8 @@
         return pkg;
     }
 
-    public void adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
-            boolean doDexOpt, boolean forceDexOpt, boolean deferDexOpt) {
-        String requiredInstructionSet = null;
+    private boolean adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
+            String requiredInstructionSet, boolean forceDexOpt, boolean deferDexOpt) {
         PackageSetting requirer = null;
         for (PackageSetting ps : packagesForUser) {
             if (ps.cpuAbiString != null) {
@@ -5970,20 +5976,16 @@
                 if (requiredInstructionSet != null) {
                     if (!instructionSet.equals(requiredInstructionSet)) {
                         // We have a mismatch between instruction sets (say arm vs arm64).
-                        //
-                        // TODO: We should rescan all the packages in a shared UID to check if
-                        // they do contain shared libs for other ABIs in addition to the ones we've
-                        // already extracted. For example, the package might contain both arm64-v8a
-                        // and armeabi-v7a shared libs, and we'd have chosen arm64-v8a on 64 bit
-                        // devices.
-                        String errorMessage = "Instruction set mismatch, " + requirer.pkg.packageName
-                                + " requires " + requiredInstructionSet + " whereas " + ps.pkg.packageName
+                        // bail out.
+                        String errorMessage = "Instruction set mismatch, "
+                                + ((requirer == null) ? "[caller]" : requirer.pkg)
+                                + " requires " + requiredInstructionSet + " whereas " + ps.pkg
                                 + " requires " + instructionSet;
                         Slog.e(TAG, errorMessage);
 
                         reportSettingsProblem(Log.WARN, errorMessage);
                         // Give up, don't bother making any other changes to the package settings.
-                        return;
+                        return false;
                     }
                 } else {
                     requiredInstructionSet = instructionSet;
@@ -5999,14 +6001,20 @@
                     if (ps.pkg != null) {
                         ps.pkg.applicationInfo.cpuAbi = requirer.cpuAbiString;
                         Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + ps.cpuAbiString);
-                        if (doDexOpt) {
-                            performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true);
+
+                        if (performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true) == DEX_OPT_FAILED) {
+                            ps.cpuAbiString = null;
+                            ps.pkg.applicationInfo.cpuAbi = null;
+                            return false;
+                        } else {
                             mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet());
                         }
                     }
                 }
             }
         }
+
+        return true;
     }
 
     private void setUpCustomResolverActivity(PackageParser.Package pkg) {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 738ad32..2c38d3c 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -460,6 +460,24 @@
     }
 
     @Override
+    public void showRecentApps(boolean triggeredFromAltTab) {
+        if (mBar != null) {
+            try {
+                mBar.showRecentApps(triggeredFromAltTab);
+            } catch (RemoteException ex) {}
+        }
+    }
+
+    @Override
+    public void hideRecentApps() {
+        if (mBar != null) {
+            try {
+                mBar.hideRecentApps();
+            } catch (RemoteException ex) {}
+        }
+    }
+
+    @Override
     public void setCurrentUser(int newUserId) {
         if (SPEW) Slog.d(TAG, "Setting current user to user " + newUserId);
         mCurrentUserId = newUserId;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 99ec242..c20e38c 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -679,7 +679,7 @@
 
     Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
                             int appWidth, int appHeight, int orientation,
-                            Rect containingFrame, Rect contentInsets, Configuration configuration) {
+                            Rect containingFrame, Rect contentInsets) {
         Animation a;
         if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
             a = loadAnimation(mNextAppTransitionPackage, enter ?
@@ -700,15 +700,9 @@
                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
             mNextAppTransitionScaleUp =
                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
-            boolean useAlternateThumbnailAnimation = (configuration.smallestScreenWidthDp < 600);
-            if (useAlternateThumbnailAnimation) {
-                a = createAlternateThumbnailEnterExitAnimationLocked(
-                        getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
-                        transit, containingFrame, contentInsets);
-            } else {
-                a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
-                        appWidth, appHeight, transit);
-            }
+            a = createAlternateThumbnailEnterExitAnimationLocked(
+                    getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
+                    transit, containingFrame, contentInsets);
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                 String animName = mNextAppTransitionScaleUp ?
                         "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b61ba5c..c6fffbf 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3194,7 +3194,7 @@
             }
 
             Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
-                    mCurConfiguration.orientation, containingFrame, contentInsets, mCurConfiguration);
+                    mCurConfiguration.orientation, containingFrame, contentInsets);
             if (a != null) {
                 if (DEBUG_ANIM) {
                     RuntimeException e = null;
@@ -8677,7 +8677,7 @@
                 wtoken.deferClearAllDrawn = false;
             }
 
-            boolean useAlternateThumbnailAnimation = (mCurConfiguration.smallestScreenWidthDp < 600);
+            boolean useAlternateThumbnailAnimation = true;
             AppWindowAnimator appAnimator =
                     topOpeningApp == null ? null : topOpeningApp.mAppAnimator;
             Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 3c9d53e..1e79dcb 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -46,6 +46,7 @@
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
+import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 import android.view.WindowManager.LayoutParams;
@@ -151,6 +152,10 @@
     static final int READY_TO_SHOW = 3;
     /** Set when the window has been shown in the screen the first time. */
     static final int HAS_DRAWN = 4;
+
+    private static final int SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN =
+            View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+
     static String drawStateToString(int state) {
         switch (state) {
             case NO_SURFACE: return "NO_SURFACE";
@@ -1176,9 +1181,15 @@
             // content insets as well.
             int offsetTop = Math.max(w.mSystemDecorRect.top, w.mContentInsets.top);
             mTmpClipRect.set(w.mSystemDecorRect);
-            mTmpClipRect.offset(0, -offsetTop);
-            mTmpClipRect.intersect(mClipRect);
-            mTmpClipRect.offset(0, offsetTop);
+            // Don't apply the workaround to apps explicitly requesting fullscreen layout.
+            if ((w.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN)
+                    == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) {
+                mTmpClipRect.intersect(mClipRect);
+            } else {
+                mTmpClipRect.offset(0, -offsetTop);
+                mTmpClipRect.intersect(mClipRect);
+                mTmpClipRect.offset(0, offsetTop);
+            }
             clipRect = mTmpClipRect;
 
         }
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
new file mode 100644
index 0000000..6b7463c
--- /dev/null
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -0,0 +1,412 @@
+/*
+ * 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.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Represents a connection to a remote endpoint that carries voice traffic.
+ */
+public abstract class Connection {
+
+    private static String TAG = Connection.class.getSimpleName();
+
+    public interface Listener {
+        void onStateChanged(Connection c, int state);
+        void onAudioStateChanged(Connection c, CallAudioState state);
+        void onHandleChanged(Connection c, Uri newHandle);
+        void onSignalChanged(Connection c, Bundle details);
+        void onDisconnected(Connection c, int cause, String message);
+        void onDestroyed(Connection c);
+    }
+
+    public static class ListenerBase implements Listener {
+        /** {@inheritDoc} */
+        @Override
+        public void onStateChanged(Connection c, int state) {}
+
+        /** {@inheritDoc} */
+         @Override
+        public void onAudioStateChanged(Connection c, CallAudioState state) {}
+
+        /** {@inheritDoc} */
+        @Override
+        public void onHandleChanged(Connection c, Uri newHandle) {}
+
+        /** {@inheritDoc} */
+        @Override
+        public void onSignalChanged(Connection c, Bundle details) {}
+
+        /** {@inheritDoc} */
+        @Override
+        public void onDisconnected(Connection c, int cause, String message) {}
+
+        /** {@inheritDoc} */
+        @Override
+        public void onDestroyed(Connection c) {}
+    }
+
+    public final class State {
+        private State() {}
+
+        public static final int NEW = 0;
+        public static final int RINGING = 1;
+        public static final int DIALING = 2;
+        public static final int ACTIVE = 3;
+        public static final int HOLDING = 4;
+        public static final int DISCONNECTED = 5;
+    }
+
+    private final Set<Listener> mListeners = new HashSet<>();
+    private int mState = State.NEW;
+    private CallAudioState mCallAudioState;
+    private Uri mHandle;
+
+    /**
+     * Create a new Connection.
+     */
+    protected Connection() {}
+
+    /**
+     * @return The handle (e.g., phone number) to which this Connection
+     *         is currently communicating.
+     */
+    public final Uri getHandle() {
+        return mHandle;
+    }
+
+    /**
+     * @return The state of this Connection.
+     *
+     * @hide
+     */
+    public final int getState() {
+        return mState;
+    }
+
+    /**
+     * @return The audio state of the call, describing how its audio is currently
+     *         being routed by the system. This is {@code null} if this Connection
+     *         does not directly know about its audio state.
+     */
+    public final CallAudioState getCallAudioState() {
+        return mCallAudioState;
+    }
+
+    /**
+     * Assign a listener to be notified of state changes.
+     *
+     * @param l A listener.
+     * @return This Connection.
+     *
+     * @hide
+     */
+    public final Connection addConnectionListener(Listener l) {
+        mListeners.add(l);
+        return this;
+    }
+
+    /**
+     * Remove a previously assigned listener that was being notified of state changes.
+     *
+     * @param l A Listener.
+     * @return This Connection.
+     *
+     * @hide
+     */
+    public final Connection removeConnectionListener(Listener l) {
+        mListeners.remove(l);
+        return this;
+    }
+
+    /**
+     * Play a DTMF tone in this Connection.
+     *
+     * @param c A DTMF character.
+     *
+     * @hide
+     */
+    public final void playDtmfTone(char c) {
+        Log.d(TAG, "playDtmfTone " + c);
+        onPlayDtmfTone(c);
+    }
+
+    /**
+     * Stop any DTMF tones which may be playing in this Connection.
+     *
+     * @hide
+     */
+    public final void stopDtmfTone() {
+        Log.d(TAG, "stopDtmfTone");
+        onStopDtmfTone();
+    }
+
+    /**
+     * Disconnect this Connection. If and when the Connection can comply with
+     * this request, it will transition to the {@link State#DISCONNECTED}
+     * state and notify its listeners.
+     *
+     * @hide
+     */
+    public final void disconnect() {
+        Log.d(TAG, "disconnect");
+        onDisconnect();
+    }
+
+    /**
+     * Abort this Connection. The Connection will immediately transition to
+     * the {@link State#DISCONNECTED} state, and send no notifications of this
+     * or any other future events.
+     *
+     * @hide
+     */
+    public final void abort() {
+        Log.d(TAG, "abort");
+        onAbort();
+    }
+
+    /**
+     * Place this Connection on hold. If and when the Connection can comply with
+     * this request, it will transition to the {@link State#HOLDING}
+     * state and notify its listeners.
+     *
+     * @hide
+     */
+    public final void hold() {
+        Log.d(TAG, "hold");
+        onHold();
+    }
+
+    /**
+     * Un-hold this Connection. If and when the Connection can comply with
+     * this request, it will transition to the {@link State#ACTIVE}
+     * state and notify its listeners.
+     *
+     * @hide
+     */
+    public final void unhold() {
+        Log.d(TAG, "unhold");
+        onUnhold();
+    }
+
+    /**
+     * Accept a {@link State#RINGING} Connection. If and when the Connection
+     * can comply with this request, it will transition to the {@link State#ACTIVE}
+     * state and notify its listeners.
+     *
+     * @hide
+     */
+    public final void answer() {
+        Log.d(TAG, "answer");
+        if (mState == State.RINGING) {
+            onAnswer();
+        }
+    }
+
+    /**
+     * Reject a {@link State#RINGING} Connection. If and when the Connection
+     * can comply with this request, it will transition to the {@link State#ACTIVE}
+     * state and notify its listeners.
+     *
+     * @hide
+     */
+    public final void reject() {
+        Log.d(TAG, "reject");
+        if (mState == State.RINGING) {
+            onReject();
+        }
+    }
+
+    /**
+     * Inform this Connection that the state of its audio output has been changed externally.
+     *
+     * @param state The new audio state.
+     */
+    public void setAudioState(CallAudioState state) {
+        Log.d(TAG, "setAudioState " + state);
+        onSetAudioState(state);
+    }
+
+    /**
+     * @param state An integer value from {@link State}.
+     * @return A string representation of the value.
+     */
+    public static String stateToString(int state) {
+        switch (state) {
+            case State.NEW:
+                return "NEW";
+            case State.RINGING:
+                return "RINGING";
+            case State.DIALING:
+                return "DIALING";
+            case State.ACTIVE:
+                return "ACTIVE";
+            case State.HOLDING:
+                return "HOLDING";
+            case State.DISCONNECTED:
+                return "DISCONNECTED";
+            default:
+                Log.wtf(TAG, "Unknown state " + state);
+                return "UNKNOWN";
+        }
+    }
+
+    /**
+     * Sets the value of the {@link #getHandle()} property and notifies listeners.
+     *
+     * @param handle The new handle.
+     */
+    protected void setHandle(Uri handle) {
+        Log.d(TAG, "setHandle " + handle);
+        // TODO: Enforce super called
+        mHandle = handle;
+        for (Listener l : mListeners) {
+            l.onHandleChanged(this, handle);
+        }
+    }
+
+    /**
+     * Sets state to active (e.g., an ongoing call where two or more parties can actively
+     * communicate).
+     */
+    protected void setActive() {
+        setState(State.ACTIVE);
+    }
+
+    /**
+     * Sets state to ringing (e.g., an inbound ringing call).
+     */
+    protected void setRinging() {
+        setState(State.RINGING);
+    }
+
+    /**
+     * Sets state to dialing (e.g., dialing an outbound call).
+     */
+    protected void setDialing() {
+        setState(State.DIALING);
+    }
+
+    /**
+     * Sets state to be on hold.
+     */
+    protected void setOnHold() {
+        setState(State.HOLDING);
+    }
+
+    /**
+     * Sets state to disconnected. This will first notify listeners with an
+     * {@link Listener#onStateChanged(Connection, int)} event, then will fire an
+     * {@link Listener#onDisconnected(Connection, int, String)} event with additional
+     * details.
+     *
+     * @param cause The reason for the disconnection, any of
+     *         {@link android.telephony.DisconnectCause}.
+     * @param message Optional call-service-provided message about the disconnect.
+     */
+    protected void setDisconnected(int cause, String message) {
+        setState(State.DISCONNECTED);
+        Log.d(TAG, "Disconnected with cause " + cause + " message " + message);
+        for (Listener l : mListeners) {
+            l.onDisconnected(this, cause, message);
+        }
+    }
+
+    /**
+     * Notifies this Connection and listeners that the {@link #getCallAudioState()} property
+     * has a new value.
+     *
+     * @param state The new call audio state.
+     */
+    protected void onSetAudioState(CallAudioState state) {
+        // TODO: Enforce super called
+        this.mCallAudioState = state;
+        for (Listener l : mListeners) {
+            l.onAudioStateChanged(this, state);
+        }
+    }
+
+    /**
+     * Notifies this Connection and listeners of a change in the current signal levels
+     * for the underlying data transport.
+     *
+     * @param details A {@link android.os.Bundle} containing details of the current level.
+     */
+    protected void onSetSignal(Bundle details) {
+        // TODO: Enforce super called
+        for (Listener l : mListeners) {
+            l.onSignalChanged(this, details);
+        }
+    }
+
+    /**
+     * Notifies this Connection of a request to play a DTMF tone.
+     *
+     * @param c A DTMF character.
+     */
+    protected void onPlayDtmfTone(char c) {}
+
+    /**
+     * Notifies this Connection of a request to stop any currently playing DTMF tones.
+     */
+    protected void onStopDtmfTone() {}
+
+    /**
+     * Notifies this Connection of a request to disconnect.
+     */
+    protected void onDisconnect() {}
+
+    /**
+     * Notifies this Connection of a request to abort.
+     */
+    protected void onAbort() {}
+
+    /**
+     * Notifies this Connection of a request to hold.
+     */
+    protected void onHold() {}
+
+    /**
+     * Notifies this Connection of a request to exit a hold state.
+     */
+    protected void onUnhold() {}
+
+    /**
+     * Notifies this Connection, which is in {@link State#RINGING}, of
+     * a request to accept.
+     */
+    protected void onAnswer() {}
+
+    /**
+     * Notifies this Connection, which is in {@link State#RINGING}, of
+     * a request to reject.
+     */
+    protected void onReject() {}
+
+    private void setState(int state) {
+        Log.d(TAG, "setState: " + stateToString(state));
+        this.mState = state;
+        for (Listener l : mListeners) {
+            l.onStateChanged(this, state);
+        }
+    }
+}
diff --git a/telecomm/java/android/telecomm/ConnectionRequest.java b/telecomm/java/android/telecomm/ConnectionRequest.java
new file mode 100644
index 0000000..c1f1871
--- /dev/null
+++ b/telecomm/java/android/telecomm/ConnectionRequest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.telecomm;
+
+import android.os.Bundle;
+import android.net.Uri;
+
+/**
+ * Simple data container encapsulating a request to some entity to
+ * create a new {@link Connection}.
+ */
+public final class ConnectionRequest {
+
+    // TODO: Token to limit recursive invocations
+    // TODO: Consider upgrading "mHandle" to ordered list of handles, indicating a set of phone
+    //         numbers that would satisfy the client's needs, in order of preference
+    private final Uri mHandle;
+    private final Bundle mExtras;
+
+    public ConnectionRequest(Uri handle, Bundle extras) {
+        mHandle = handle; mExtras = extras;
+    }
+
+    /**
+     * The handle (e.g., phone number) to which the {@link Connection} is to connect.
+     */
+    public Uri getHandle() { return mHandle; }
+
+    /**
+     * Application-specific extra data. Used for passing back information from an incoming
+     * call {@code Intent}, and for any proprietary extensions arranged between a client
+     * and servant {@code ConnectionService} which agree on a vocabulary for such data.
+     */
+    public Bundle getExtras() { return mExtras; }
+
+    public String toString() {
+        return String.format("PhoneConnectionRequest %s %s",
+                mHandle == null
+                        ? Uri.EMPTY
+                        : ConnectionService.toLogSafePhoneNumber(mHandle.toString()),
+                mExtras == null ? "" : mExtras);
+    }
+}
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
new file mode 100644
index 0000000..aba4579
--- /dev/null
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -0,0 +1,345 @@
+/*
+ * 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.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A {@link android.app.Service} that provides telephone connections to
+ * processes running on an Android device.
+ */
+public abstract class ConnectionService extends CallService {
+    private static final String TAG = ConnectionService.class.getSimpleName();
+
+    // STOPSHIP: Debug Logging should be conditional on a debug flag or use a set of
+    // logging functions that make it automaticaly so.
+
+    // Flag controlling whether PII is emitted into the logs
+    private static final boolean PII_DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private static final Connection NULL_CONNECTION = new Connection() {};
+
+    // Mappings from Connections to IDs as understood by the current CallService implementation
+    private final Map<String, Connection> mConnectionById = new HashMap<>();
+    private final Map<Connection, String> mIdByConnection = new HashMap<>();
+
+    private final Connection.Listener mConnectionListener = new Connection.Listener() {
+        @Override
+        public void onStateChanged(Connection c, int state) {
+            String id = mIdByConnection.get(c);
+            Log.d(TAG, "Adapter set state " + id + " " + Connection.stateToString(state));
+            switch (state) {
+                case Connection.State.ACTIVE:
+                    getAdapter().setActive(id);
+                    break;
+                case Connection.State.DIALING:
+                    getAdapter().setDialing(id);
+                    break;
+                case Connection.State.DISCONNECTED:
+                    // Handled in onDisconnected()
+                    break;
+                case Connection.State.HOLDING:
+                    getAdapter().setOnHold(id);
+                    break;
+                case Connection.State.NEW:
+                    // Nothing to tell Telecomm
+                    break;
+                case Connection.State.RINGING:
+                    getAdapter().setRinging(id);
+                    break;
+            }
+        }
+
+        @Override
+        public void onDisconnected(Connection c, int cause, String message) {
+            String id = mIdByConnection.get(c);
+            Log.d(TAG, "Adapter set disconnected " + cause + " " + message);
+            getAdapter().setDisconnected(id, cause, message);
+        }
+
+        @Override
+        public void onHandleChanged(Connection c, Uri newHandle) {
+            // TODO: Unsupported yet
+        }
+
+        @Override
+        public void onAudioStateChanged(Connection c, CallAudioState state) {
+            // TODO: Unsupported yet
+        }
+
+        @Override
+        public void onSignalChanged(Connection c, Bundle details) {
+            // TODO: Unsupported yet
+        }
+
+        @Override
+        public void onDestroyed(Connection c) {
+            removeConnection(c);
+        }
+    };
+
+    @Override
+    public final void isCompatibleWith(final CallInfo callInfo) {
+        Log.d(TAG, "isCompatibleWith " + callInfo);
+        onFindSubscriptions(
+                callInfo.getHandle(),
+                new Response<Uri, Subscription>() {
+                    @Override
+                    public void onResult(Uri handle, Subscription... result) {
+                        boolean isCompatible = result.length > 0;
+                        Log.d(TAG, "adapter setIsCompatibleWith "
+                                + callInfo.getId() + " " + isCompatible);
+                        getAdapter().setIsCompatibleWith(callInfo.getId(), isCompatible);
+                    }
+
+                    @Override
+                    public void onError(Uri handle, String reason) {
+                        Log.wtf(TAG, "Error in onFindSubscriptions " + callInfo.getHandle()
+                                + " error: " + reason);
+                        getAdapter().setIsCompatibleWith(callInfo.getId(), false);
+                    }
+                }
+        );
+    }
+
+    @Override
+    public final void call(final CallInfo callInfo) {
+        Log.d(TAG, "call " + callInfo);
+        onCreateConnections(
+                new ConnectionRequest(
+                        callInfo.getHandle(),
+                        callInfo.getExtras()),
+                new Response<ConnectionRequest, Connection>() {
+                    @Override
+                    public void onResult(ConnectionRequest request, Connection... result) {
+                        if (result.length != 1) {
+                            Log.d(TAG, "adapter handleFailedOutgoingCall " + callInfo);
+                            getAdapter().handleFailedOutgoingCall(
+                                    callInfo.getId(),
+                                    "Created " + result.length + " Connections, expected 1");
+                            for (Connection c : result) {
+                                c.abort();
+                            }
+                        } else {
+                            addConnection(callInfo.getId(), result[0]);
+                            Log.d(TAG, "adapter handleSuccessfulOutgoingCall "
+                                    + callInfo.getId());
+                            getAdapter().handleSuccessfulOutgoingCall(callInfo.getId());
+                        }
+                    }
+
+                    @Override
+                    public void onError(ConnectionRequest request, String reason) {
+                        getAdapter().handleFailedOutgoingCall(callInfo.getId(), reason);
+                    }
+                }
+        );
+    }
+
+    @Override
+    public final void abort(String callId) {
+        Log.d(TAG, "abort " + callId);
+        findConnectionForAction(callId, "abort").abort();
+    }
+
+    @Override
+    public final void setIncomingCallId(final String callId, Bundle extras) {
+        Log.d(TAG, "setIncomingCallId " + callId + " " + extras);
+        onCreateIncomingConnection(
+                new ConnectionRequest(
+                        null,  // TODO: Can we obtain this from "extras"?
+                        extras),
+                new Response<ConnectionRequest, Connection>() {
+                    @Override
+                    public void onResult(ConnectionRequest request, Connection... result) {
+                        if (result.length != 1) {
+                            Log.d(TAG, "adapter handleFailedOutgoingCall " + callId);
+                            getAdapter().handleFailedOutgoingCall(
+                                    callId,
+                                    "Created " + result.length + " Connections, expected 1");
+                            for (Connection c : result) {
+                                c.abort();
+                            }
+                        } else {
+                            addConnection(callId, result[0]);
+                            Log.d(TAG, "adapter notifyIncomingCall " + callId);
+                            // TODO: Uri.EMPTY is because CallInfo crashes when Parceled with a
+                            // null URI ... need to fix that at its cause!
+                            getAdapter().notifyIncomingCall(new CallInfo(
+                                    callId,
+                                    connectionStateToCallState(result[0].getState()),
+                                    request.getHandle() /* result[0].getHandle() == null
+                                            ? Uri.EMPTY : result[0].getHandle() */));
+                        }
+                    }
+
+                    @Override
+                    public void onError(ConnectionRequest request, String reason) {
+                        Log.d(TAG, "adapter failed setIncomingCallId " + request + " " + reason);
+                    }
+                }
+        );
+    }
+
+    @Override
+    public final void answer(String callId) {
+        Log.d(TAG, "answer " + callId);
+        findConnectionForAction(callId, "answer").answer();
+    }
+
+    @Override
+    public final void reject(String callId) {
+        Log.d(TAG, "reject " + callId);
+        findConnectionForAction(callId, "reject").reject();
+    }
+
+    @Override
+    public final void disconnect(String callId) {
+        Log.d(TAG, "disconnect " + callId);
+        findConnectionForAction(callId, "disconnect").disconnect();
+    }
+
+    @Override
+    public final void hold(String callId) {
+        Log.d(TAG, "hold " + callId);
+        findConnectionForAction(callId, "hold").hold();
+    }
+
+    @Override
+    public final void unhold(String callId) {
+        Log.d(TAG, "unhold " + callId);
+        findConnectionForAction(callId, "unhold").unhold();
+    }
+
+    @Override
+    public final void playDtmfTone(String callId, char digit) {
+        Log.d(TAG, "playDtmfTone " + callId + " " + Character.toString(digit));
+        findConnectionForAction(callId, "playDtmfTone").playDtmfTone(digit);
+    }
+
+    @Override
+    public final void stopDtmfTone(String callId) {
+        Log.d(TAG, "stopDtmfTone " + callId);
+        findConnectionForAction(callId, "stopDtmfTone").stopDtmfTone();
+    }
+
+    @Override
+    public final void onAudioStateChanged(String callId, CallAudioState audioState) {
+        Log.d(TAG, "onAudioStateChanged " + callId + " " + audioState);
+        findConnectionForAction(callId, "onAudioStateChanged").setAudioState(audioState);
+    }
+
+    /**
+     * Find a set of Subscriptions matching a given handle (e.g. phone number).
+     *
+     * @param handle A handle (e.g. phone number) with which to connect.
+     * @param callback A callback for providing the result.
+     */
+    public void onFindSubscriptions(
+            Uri handle,
+            Response<Uri, Subscription> callback) {}
+
+    /**
+     * Create a Connection given a request.
+     *
+     * @param request Data encapsulating details of the desired Connection.
+     * @param callback A callback for providing the result.
+     */
+    public void onCreateConnections(
+            ConnectionRequest request,
+            Response<ConnectionRequest, Connection> callback) {}
+
+    /**
+     * Create a Connection to match an incoming connection notification.
+     *
+     * @param request Data encapsulating details of the desired Connection.
+     * @param callback A callback for providing the result.
+     */
+    public void onCreateIncomingConnection(
+            ConnectionRequest request,
+            Response<ConnectionRequest, Connection> callback) {}
+
+    static String toLogSafePhoneNumber(String number) {
+        // For unknown number, log empty string.
+        if (number == null) {
+            return "";
+        }
+
+        if (PII_DEBUG) {
+            // When PII_DEBUG is true we emit PII.
+            return number;
+        }
+
+        // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare
+        // sanitized phone numbers.
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < number.length(); i++) {
+            char c = number.charAt(i);
+            if (c == '-' || c == '@' || c == '.') {
+                builder.append(c);
+            } else {
+                builder.append('x');
+            }
+        }
+        return builder.toString();
+    }
+
+    private CallState connectionStateToCallState(int connectionState) {
+        switch (connectionState) {
+            case Connection.State.NEW:
+                return CallState.NEW;
+            case Connection.State.RINGING:
+                return CallState.RINGING;
+            case Connection.State.DIALING:
+                return CallState.DIALING;
+            case Connection.State.ACTIVE:
+                return CallState.ACTIVE;
+            case Connection.State.HOLDING:
+                return CallState.ON_HOLD;
+            case Connection.State.DISCONNECTED:
+                return CallState.DISCONNECTED;
+            default:
+                Log.wtf(TAG, "Unknown Connection.State " + connectionState);
+                return CallState.NEW;
+        }
+    }
+
+    private void addConnection(String callId, Connection connection) {
+        mConnectionById.put(callId, connection);
+        mIdByConnection.put(connection, callId);
+        connection.addConnectionListener(mConnectionListener);
+    }
+
+    private void removeConnection(Connection connection) {
+        connection.removeConnectionListener(mConnectionListener);
+        mConnectionById.remove(mIdByConnection.get(connection));
+        mIdByConnection.remove(connection);
+    }
+
+    private Connection findConnectionForAction(String callId, String action) {
+        if (mConnectionById.containsKey(callId)) {
+            return mConnectionById.get(callId);
+        }
+        Log.wtf(TAG, action + " - Cannot find Connection \"" + callId + "\"");
+        return NULL_CONNECTION;
+    }
+}
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/Response.java b/telecomm/java/android/telecomm/Response.java
new file mode 100644
index 0000000..14f8340
--- /dev/null
+++ b/telecomm/java/android/telecomm/Response.java
@@ -0,0 +1,39 @@
+/*
+ * 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.telecomm;
+
+/**
+ * Used to inform a client of asynchronously returned results.
+ */
+public interface Response<IN, OUT> {
+
+    /**
+     * Provide a set of results.
+     *
+     * @param request The original request.
+     * @param result The results.
+     */
+    void onResult(IN request, OUT... result);
+
+    /**
+     * Indicates the inability to provide results.
+     *
+     * @param request The original request.
+     * @param reason The reason for the failure.
+     */
+    void onError(IN request, String reason);
+}
diff --git a/telecomm/java/android/telecomm/Subscription.java b/telecomm/java/android/telecomm/Subscription.java
new file mode 100644
index 0000000..f187f4d
--- /dev/null
+++ b/telecomm/java/android/telecomm/Subscription.java
@@ -0,0 +1,48 @@
+/*
+ * 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.telecomm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a distinct subscription, line of service or call placement method that
+ * a {@link ConnectionService} can use to place phone calls.
+ */
+public class Subscription implements Parcelable {
+
+    public Subscription() {}
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {}
+
+    public static final Parcelable.Creator<Subscription> CREATOR
+            = new Parcelable.Creator<Subscription>() {
+        public Subscription createFromParcel(Parcel in) {
+            return new Subscription(in);
+        }
+
+        public Subscription[] newArray(int size) {
+            return new Subscription[size];
+        }
+    };
+
+    private Subscription(Parcel in) {}
+}
diff --git a/telephony/java/android/telephony/CallStateListener.java b/telephony/java/android/telephony/CallStateListener.java
deleted file mode 100644
index e2ffbfa..0000000
--- a/telephony/java/android/telephony/CallStateListener.java
+++ /dev/null
@@ -1,36 +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.telephony;
-
-import android.annotation.PrivateApi;
-
-/** @hide */
-@PrivateApi
-public interface CallStateListener {
-    /**
-     * Notify of a new or updated call.
-     * Any time the state of a call is updated, it will alert any listeners. This includes changes
-     * of state such as when a call is put on hold or conferenced.
-     *
-     * @param callId a unique ideCntifier for a given call that can be used to track state changes
-     * @param state the new state of the call.
-     *              {@see com.android.services.telephony.common.Call$State}
-     * @param number the phone number of the call. For some states, this may be blank. However, it
-     *               will be populated for any initial state.
-     */
-    public void onCallStateChanged(int callId, int state, String number);
-}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2bf9ef1..5d485c5 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -32,7 +32,6 @@
 
 import com.android.internal.telephony.IPhoneSubInfo;
 import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.ITelephonyListener;
 import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RILConstants;
@@ -82,40 +81,8 @@
         static final int NEVER_USE = 2;
     }
 
-    private final HashMap<CallStateListener,Listener> mListeners
-            = new HashMap<CallStateListener,Listener>();
     private final Context mContext;
 
-    private static class Listener extends ITelephonyListener.Stub {
-        final CallStateListener mListener;
-        private static final int WHAT = 1;
-
-        private Handler mHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                mListener.onCallStateChanged(msg.arg1, msg.arg2, (String)msg.obj);
-            }
-        };
-
-        Listener(CallStateListener listener) {
-            mListener = listener;
-        }
-
-        @Override
-        public void onUpdate(final int callId, final int state, final String number) {
-            if (mHandler != null) {
-                mHandler.sendMessage(mHandler.obtainMessage(WHAT, callId, state, number));
-            }
-        }
-
-        void clearQueue() {
-            mHandler.removeMessages(WHAT);
-
-            // Don't accept more incoming binder calls either.
-            mHandler = null;
-        }
-    }
-
     /** @hide */
     public TelephonyManager(Context context) {
         Context appContext = context.getApplicationContext();
@@ -2047,46 +2014,6 @@
 
     /** @hide */
     @PrivateApi
-    public void toggleHold() {
-        try {
-            getITelephony().toggleHold();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#toggleHold", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void merge() {
-        try {
-            getITelephony().merge();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#merge", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void swap() {
-        try {
-            getITelephony().swap();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#swap", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void mute(boolean mute) {
-        try {
-            getITelephony().mute(mute);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#mute", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
     public void silenceRinger() {
         try {
             getITelephony().silenceRinger();
@@ -2322,56 +2249,4 @@
         }
         return false;
     }
-
-    /** @hide */
-    @PrivateApi
-    public void playDtmfTone(char digit, boolean timedShortCode) {
-        try {
-            getITelephony().playDtmfTone(digit, timedShortCode);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#playDtmfTone", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void stopDtmfTone() {
-        try {
-            getITelephony().stopDtmfTone();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#stopDtmfTone", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void addCallStateListener(CallStateListener listener) {
-        try {
-            if (listener == null) {
-                throw new RuntimeException("Listener can't be null");
-            }
-            if (!mListeners.containsKey(listener)) {
-                final Listener l = new Listener(listener);
-                mListeners.put(listener, l);
-                getITelephony().addListener(l);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#addListener", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void removeCallStateListener(CallStateListener listener) {
-        try {
-            final Listener l = mListeners.remove(listener);
-            if (l != null) {
-                // Make sure that no callbacks that are already in flight come.
-                l.clearQueue();
-                getITelephony().removeListener(l);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#removeListener", e);
-        }
-    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 8b80bfa..baacb74 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -21,8 +21,6 @@
 import android.telephony.CellInfo;
 import android.telephony.NeighboringCellInfo;
 
-import com.android.internal.telephony.ITelephonyListener;
-
 import java.util.List;
 
 import java.util.List;
@@ -438,47 +436,4 @@
      * @return true on success; false on any failure.
      */
     boolean setPreferredNetworkType(int networkType);
-
-    /**
-     * Put a call on hold.
-     */
-     void toggleHold();
-
-     /**
-      * Merge foreground and background calls.
-      */
-     void merge();
-
-     /**
-      * Swap foreground and background calls.
-      */
-     void swap();
-
-     /**
-      * Mute the phone.
-      */
-     void mute(boolean mute);
-
-    /**
-     * Start playing DTMF tone for the specified digit.
-     *
-     * @param digit the digit that corresponds with the desired tone.
-     * @param timedShortcode whether the specified digit should be played as a timed short code.
-     */
-     void playDtmfTone(char digit, boolean timedShortCode);
-
-     /**
-      * Stop playing DTMF tones.
-      */
-     void stopDtmfTone();
-
-     /**
-       * Register a callback.
-       */
-      void addListener(ITelephonyListener listener);
-
-      /**
-       * Unregister a callback.
-       */
-      void removeListener(ITelephonyListener listener);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl b/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl
deleted file mode 100644
index c226217..0000000
--- a/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-/**
- * Interface used to register a listener that gets more detailed call state information than
- * {@link android.telephony.PhoneStateListener}
- *
- * {@hide}
- */
-oneway interface ITelephonyListener {
-    void onUpdate(int callId, int state, String number);
-}
diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
index 189fa6a..2b14384 100644
--- a/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
+++ b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
@@ -15,8 +15,8 @@
 
 package com.android.onemedia;
 
-import android.media.session.SessionToken;
+import android.media.session.MediaSessionToken;
 
 interface IPlayerCallback {
-    void onSessionChanged(in SessionToken session);
+    void onSessionChanged(in MediaSessionToken session);
 }
\ No newline at end of file
diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
index 15ea25f..efdbe9a 100644
--- a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
+++ b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
@@ -15,14 +15,14 @@
 
 package com.android.onemedia;
 
-import android.media.session.SessionToken;
+import android.media.session.MediaSessionToken;
 import android.os.Bundle;
 
 import com.android.onemedia.IPlayerCallback;
 import com.android.onemedia.playback.IRequestCallback;
 
 interface IPlayerService {
-    SessionToken getSessionToken();
+    MediaSessionToken getSessionToken();
     void registerCallback(in IPlayerCallback cb);
     void unregisterCallback(in IPlayerCallback cb);
     void sendRequest(String action, in Bundle params, in IRequestCallback cb);
diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
index b9a6470..158f5e4 100644
--- a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
+++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
@@ -17,7 +17,7 @@
 
 
 import android.app.Activity;
-import android.media.session.MediaMetadata;
+import android.media.MediaMetadata;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.util.Log;
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
index e3f5c0c..9f7bb26 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerController.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
@@ -16,10 +16,10 @@
  */
 package com.android.onemedia;
 
-import android.media.session.SessionController;
-import android.media.session.MediaMetadata;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
 import android.media.session.RouteInfo;
-import android.media.session.SessionManager;
+import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 import android.media.session.TransportController;
 import android.os.Bundle;
@@ -40,7 +40,7 @@
     public static final int STATE_DISCONNECTED = 0;
     public static final int STATE_CONNECTED = 1;
 
-    protected SessionController mController;
+    protected MediaController mController;
     protected IPlayerService mBinder;
     protected TransportController mTransportControls;
 
@@ -49,7 +49,7 @@
     private Listener mListener;
     private TransportListener mTransportListener = new TransportListener();
     private SessionCallback mControllerCb;
-    private SessionManager mManager;
+    private MediaSessionManager mManager;
     private Handler mHandler = new Handler();
 
     private boolean mResumed;
@@ -62,7 +62,7 @@
             mServiceIntent = serviceIntent;
         }
         mControllerCb = new SessionCallback();
-        mManager = (SessionManager) context
+        mManager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
 
         mResumed = false;
@@ -155,7 +155,7 @@
             mBinder = IPlayerService.Stub.asInterface(service);
             Log.d(TAG, "service is " + service + " binder is " + mBinder);
             try {
-                mController = SessionController.fromToken(mBinder.getSessionToken());
+                mController = MediaController.fromToken(mBinder.getSessionToken());
             } catch (RemoteException e) {
                 Log.e(TAG, "Error getting session", e);
                 return;
@@ -176,7 +176,7 @@
         }
     };
 
-    private class SessionCallback extends SessionController.Callback {
+    private class SessionCallback extends MediaController.Callback {
         @Override
         public void onRouteChanged(RouteInfo route) {
             // TODO
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerService.java b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
index 8b53ddf..0ad6dd1 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerService.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
@@ -17,7 +17,7 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.media.session.SessionToken;
+import android.media.session.MediaSessionToken;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -149,7 +149,7 @@
         }
 
         @Override
-        public SessionToken getSessionToken() throws RemoteException {
+        public MediaSessionToken getSessionToken() throws RemoteException {
             return mSession.getSessionToken();
         }
     }
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index b7dcef7..94d0851 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -21,9 +21,9 @@
 import android.media.session.RouteInfo;
 import android.media.session.RouteOptions;
 import android.media.session.RoutePlaybackControls;
-import android.media.session.Session;
-import android.media.session.SessionManager;
-import android.media.session.SessionToken;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.media.session.MediaSessionToken;
 import android.media.session.PlaybackState;
 import android.media.session.TransportPerformer;
 import android.os.Bundle;
@@ -40,10 +40,10 @@
 public class PlayerSession {
     private static final String TAG = "PlayerSession";
 
-    protected Session mSession;
+    protected MediaSession mSession;
     protected Context mContext;
     protected Renderer mRenderer;
-    protected Session.Callback mCallback;
+    protected MediaSession.Callback mCallback;
     protected Renderer.Listener mRenderListener;
     protected TransportPerformer mPerformer;
 
@@ -79,7 +79,7 @@
         if (mSession != null) {
             mSession.release();
         }
-        SessionManager man = (SessionManager) mContext
+        MediaSessionManager man = (MediaSessionManager) mContext
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
         mSession = man.createSession("OneMedia");
@@ -87,7 +87,7 @@
         mPerformer = mSession.getTransportPerformer();
         mPerformer.addListener(new TransportListener());
         mPerformer.setPlaybackState(mPlaybackState);
-        mSession.setFlags(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
+        mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
         mSession.setRouteOptions(mRouteOptions);
         mSession.setActive(true);
     }
@@ -106,7 +106,7 @@
         mListener = listener;
     }
 
-    public SessionToken getSessionToken() {
+    public MediaSessionToken getSessionToken() {
         return mSession.getSessionToken();
     }
 
@@ -204,7 +204,7 @@
 
     }
 
-    private class SessionCb extends Session.Callback {
+    private class SessionCb extends MediaSession.Callback {
         @Override
         public void onMediaButton(Intent mediaRequestIntent) {
             if (Intent.ACTION_MEDIA_BUTTON.equals(mediaRequestIntent.getAction())) {