Merge "Don't allow to scroll to QS if not provisioned" into lmp-dev
diff --git a/Android.mk b/Android.mk
index b419231..80b860b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -329,12 +329,7 @@
 	media/java/android/media/projection/IMediaProjection.aidl \
 	media/java/android/media/projection/IMediaProjectionCallback.aidl \
 	media/java/android/media/projection/IMediaProjectionManager.aidl \
-	media/java/android/media/routing/IMediaRouteService.aidl \
-	media/java/android/media/routing/IMediaRouteClientCallback.aidl \
-	media/java/android/media/routing/IMediaRouter.aidl \
-	media/java/android/media/routing/IMediaRouterDelegate.aidl \
-	media/java/android/media/routing/IMediaRouterRoutingCallback.aidl \
-	media/java/android/media/routing/IMediaRouterStateCallback.aidl \
+	media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl \
 	media/java/android/media/session/IActiveSessionsListener.aidl \
 	media/java/android/media/session/ISessionController.aidl \
 	media/java/android/media/session/ISessionControllerCallback.aidl \
@@ -496,7 +491,6 @@
 	frameworks/base/location/java/com/android/internal/location/ProviderRequest.aidl \
 	frameworks/base/media/java/android/media/MediaMetadata.aidl \
 	frameworks/base/media/java/android/media/Rating.aidl \
-	frameworks/base/media/java/android/media/routing/MediaRouteSelector.aidl \
 	frameworks/base/media/java/android/media/session/MediaSession.aidl \
 	frameworks/base/media/java/android/media/session/PlaybackState.aidl \
 	frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
diff --git a/api/current.txt b/api/current.txt
index 7b7e876..516a2b6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23,7 +23,6 @@
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
-    field public static final java.lang.String BIND_MEDIA_ROUTE_SERVICE = "android.permission.BIND_MEDIA_ROUTE_SERVICE";
     field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
     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";
@@ -1037,7 +1036,6 @@
     field public static final int required = 16843406; // 0x101028e
     field public static final int requiredAccountType = 16843734; // 0x10103d6
     field public static final int requiredForAllUsers = 16843728; // 0x10103d0
-    field public static final int requiredForProfile = 16843816; // 0x1010428
     field public static final int requiresFadingEdge = 16843685; // 0x10103a5
     field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
     field public static final int resizeMode = 16843619; // 0x1010363
@@ -2048,6 +2046,8 @@
     field public static final int TextAppearance_Material_Widget_TextView = 16974381; // 0x103022d
     field public static final int TextAppearance_Material_Widget_TextView_PopupMenu = 16974382; // 0x103022e
     field public static final int TextAppearance_Material_Widget_TextView_SpinnerItem = 16974383; // 0x103022f
+    field public static final int TextAppearance_Material_Widget_Toolbar_Subtitle = 16974569; // 0x10302e9
+    field public static final int TextAppearance_Material_Widget_Toolbar_Title = 16974568; // 0x10302e8
     field public static final int TextAppearance_Material_WindowTitle = 16974361; // 0x1030219
     field public static final int TextAppearance_Medium = 16973892; // 0x1030044
     field public static final int TextAppearance_Medium_Inverse = 16973893; // 0x1030045
@@ -5370,7 +5370,8 @@
     method public java.lang.CharSequence onDisableRequested(android.content.Context, android.content.Intent);
     method public void onDisabled(android.content.Context, android.content.Intent);
     method public void onEnabled(android.content.Context, android.content.Intent);
-    method public void onLockTaskModeChanged(android.content.Context, android.content.Intent, boolean, java.lang.String);
+    method public void onLockTaskModeEntering(android.content.Context, android.content.Intent, java.lang.String);
+    method public void onLockTaskModeExiting(android.content.Context, android.content.Intent);
     method public void onPasswordChanged(android.content.Context, android.content.Intent);
     method public void onPasswordExpiring(android.content.Context, android.content.Intent);
     method public void onPasswordFailed(android.content.Context, android.content.Intent);
@@ -5380,7 +5381,8 @@
     field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
     field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
     field public static final java.lang.String ACTION_DEVICE_ADMIN_ENABLED = "android.app.action.DEVICE_ADMIN_ENABLED";
-    field public static final java.lang.String ACTION_LOCK_TASK_CHANGED = "android.app.action.ACTION_LOCK_TASK_CHANGED";
+    field public static final java.lang.String ACTION_LOCK_TASK_ENTERING = "android.app.action.ACTION_LOCK_TASK_ENTERING";
+    field public static final java.lang.String ACTION_LOCK_TASK_EXITING = "android.app.action.ACTION_LOCK_TASK_EXITING";
     field public static final java.lang.String ACTION_PASSWORD_CHANGED = "android.app.action.ACTION_PASSWORD_CHANGED";
     field public static final java.lang.String ACTION_PASSWORD_EXPIRING = "android.app.action.ACTION_PASSWORD_EXPIRING";
     field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
@@ -5388,7 +5390,6 @@
     field public static final java.lang.String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.ACTION_PROFILE_PROVISIONING_COMPLETE";
     field public static final java.lang.String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
     field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
-    field public static final java.lang.String EXTRA_LOCK_TASK_ENTERING = "android.app.extra.LOCK_TASK_ENTERING";
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
   }
 
@@ -5457,7 +5458,7 @@
     method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
-    method public void setLockTaskPackages(java.lang.String[]) throws java.lang.SecurityException;
+    method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -8595,19 +8596,26 @@
   }
 
   public class LauncherApps {
+    method public void addCallback(android.content.pm.LauncherApps.Callback);
+    method public void addCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
     method public void addOnAppsChangedCallback(android.content.pm.LauncherApps.OnAppsChangedCallback);
     method public void addOnAppsChangedCallback(android.content.pm.LauncherApps.OnAppsChangedCallback, android.os.Handler);
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
+    method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
     method public boolean isActivityEnabledForProfile(android.content.ComponentName, android.os.UserHandle);
+    method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
     method public boolean isPackageEnabledForProfile(java.lang.String, android.os.UserHandle);
+    method public void removeCallback(android.content.pm.LauncherApps.Callback);
     method public void removeOnAppsChangedCallback(android.content.pm.LauncherApps.OnAppsChangedCallback);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
     method public void showAppDetailsForProfile(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startActivityForProfile(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+    method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+    method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
   }
 
-  public static abstract class LauncherApps.OnAppsChangedCallback {
-    ctor public LauncherApps.OnAppsChangedCallback();
+  public static abstract class LauncherApps.Callback {
+    ctor public LauncherApps.Callback();
     method public abstract void onPackageAdded(java.lang.String, android.os.UserHandle);
     method public abstract void onPackageChanged(java.lang.String, android.os.UserHandle);
     method public abstract void onPackageRemoved(java.lang.String, android.os.UserHandle);
@@ -8615,6 +8623,10 @@
     method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
   }
 
+  public static abstract class LauncherApps.OnAppsChangedCallback extends android.content.pm.LauncherApps.Callback {
+    ctor public LauncherApps.OnAppsChangedCallback();
+  }
+
   public class PackageInfo implements android.os.Parcelable {
     ctor public PackageInfo();
     method public int describeContents();
@@ -8666,14 +8678,14 @@
     field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
     field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
     field public static final int STATUS_FAILURE = 1; // 0x1
-    field public static final int STATUS_FAILURE_ABORTED = 2; // 0x2
-    field public static final int STATUS_FAILURE_BLOCKED = 1; // 0x1
-    field public static final int STATUS_FAILURE_CONFLICT = 4; // 0x4
-    field public static final int STATUS_FAILURE_INCOMPATIBLE = 6; // 0x6
-    field public static final int STATUS_FAILURE_INVALID = 3; // 0x3
-    field public static final int STATUS_FAILURE_STORAGE = 5; // 0x5
+    field public static final int STATUS_FAILURE_ABORTED = 3; // 0x3
+    field public static final int STATUS_FAILURE_BLOCKED = 2; // 0x2
+    field public static final int STATUS_FAILURE_CONFLICT = 5; // 0x5
+    field public static final int STATUS_FAILURE_INCOMPATIBLE = 7; // 0x7
+    field public static final int STATUS_FAILURE_INVALID = 4; // 0x4
+    field public static final int STATUS_FAILURE_STORAGE = 6; // 0x6
+    field public static final int STATUS_PENDING_USER_ACTION = -1; // 0xffffffff
     field public static final int STATUS_SUCCESS = 0; // 0x0
-    field public static final int STATUS_USER_ACTION_REQUIRED = -1; // 0xffffffff
   }
 
   public static class PackageInstaller.Session implements java.io.Closeable {
@@ -8681,7 +8693,7 @@
     method public void close();
     method public void commit(android.content.IntentSender);
     method public void fsync(java.io.OutputStream) throws java.io.IOException;
-    method public java.lang.String[] getNames();
+    method public java.lang.String[] getNames() throws java.io.IOException;
     method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
     method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
     method public void setProgress(float);
@@ -13304,85 +13316,6 @@
 
 }
 
-package android.hardware.location {
-
-  public final class GeofenceHardware {
-    method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
-    method public int[] getMonitoringTypes();
-    method public int getStatusOfMonitoringType(int);
-    method public boolean pauseGeofence(int, int);
-    method public boolean registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
-    method public boolean removeGeofence(int, int);
-    method public boolean resumeGeofence(int, int, int);
-    method public boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
-    field public static final int GEOFENCE_ENTERED = 1; // 0x1
-    field public static final int GEOFENCE_ERROR_ID_EXISTS = 2; // 0x2
-    field public static final int GEOFENCE_ERROR_ID_UNKNOWN = 3; // 0x3
-    field public static final int GEOFENCE_ERROR_INSUFFICIENT_MEMORY = 6; // 0x6
-    field public static final int GEOFENCE_ERROR_INVALID_TRANSITION = 4; // 0x4
-    field public static final int GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 1; // 0x1
-    field public static final int GEOFENCE_EXITED = 2; // 0x2
-    field public static final int GEOFENCE_FAILURE = 5; // 0x5
-    field public static final int GEOFENCE_SUCCESS = 0; // 0x0
-    field public static final int GEOFENCE_UNCERTAIN = 4; // 0x4
-    field public static final int MONITORING_TYPE_FUSED_HARDWARE = 1; // 0x1
-    field public static final int MONITORING_TYPE_GPS_HARDWARE = 0; // 0x0
-    field public static final int MONITOR_CURRENTLY_AVAILABLE = 0; // 0x0
-    field public static final int MONITOR_CURRENTLY_UNAVAILABLE = 1; // 0x1
-    field public static final int MONITOR_UNSUPPORTED = 2; // 0x2
-    field public static final int SOURCE_TECHNOLOGY_BLUETOOTH = 16; // 0x10
-    field public static final int SOURCE_TECHNOLOGY_CELL = 8; // 0x8
-    field public static final int SOURCE_TECHNOLOGY_GNSS = 1; // 0x1
-    field public static final int SOURCE_TECHNOLOGY_SENSORS = 4; // 0x4
-    field public static final int SOURCE_TECHNOLOGY_WIFI = 2; // 0x2
-  }
-
-  public abstract class GeofenceHardwareCallback {
-    ctor public GeofenceHardwareCallback();
-    method public void onGeofenceAdd(int, int);
-    method public void onGeofencePause(int, int);
-    method public void onGeofenceRemove(int, int);
-    method public void onGeofenceResume(int, int);
-    method public void onGeofenceTransition(int, int, android.location.Location, long, int);
-  }
-
-  public abstract class GeofenceHardwareMonitorCallback {
-    ctor public GeofenceHardwareMonitorCallback();
-    method public deprecated void onMonitoringSystemChange(int, boolean, android.location.Location);
-    method public void onMonitoringSystemChange(android.hardware.location.GeofenceHardwareMonitorEvent);
-  }
-
-  public class GeofenceHardwareMonitorEvent implements android.os.Parcelable {
-    ctor public GeofenceHardwareMonitorEvent(int, int, int, android.location.Location);
-    method public int describeContents();
-    method public android.location.Location getLocation();
-    method public int getMonitoringStatus();
-    method public int getMonitoringType();
-    method public int getSourceTechnologies();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public final class GeofenceHardwareRequest {
-    ctor public GeofenceHardwareRequest();
-    method public static android.hardware.location.GeofenceHardwareRequest createCircularGeofence(double, double, double);
-    method public int getLastTransition();
-    method public double getLatitude();
-    method public double getLongitude();
-    method public int getMonitorTransitions();
-    method public int getNotificationResponsiveness();
-    method public double getRadius();
-    method public int getSourceTechnologies();
-    method public int getUnknownTimer();
-    method public void setLastTransition(int);
-    method public void setMonitorTransitions(int);
-    method public void setNotificationResponsiveness(int);
-    method public void setSourceTechnologies(int);
-    method public void setUnknownTimer(int);
-  }
-
-}
-
 package android.hardware.usb {
 
   public class UsbAccessory implements android.os.Parcelable {
@@ -16446,242 +16379,6 @@
 
 }
 
-package android.media.routing {
-
-  public final class MediaRouteSelector implements android.os.Parcelable {
-    method public boolean containsProtocol(java.lang.Class<?>);
-    method public boolean containsProtocol(java.lang.String);
-    method public int describeContents();
-    method public android.os.Bundle getExtras();
-    method public int getOptionalFeatures();
-    method public java.util.List<java.lang.String> getOptionalProtocols();
-    method public int getRequiredFeatures();
-    method public java.util.List<java.lang.String> getRequiredProtocols();
-    method public java.lang.String getServicePackageName();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public static final class MediaRouteSelector.Builder {
-    ctor public MediaRouteSelector.Builder();
-    method public android.media.routing.MediaRouteSelector.Builder addOptionalProtocol(java.lang.Class<?>);
-    method public android.media.routing.MediaRouteSelector.Builder addOptionalProtocol(java.lang.String);
-    method public android.media.routing.MediaRouteSelector.Builder addRequiredProtocol(java.lang.Class<?>);
-    method public android.media.routing.MediaRouteSelector.Builder addRequiredProtocol(java.lang.String);
-    method public android.media.routing.MediaRouteSelector build();
-    method public android.media.routing.MediaRouteSelector.Builder setExtras(android.os.Bundle);
-    method public android.media.routing.MediaRouteSelector.Builder setOptionalFeatures(int);
-    method public android.media.routing.MediaRouteSelector.Builder setRequiredFeatures(int);
-    method public android.media.routing.MediaRouteSelector.Builder setServicePackageName(java.lang.String);
-  }
-
-  public abstract class MediaRouteService extends android.app.Service {
-    ctor public MediaRouteService();
-    method public android.media.routing.MediaRouter.ServiceMetadata getServiceMetadata();
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.media.routing.MediaRouteService.ClientSession onCreateClientSession(android.media.routing.MediaRouteService.ClientInfo);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.media.routing.MediaRouteService";
-  }
-
-  public static final class MediaRouteService.ClientInfo {
-    method public java.lang.String getPackageName();
-    method public int getUid();
-  }
-
-  public static abstract class MediaRouteService.ClientSession {
-    ctor public MediaRouteService.ClientSession();
-    method public abstract boolean onConnect(android.media.routing.MediaRouter.ConnectionRequest, android.media.routing.MediaRouteService.ConnectionCallback);
-    method public abstract void onDisconnect();
-    method public void onPauseStream();
-    method public void onRelease();
-    method public void onResumeStream();
-    method public abstract boolean onStartDiscovery(android.media.routing.MediaRouter.DiscoveryRequest, android.media.routing.MediaRouteService.DiscoveryCallback);
-    method public abstract void onStopDiscovery();
-  }
-
-  public final class MediaRouteService.ConnectionCallback {
-    method public void onConnected(android.media.routing.MediaRouter.ConnectionInfo);
-    method public void onConnectionFailed(int, java.lang.CharSequence, android.os.Bundle);
-    method public void onDisconnected();
-  }
-
-  public final class MediaRouteService.DiscoveryCallback {
-    method public void onDestinationFound(android.media.routing.MediaRouter.DestinationInfo, java.util.List<android.media.routing.MediaRouter.RouteInfo>);
-    method public void onDestinationLost(android.media.routing.MediaRouter.DestinationInfo);
-    method public void onDiscoveryFailed(int, java.lang.CharSequence, android.os.Bundle);
-  }
-
-  public final class MediaRouter {
-    ctor public MediaRouter(android.content.Context);
-    method public void addSelector(android.media.routing.MediaRouteSelector);
-    method public void clearSelectors();
-    method public android.media.routing.MediaRouter.Delegate createDelegate();
-    method public android.media.routing.MediaRouter.ConnectionInfo getConnection();
-    method public int getConnectionState();
-    method public java.util.List<android.media.routing.MediaRouter.DestinationInfo> getDiscoveredDestinations();
-    method public java.util.List<android.media.routing.MediaRouter.RouteInfo> getDiscoveredRoutes(android.media.routing.MediaRouter.DestinationInfo);
-    method public int getDiscoveryState();
-    method public android.media.AudioAttributes getPreferredAudioAttributes();
-    method public android.view.Display getPreferredPresentationDisplay();
-    method public android.media.VolumeProvider getPreferredVolumeProvider();
-    method public android.media.routing.MediaRouter.DestinationInfo getSelectedDestination();
-    method public android.media.routing.MediaRouter.RouteInfo getSelectedRoute();
-    method public java.util.List<android.media.routing.MediaRouteSelector> getSelectors();
-    method public boolean isReleased();
-    method public void pauseStream();
-    method public void release();
-    method public void removeSelector(android.media.routing.MediaRouteSelector);
-    method public void resumeStream();
-    method public void setRoutingCallback(android.media.routing.MediaRouter.RoutingCallback, android.os.Handler);
-    field public static final int CONNECTION_ERROR_ABORTED = 1; // 0x1
-    field public static final int CONNECTION_ERROR_BARGED = 7; // 0x7
-    field public static final int CONNECTION_ERROR_BROKEN = 6; // 0x6
-    field public static final int CONNECTION_ERROR_BUSY = 4; // 0x4
-    field public static final int CONNECTION_ERROR_TIMEOUT = 5; // 0x5
-    field public static final int CONNECTION_ERROR_UNAUTHORIZED = 2; // 0x2
-    field public static final int CONNECTION_ERROR_UNKNOWN = 0; // 0x0
-    field public static final int CONNECTION_ERROR_UNREACHABLE = 3; // 0x3
-    field public static final int CONNECTION_FLAG_BARGE = 1; // 0x1
-    field public static final int CONNECTION_STATE_CONNECTED = 2; // 0x2
-    field public static final int CONNECTION_STATE_CONNECTING = 1; // 0x1
-    field public static final int CONNECTION_STATE_DISCONNECTED = 0; // 0x0
-    field public static final int DISCONNECTION_REASON_APPLICATION_REQUEST = 0; // 0x0
-    field public static final int DISCONNECTION_REASON_ERROR = 2; // 0x2
-    field public static final int DISCONNECTION_REASON_USER_REQUEST = 1; // 0x1
-    field public static final int DISCOVERY_ERROR_ABORTED = 1; // 0x1
-    field public static final int DISCOVERY_ERROR_NO_CONNECTIVITY = 2; // 0x2
-    field public static final int DISCOVERY_ERROR_UNKNOWN = 0; // 0x0
-    field public static final int DISCOVERY_FLAG_BACKGROUND = 1; // 0x1
-    field public static final int DISCOVERY_STATE_STARTED = 1; // 0x1
-    field public static final int DISCOVERY_STATE_STOPPED = 0; // 0x0
-    field public static final int ROUTE_FEATURE_LIVE_AUDIO = 1; // 0x1
-    field public static final int ROUTE_FEATURE_LIVE_VIDEO = 2; // 0x2
-  }
-
-  public static final class MediaRouter.ConnectionInfo {
-    method public android.media.AudioAttributes getAudioAttributes();
-    method public android.os.Bundle getExtras();
-    method public int getFeatures();
-    method public android.view.Display getPresentationDisplay();
-    method public android.os.IBinder getProtocolBinder(java.lang.String);
-    method public android.os.IBinder getProtocolBinder(int);
-    method public T getProtocolObject(java.lang.Class<T>);
-    method public java.util.List<java.lang.String> getProtocols();
-    method public android.media.routing.MediaRouter.RouteInfo getRoute();
-    method public android.media.VolumeProvider getVolumeProvider();
-  }
-
-  public static final class MediaRouter.ConnectionInfo.Builder {
-    ctor public MediaRouter.ConnectionInfo.Builder(android.media.routing.MediaRouter.RouteInfo);
-    method public android.media.routing.MediaRouter.ConnectionInfo build();
-    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setAudioAttributes(android.media.AudioAttributes);
-    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setExtras(android.os.Bundle);
-    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setPresentationDisplay(android.view.Display);
-    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setProtocolBinder(java.lang.String, android.os.IBinder);
-    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setProtocolStub(java.lang.Class<?>, android.os.IInterface);
-    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setVolumeProvider(android.media.VolumeProvider);
-  }
-
-  public static final class MediaRouter.ConnectionRequest {
-    method public android.os.Bundle getExtras();
-    method public int getFlags();
-    method public android.media.routing.MediaRouter.RouteInfo getRoute();
-    method public void setExtras(android.os.Bundle);
-    method public void setFlags(int);
-    method public void setRoute(android.media.routing.MediaRouter.RouteInfo);
-  }
-
-  public static final class MediaRouter.Delegate {
-    ctor public MediaRouter.Delegate();
-    method public void addStateCallback(android.media.routing.MediaRouter.StateCallback, android.os.Handler);
-    method public void connect(android.media.routing.MediaRouter.DestinationInfo, int);
-    method public void disconnect(int);
-    method public int getConnectionState();
-    method public java.util.List<android.media.routing.MediaRouter.DestinationInfo> getDiscoveredDestinations();
-    method public int getDiscoveryState();
-    method public android.media.routing.MediaRouter.DestinationInfo getSelectedDestination();
-    method public boolean isReleased();
-    method public void removeStateCallback(android.media.routing.MediaRouter.StateCallback);
-    method public void startDiscovery(int);
-    method public void stopDiscovery();
-  }
-
-  public static final class MediaRouter.DestinationInfo {
-    method public java.lang.CharSequence getDescription();
-    method public android.os.Bundle getExtras();
-    method public int getIconResourceId();
-    method public java.lang.String getId();
-    method public java.lang.CharSequence getName();
-    method public android.media.routing.MediaRouter.ServiceMetadata getServiceMetadata();
-    method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
-  }
-
-  public static final class MediaRouter.DestinationInfo.Builder {
-    ctor public MediaRouter.DestinationInfo.Builder(java.lang.String, android.media.routing.MediaRouter.ServiceMetadata, java.lang.CharSequence);
-    method public android.media.routing.MediaRouter.DestinationInfo build();
-    method public android.media.routing.MediaRouter.DestinationInfo.Builder setDescription(java.lang.CharSequence);
-    method public android.media.routing.MediaRouter.DestinationInfo.Builder setExtras(android.os.Bundle);
-    method public android.media.routing.MediaRouter.DestinationInfo.Builder setIconResourceId(int);
-  }
-
-  public static final class MediaRouter.DiscoveryRequest {
-    method public int getFlags();
-    method public java.util.List<android.media.routing.MediaRouteSelector> getSelectors();
-    method public void setFlags(int);
-    method public void setSelectors(java.util.List<android.media.routing.MediaRouteSelector>);
-  }
-
-  public static final class MediaRouter.RouteInfo {
-    method public android.media.routing.MediaRouter.DestinationInfo getDestination();
-    method public android.os.Bundle getExtras();
-    method public int getFeatures();
-    method public java.lang.String getId();
-    method public java.util.List<java.lang.String> getProtocols();
-    method public android.media.routing.MediaRouteSelector getSelector();
-  }
-
-  public static final class MediaRouter.RouteInfo.Builder {
-    ctor public MediaRouter.RouteInfo.Builder(java.lang.String, android.media.routing.MediaRouter.DestinationInfo, android.media.routing.MediaRouteSelector);
-    method public android.media.routing.MediaRouter.RouteInfo.Builder addProtocol(java.lang.Class<T>);
-    method public android.media.routing.MediaRouter.RouteInfo.Builder addProtocol(java.lang.String);
-    method public android.media.routing.MediaRouter.RouteInfo build();
-    method public android.media.routing.MediaRouter.RouteInfo.Builder setExtras(android.os.Bundle);
-    method public android.media.routing.MediaRouter.RouteInfo.Builder setFeatures(int);
-  }
-
-  public static abstract class MediaRouter.RoutingCallback extends android.media.routing.MediaRouter.StateCallback {
-    ctor public MediaRouter.RoutingCallback();
-    method public boolean onPrepareConnectionRequest(android.media.routing.MediaRouter.ConnectionRequest, android.media.routing.MediaRouter.DestinationInfo, java.util.List<android.media.routing.MediaRouter.RouteInfo>);
-    method public boolean onPrepareDiscoveryRequest(android.media.routing.MediaRouter.DiscoveryRequest, java.util.List<android.media.routing.MediaRouteSelector>);
-  }
-
-  public static final class MediaRouter.ServiceMetadata {
-    method public android.content.ComponentName getComponentName();
-    method public android.graphics.drawable.Drawable getIcon(android.content.pm.PackageManager);
-    method public java.lang.CharSequence getLabel(android.content.pm.PackageManager);
-    method public java.lang.String getPackageName();
-    method public android.content.pm.ServiceInfo getService();
-  }
-
-  public static abstract class MediaRouter.StateCallback {
-    ctor public MediaRouter.StateCallback();
-    method public void onConnected();
-    method public void onConnecting();
-    method public void onConnectionFailed(int, java.lang.CharSequence, android.os.Bundle);
-    method public void onConnectionStateChanged(int);
-    method public void onDestinationFound(android.media.routing.MediaRouter.DestinationInfo);
-    method public void onDestinationLost(android.media.routing.MediaRouter.DestinationInfo);
-    method public void onDisconnected();
-    method public void onDiscoveryFailed(int, java.lang.CharSequence, android.os.Bundle);
-    method public void onDiscoveryStarted();
-    method public void onDiscoveryStateChanged(int);
-    method public void onDiscoveryStopped();
-    method public void onReleased();
-    method public void onSelectedDestinationChanged(android.media.routing.MediaRouter.DestinationInfo);
-  }
-
-}
-
 package android.media.session {
 
   public final class MediaController {
@@ -16689,35 +16386,42 @@
     method public void addCallback(android.media.session.MediaController.Callback);
     method public void addCallback(android.media.session.MediaController.Callback, android.os.Handler);
     method public void adjustVolume(int, int);
-    method public android.media.routing.MediaRouter.Delegate createMediaRouterDelegate();
     method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
+    method public android.media.session.MediaController.AudioInfo getAudioInfo();
     method public android.os.Bundle getExtras();
     method public long getFlags();
     method public android.app.PendingIntent getLaunchActivity();
     method public android.media.MediaMetadata getMetadata();
     method public java.lang.String getPackageName();
     method public android.media.session.PlaybackState getPlaybackState();
-    method public java.util.List<android.media.session.MediaSession.Track> getQueue();
+    method public java.util.List<android.media.session.MediaSession.Item> getQueue();
     method public java.lang.CharSequence getQueueTitle();
     method public int getRatingType();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public android.media.session.MediaController.TransportControls getTransportControls();
-    method public android.media.session.MediaController.VolumeInfo getVolumeInfo();
     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 setVolumeTo(int, int);
   }
 
+  public static final class MediaController.AudioInfo {
+    method public android.media.AudioAttributes getAudioAttributes();
+    method public int getCurrentVolume();
+    method public int getMaxVolume();
+    method public int getVolumeControl();
+    method public int getVolumeType();
+  }
+
   public static abstract class MediaController.Callback {
     ctor public MediaController.Callback();
+    method public void onAudioInfoChanged(android.media.session.MediaController.AudioInfo);
     method public void onExtrasChanged(android.os.Bundle);
     method public void onMetadataChanged(android.media.MediaMetadata);
     method public void onPlaybackStateChanged(android.media.session.PlaybackState);
-    method public void onQueueChanged(java.util.List<android.media.session.MediaSession.Track>);
+    method public void onQueueChanged(java.util.List<android.media.session.MediaSession.Item>);
     method public void onQueueTitleChanged(java.lang.CharSequence);
     method public void onSessionDestroyed();
     method public void onSessionEvent(java.lang.String, android.os.Bundle);
-    method public void onVolumeInfoChanged(android.media.session.MediaController.VolumeInfo);
   }
 
   public final class MediaController.TransportControls {
@@ -16731,20 +16435,12 @@
     method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
     method public void sendCustomAction(java.lang.String, android.os.Bundle);
     method public void setRating(android.media.Rating);
+    method public void skipToItem(long);
     method public void skipToNext();
     method public void skipToPrevious();
-    method public void skipToTrack(long);
     method public void stop();
   }
 
-  public static final class MediaController.VolumeInfo {
-    method public android.media.AudioAttributes getAudioAttributes();
-    method public int getCurrentVolume();
-    method public int getMaxVolume();
-    method public int getVolumeControl();
-    method public int getVolumeType();
-  }
-
   public final class MediaSession {
     ctor public MediaSession(android.content.Context, java.lang.String);
     method public android.media.session.MediaController getController();
@@ -16759,12 +16455,11 @@
     method public void setFlags(int);
     method public void setLaunchActivity(android.app.PendingIntent);
     method public void setMediaButtonReceiver(android.app.PendingIntent);
-    method public void setMediaRouter(android.media.routing.MediaRouter);
     method public void setMetadata(android.media.MediaMetadata);
     method public void setPlaybackState(android.media.session.PlaybackState);
     method public void setPlaybackToLocal(android.media.AudioAttributes);
     method public void setPlaybackToRemote(android.media.VolumeProvider);
-    method public void setQueue(java.util.List<android.media.session.MediaSession.Track>);
+    method public void setQueue(java.util.List<android.media.session.MediaSession.Item>);
     method public void setQueueTitle(java.lang.CharSequence);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
@@ -16785,19 +16480,13 @@
     method public void onRewind();
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
+    method public void onSkipToItem(long);
     method public void onSkipToNext();
     method public void onSkipToPrevious();
-    method public void onSkipToTrack(long);
     method public void onStop();
   }
 
-  public static final class MediaSession.Token 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 static final class MediaSession.Track implements android.os.Parcelable {
+  public static final class MediaSession.Item implements android.os.Parcelable {
     method public int describeContents();
     method public android.os.Bundle getExtras();
     method public long getId();
@@ -16808,20 +16497,25 @@
     field public static final int UNKNOWN_ID = -1; // 0xffffffff
   }
 
-  public static final class MediaSession.Track.Builder {
-    ctor public MediaSession.Track.Builder(android.media.MediaMetadata, long, android.net.Uri);
-    method public android.media.session.MediaSession.Track build();
-    method public android.media.session.MediaSession.Track.Builder setExtras(android.os.Bundle);
+  public static final class MediaSession.Item.Builder {
+    ctor public MediaSession.Item.Builder(android.media.MediaMetadata, long, android.net.Uri);
+    method public android.media.session.MediaSession.Item build();
+    method public android.media.session.MediaSession.Item.Builder setExtras(android.os.Bundle);
+  }
+
+  public static final class MediaSession.Token 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 MediaSessionManager {
-    method public void addActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener, android.content.ComponentName);
+    method public void addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName);
     method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName);
-    method public void removeActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener);
+    method public void removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
   }
 
-  public static abstract class MediaSessionManager.SessionListener {
-    ctor public MediaSessionManager.SessionListener(android.content.Context);
+  public static abstract interface MediaSessionManager.OnActiveSessionsChangedListener {
     method public abstract void onActiveSessionsChanged(java.util.List<android.media.session.MediaController>);
   }
 
@@ -16845,9 +16539,9 @@
     field public static final long ACTION_REWIND = 8L; // 0x8L
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
     field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SKIP_TO_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
     field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
-    field public static final long ACTION_SKIP_TO_TRACK = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
@@ -16871,7 +16565,7 @@
     method public android.media.session.PlaybackState.Builder addCustomAction(android.media.session.PlaybackState.CustomAction);
     method public android.media.session.PlaybackState build();
     method public android.media.session.PlaybackState.Builder setActions(long);
-    method public android.media.session.PlaybackState.Builder setActiveTrack(long);
+    method public android.media.session.PlaybackState.Builder setActiveItem(long);
     method public android.media.session.PlaybackState.Builder setBufferPosition(long);
     method public android.media.session.PlaybackState.Builder setErrorMessage(java.lang.CharSequence);
     method public android.media.session.PlaybackState.Builder setState(int, long, float, long);
@@ -17139,6 +16833,7 @@
     method public final java.lang.String getId();
     method public final java.lang.String getLanguage();
     method public final int getType();
+    method public final float getVideoFrameRate();
     method public final int getVideoHeight();
     method public final int getVideoWidth();
     method public void writeToParcel(android.os.Parcel, int);
@@ -17155,6 +16850,7 @@
     method public final android.media.tv.TvTrackInfo.Builder setAudioSampleRate(int);
     method public final android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
     method public final android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String);
+    method public final android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float);
     method public final android.media.tv.TvTrackInfo.Builder setVideoHeight(int);
     method public final android.media.tv.TvTrackInfo.Builder setVideoWidth(int);
   }
@@ -17175,8 +16871,6 @@
     method public void setStreamVolume(float);
     method public void setTvInputListener(android.media.tv.TvView.TvInputListener);
     method public void tune(java.lang.String, android.net.Uri);
-    field public static final int ERROR_INPUT_DISCONNECTED = 1; // 0x1
-    field public static final int ERROR_INPUT_NOT_CONNECTED = 0; // 0x0
   }
 
   public static abstract interface TvView.OnUnhandledInputEventListener {
@@ -17186,9 +16880,10 @@
   public static abstract class TvView.TvInputListener {
     ctor public TvView.TvInputListener();
     method public void onChannelRetuned(java.lang.String, android.net.Uri);
+    method public void onConnectionFailed(java.lang.String);
     method public void onContentAllowed(java.lang.String);
     method public void onContentBlocked(java.lang.String, android.media.tv.TvContentRating);
-    method public void onError(java.lang.String, int);
+    method public void onDisconnected(java.lang.String);
     method public void onTrackSelected(java.lang.String, int, java.lang.String);
     method public void onTracksChanged(java.lang.String, java.util.List<android.media.tv.TvTrackInfo>);
     method public void onVideoAvailable(java.lang.String);
@@ -28812,6 +28507,8 @@
 package android.telecomm {
 
   public final class AudioState implements android.os.Parcelable {
+    ctor public AudioState(boolean, int, int);
+    ctor public AudioState(android.telecomm.AudioState);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
@@ -28837,6 +28534,25 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public abstract class Conference {
+    ctor public Conference(android.telecomm.PhoneAccountHandle);
+    method public boolean addConnection(android.telecomm.Connection);
+    method public void destroy();
+    method public final int getCapabilities();
+    method public final java.util.List<android.telecomm.Connection> getConnections();
+    method public final android.telecomm.PhoneAccountHandle getPhoneAccount();
+    method public final int getState();
+    method public void onDisconnect();
+    method public void onHold();
+    method public void onSeparate(android.telecomm.Connection);
+    method public void onUnhold();
+    method public void removeConnection(android.telecomm.Connection);
+    method public final void setActive();
+    method public final void setCapabilities(int);
+    method public final void setDisconnected(int, java.lang.String);
+    method public final void setOnHold();
+  }
+
   public abstract class Connection {
     ctor public Connection();
     method public static android.telecomm.Connection createCanceledConnection();
@@ -28847,22 +28563,19 @@
     method public final int getCallCapabilities();
     method public final java.lang.String getCallerDisplayName();
     method public final int getCallerDisplayNamePresentation();
-    method public final java.util.List<android.telecomm.Connection> getChildConnections();
+    method public final android.telecomm.Conference getConference();
     method public final java.util.List<android.telecomm.Connection> getConferenceableConnections();
     method public final int getFailureCode();
     method public final java.lang.String getFailureMessage();
     method public final android.net.Uri getHandle();
     method public final int getHandlePresentation();
-    method public final android.telecomm.Connection getParentConnection();
     method public final int getState();
     method public final android.telecomm.StatusHints getStatusHints();
     method public final android.telecomm.Connection.VideoProvider getVideoProvider();
     method public final int getVideoState();
-    method public final boolean isConferenceConnection();
     method public final boolean isRequestingRingback();
     method public void onAbort();
     method public void onAnswer(int);
-    method public void onChildrenChanged(java.util.List<android.telecomm.Connection>);
     method public void onConferenceWith(android.telecomm.Connection);
     method public void onDisconnect();
     method public void onHold();
@@ -28879,16 +28592,14 @@
     method public final void setAudioModeIsVoip(boolean);
     method public final void setCallCapabilities(int);
     method public final void setCallerDisplayName(java.lang.String, int);
-    method public final void setCanceled();
     method public final void setConferenceableConnections(java.util.List<android.telecomm.Connection>);
+    method public final void setConnectionService(android.telecomm.ConnectionService);
     method public final void setDialing();
     method public final void setDisconnected(int, java.lang.String);
-    method public final void setFailed(int, java.lang.String);
     method public final void setHandle(android.net.Uri, int);
     method public final void setInitialized();
     method public final void setInitializing();
     method public final void setOnHold();
-    method public final void setParentConnection(android.telecomm.Connection);
     method public final void setPostDialWait(java.lang.String);
     method public final void setRequestingRingback(boolean);
     method public final void setRinging();
@@ -28898,10 +28609,8 @@
     method public final void startActivityFromInCall(android.app.PendingIntent);
     method public static java.lang.String stateToString(int);
     field public static final int STATE_ACTIVE = 4; // 0x4
-    field public static final int STATE_CANCELED = 8; // 0x8
     field public static final int STATE_DIALING = 3; // 0x3
     field public static final int STATE_DISCONNECTED = 6; // 0x6
-    field public static final int STATE_FAILED = 7; // 0x7
     field public static final int STATE_HOLDING = 5; // 0x5
     field public static final int STATE_INITIALIZING = 0; // 0x0
     field public static final int STATE_NEW = 1; // 0x1
@@ -28951,13 +28660,14 @@
 
   public abstract class ConnectionService extends android.app.Service {
     ctor public ConnectionService();
+    method public final void addConference(android.telecomm.Conference);
     method public final android.telecomm.RemoteConnection createRemoteIncomingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
     method public final android.telecomm.RemoteConnection createRemoteOutgoingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
     method public final java.util.Collection<android.telecomm.Connection> getAllConnections();
     method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onConference(android.telecomm.Connection, android.telecomm.Connection);
     method public void onConnectionAdded(android.telecomm.Connection);
     method public void onConnectionRemoved(android.telecomm.Connection);
-    method public void onCreateConferenceConnection(java.lang.String, android.telecomm.Connection, android.telecomm.Response<java.lang.String, android.telecomm.Connection>);
     method public android.telecomm.Connection onCreateIncomingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
     method public android.telecomm.Connection onCreateOutgoingConnection(android.telecomm.PhoneAccountHandle, android.telecomm.ConnectionRequest);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecomm.ConnectionService";
@@ -29690,6 +29400,7 @@
     method public int hasCarrierPrivileges();
     method public boolean hasIccCard();
     method public boolean iccCloseLogicalChannel(int);
+    method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
     method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
     method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
@@ -32291,6 +32002,8 @@
     method public void captureEndValues(android.transition.TransitionValues);
     method public void captureStartValues(android.transition.TransitionValues);
     method public int getOrdering();
+    method public android.transition.Transition getTransitionAt(int);
+    method public int getTransitionCount();
     method public android.transition.TransitionSet removeTransition(android.transition.Transition);
     method public android.transition.TransitionSet setOrdering(int);
     field public static final int ORDERING_SEQUENTIAL = 1; // 0x1
diff --git a/cmds/appops/Android.mk b/cmds/appops/Android.mk
new file mode 100644
index 0000000..1e15204
--- /dev/null
+++ b/cmds/appops/Android.mk
@@ -0,0 +1,16 @@
+# Copyright 2014 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := appops
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := appops
+LOCAL_SRC_FILES := appops
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
+
diff --git a/cmds/appops/MODULE_LICENSE_APACHE2 b/cmds/appops/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/appops/MODULE_LICENSE_APACHE2
diff --git a/cmds/appops/NOTICE b/cmds/appops/NOTICE
new file mode 100644
index 0000000..06a9081
--- /dev/null
+++ b/cmds/appops/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/cmds/appops/appops b/cmds/appops/appops
new file mode 100755
index 0000000..407e551
--- /dev/null
+++ b/cmds/appops/appops
@@ -0,0 +1,5 @@
+# Script to start "appwidget" on the device, which has a very rudimentary shell.
+base=/system
+export CLASSPATH=$base/framework/appops.jar
+exec app_process $base/bin com.android.commands.appops.AppOpsCommand "$@"
+
diff --git a/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java
new file mode 100644
index 0000000..c414f58
--- /dev/null
+++ b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java
@@ -0,0 +1,137 @@
+/*
+** Copyright 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.commands.appops;
+
+import android.app.ActivityManager;
+import android.app.ActivityThread;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.os.BaseCommand;
+
+import java.io.PrintStream;
+
+/**
+ * This class is a command line utility for manipulating AppOps permissions.
+ */
+public class AppOpsCommand extends BaseCommand {
+
+    public static void main(String[] args) {
+        new AppOpsCommand().run(args);
+    }
+
+    @Override
+    public void onShowUsage(PrintStream out) {
+        out.println("usage: adb shell appops set <PACKAGE> <OP> "
+                + "<allow|ignore|deny|default> [--user <USER_ID>]\n"
+                + "  <PACKAGE> an Android package name.\n"
+                + "  <OP>      an AppOps operation.\n"
+                + "  <USER_ID> the user id under which the package is installed. If --user is not\n"
+                + "            specified, the current user is assumed.\n");
+    }
+
+    private static final String COMMAND_SET = "set";
+
+    @Override
+    public void onRun() throws Exception {
+        String command = nextArgRequired();
+        switch (command) {
+            case COMMAND_SET:
+                runSet();
+                break;
+
+            default:
+                throw new IllegalArgumentException("Unknown command '" + command + "'.");
+        }
+    }
+
+    private static final String ARGUMENT_USER = "--user";
+
+    // Modes
+    private static final String MODE_ALLOW = "allow";
+    private static final String MODE_DENY = "deny";
+    private static final String MODE_IGNORE = "ignore";
+    private static final String MODE_DEFAULT = "default";
+
+    private void runSet() throws Exception {
+        String packageName = null;
+        String op = null;
+        String mode = null;
+        int userId = UserHandle.USER_CURRENT;
+        for (String argument; (argument = nextArg()) != null;) {
+            if (ARGUMENT_USER.equals(argument)) {
+                userId = Integer.parseInt(nextArgRequired());
+            } else {
+                if (packageName == null) {
+                    packageName = argument;
+                } else if (op == null) {
+                    op = argument;
+                } else if (mode == null) {
+                    mode = argument;
+                } else {
+                    throw new IllegalArgumentException("Unsupported argument: " + argument);
+                }
+            }
+        }
+
+        if (packageName == null) {
+            throw new IllegalArgumentException("Package name not specified.");
+        } else if (op == null) {
+            throw new IllegalArgumentException("Operation not specified.");
+        } else if (mode == null) {
+            throw new IllegalArgumentException("Mode not specified.");
+        }
+
+        final int opInt = AppOpsManager.strOpToOp(op);
+        final int modeInt;
+        switch (mode) {
+            case MODE_ALLOW:
+                modeInt = AppOpsManager.MODE_ALLOWED;
+                break;
+            case MODE_DENY:
+                modeInt = AppOpsManager.MODE_ERRORED;
+                break;
+            case MODE_IGNORE:
+                modeInt = AppOpsManager.MODE_IGNORED;
+                break;
+            case MODE_DEFAULT:
+                modeInt = AppOpsManager.MODE_DEFAULT;
+                break;
+            default:
+                throw new IllegalArgumentException("Mode is invalid.");
+        }
+
+        // Parsing complete, let's execute the command.
+
+        if (userId == UserHandle.USER_CURRENT) {
+            userId = ActivityManager.getCurrentUser();
+        }
+
+        final IPackageManager pm = ActivityThread.getPackageManager();
+        final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
+                ServiceManager.getService(Context.APP_OPS_SERVICE));
+        final int uid = pm.getPackageUid(packageName, userId);
+        if (uid < 0) {
+            throw new Exception("No UID for " + packageName + " for user " + userId);
+        }
+        appOpsService.setMode(opInt, uid, packageName, modeInt);
+    }
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 21c8b75..f5ac5f7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2095,7 +2095,9 @@
                     "by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " +
                     "android:windowActionBar to false in your theme to use a Toolbar instead.");
         }
-        mActionBar = new ToolbarActionBar(toolbar, getTitle(), this);
+        ToolbarActionBar tbab = new ToolbarActionBar(toolbar, getTitle(), this);
+        mActionBar = tbab;
+        mWindow.setCallback(tbab.getWrappedWindowCallback());
         mActionBar.invalidateOptionsMenu();
     }
 
@@ -3820,6 +3822,29 @@
     }
 
     /**
+     * Start a new activity as if it was started by the activity that started our
+     * current activity.  This is for the resolver and chooser activities, which operate
+     * as intermediaries that dispatch their intent to the target the user selects -- to
+     * do this, they must perform all security checks including permission grants as if
+     * their launch had come from the original activity.
+     * @hide
+     */
+    public void startActivityAsCaller(Intent intent, @Nullable Bundle options) {
+        if (mParent != null) {
+            throw new RuntimeException("Can't be called from a child");
+        }
+        Instrumentation.ActivityResult ar =
+                mInstrumentation.execStartActivityAsCaller(
+                        this, mMainThread.getApplicationThread(), mToken, this,
+                        intent, -1, options);
+        if (ar != null) {
+            mMainThread.sendActivityResult(
+                mToken, mEmbeddedID, -1, ar.getResultCode(),
+                ar.getResultData());
+        }
+    }
+
+    /**
      * Same as calling {@link #startIntentSenderForResult(IntentSender, int,
      * Intent, int, int, int, Bundle)} with no options.
      *
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 31cb4d6..1cb1047 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -169,6 +169,31 @@
             return true;
         }
 
+        case START_ACTIVITY_AS_CALLER_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder b = data.readStrongBinder();
+            IApplicationThread app = ApplicationThreadNative.asInterface(b);
+            String callingPackage = data.readString();
+            Intent intent = Intent.CREATOR.createFromParcel(data);
+            String resolvedType = data.readString();
+            IBinder resultTo = data.readStrongBinder();
+            String resultWho = data.readString();
+            int requestCode = data.readInt();
+            int startFlags = data.readInt();
+            String profileFile = data.readString();
+            ParcelFileDescriptor profileFd = data.readInt() != 0
+                    ? data.readFileDescriptor() : null;
+            Bundle options = data.readInt() != 0
+                    ? Bundle.CREATOR.createFromParcel(data) : null;
+            int result = startActivityAsCaller(app, callingPackage, intent, resolvedType,
+                    resultTo, resultWho, requestCode, startFlags,
+                    profileFile, profileFd, options);
+            reply.writeNoException();
+            reply.writeInt(result);
+            return true;
+        }
+
         case START_ACTIVITY_AND_WAIT_TRANSACTION:
         {
             data.enforceInterface(IActivityManager.descriptor);
@@ -2347,6 +2372,41 @@
         data.recycle();
         return result;
     }
+    public int startActivityAsCaller(IApplicationThread caller, String callingPackage,
+            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+            int startFlags, String profileFile,
+            ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
+        data.writeString(callingPackage);
+        intent.writeToParcel(data, 0);
+        data.writeString(resolvedType);
+        data.writeStrongBinder(resultTo);
+        data.writeString(resultWho);
+        data.writeInt(requestCode);
+        data.writeInt(startFlags);
+        data.writeString(profileFile);
+        if (profileFd != null) {
+            data.writeInt(1);
+            profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+        } else {
+            data.writeInt(0);
+        }
+        if (options != null) {
+            data.writeInt(1);
+            options.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        mRemote.transact(START_ACTIVITY_AS_CALLER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int result = reply.readInt();
+        reply.recycle();
+        data.recycle();
+        return result;
+    }
     public WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo, String resultWho,
             int requestCode, int startFlags, String profileFile,
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d9ea671..2136209 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3494,6 +3494,20 @@
         synchronized (mResourcesManager) {
             mCoreSettings = coreSettings;
         }
+        onCoreSettingsChange();
+    }
+
+    private void onCoreSettingsChange() {
+        boolean debugViewAttributes =
+                mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
+        if (debugViewAttributes != View.mDebugViewAttributes) {
+            View.mDebugViewAttributes = debugViewAttributes;
+
+            // request all activities to relaunch for the changes to take place
+            for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
+                requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, false);
+            }
+        }
     }
 
     private void handleUpdatePackageCompatibilityInfo(UpdateCompatibilityData data) {
@@ -4324,6 +4338,9 @@
         final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
         DateFormat.set24HourTimePref(is24Hr);
 
+        View.mDebugViewAttributes =
+                mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
+
         /**
          * For system applications on userdebug/eng builds, log stack
          * traces of disk and network access to dropbox for analysis.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index a6b3608..0d2ad08 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1046,7 +1046,10 @@
         return packageName + " from uid " + uid + " not allowed to perform " + sOpNames[op];
     }
 
-    private int strOpToOp(String op) {
+    /**
+     * {@hide}
+     */
+    public static int strOpToOp(String op) {
         Integer val = sOpStrToOp.get(op);
         if (val == null) {
             throw new IllegalArgumentException("Unknown operation string: " + op);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 2dbc4ea..8e21899 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -68,6 +68,10 @@
             Intent intent, String resolvedType, IBinder resultTo, String resultWho,
             int requestCode, int flags, String profileFile,
             ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException;
+    public int startActivityAsCaller(IApplicationThread caller, String callingPackage,
+            Intent intent, String resolvedType, IBinder resultTo, String resultWho,
+            int requestCode, int flags, String profileFile,
+            ParcelFileDescriptor profileFd, Bundle options) throws RemoteException;
     public WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo, String resultWho,
             int requestCode, int flags, String profileFile,
@@ -760,4 +764,5 @@
     int START_ACTIVITY_FROM_RECENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 229;
     int NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+230;
     int KEYGUARD_WAITING_FOR_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+231;
+    int START_ACTIVITY_AS_CALLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+232;
 }
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index c583998..b28d7cc 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1665,6 +1665,43 @@
         return null;
     }
 
+    /**
+     * Special version!
+     * @hide
+     */
+    public ActivityResult execStartActivityAsCaller(
+            Context who, IBinder contextThread, IBinder token, Activity target,
+            Intent intent, int requestCode, Bundle options) {
+        IApplicationThread whoThread = (IApplicationThread) contextThread;
+        if (mActivityMonitors != null) {
+            synchronized (mSync) {
+                final int N = mActivityMonitors.size();
+                for (int i=0; i<N; i++) {
+                    final ActivityMonitor am = mActivityMonitors.get(i);
+                    if (am.match(who, null, intent)) {
+                        am.mHits++;
+                        if (am.isBlocking()) {
+                            return requestCode >= 0 ? am.getResult() : null;
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+        try {
+            intent.migrateExtraStreamToClipData();
+            intent.prepareToLeaveProcess();
+            int result = ActivityManagerNative.getDefault()
+                .startActivityAsCaller(whoThread, who.getBasePackageName(), intent,
+                        intent.resolveTypeIfNeeded(who.getContentResolver()),
+                        token, target != null ? target.mEmbeddedID : null,
+                        requestCode, 0, null, null, options);
+            checkStartActivityResult(result, intent);
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
+
     /*package*/ final void init(ActivityThread thread,
             Context instrContext, Context appContext, ComponentName component, 
             IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5f58839..70ba8ea 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1607,6 +1607,7 @@
         builder.setPriority(this.priority);
         builder.setTicker(this.tickerText);
         builder.setNumber(this.number);
+        builder.setColor(this.color);
         builder.mFlags = this.flags;
         builder.setSound(this.sound, this.audioStreamType);
         builder.setDefaults(this.defaults);
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 697c5d8..6454367 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -110,6 +110,7 @@
         setView(view);
         setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
         setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
+        setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
 
         mTimePicker = (TimePicker) view.findViewById(R.id.timePicker);
         mTimePicker.setIs24HourView(mIs24HourView);
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 1f168c3..15def09 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -167,28 +167,30 @@
 
     /**
      * Action sent to a device administrator to notify that the device is entering
-     * or exiting lock task mode from an authorized package.  The extra
-     * {@link #EXTRA_LOCK_TASK_ENTERING} will describe whether entering or exiting
-     * the mode.  If entering, the extra {@link #EXTRA_LOCK_TASK_PACKAGE} will describe
-     * the authorized package using lock task mode.
+     * lock task mode from an authorized package.  The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
+     * will describe the authorized package using lock task mode.
      *
-     * @see DevicePolicyManager#isLockTaskPermitted
+     * @see DevicePolicyManager#isLockTaskPermitted(String)
      *
      * <p>The calling device admin must be the device owner or profile
      * owner to receive this broadcast.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_LOCK_TASK_CHANGED
-            = "android.app.action.ACTION_LOCK_TASK_CHANGED";
+    public static final String ACTION_LOCK_TASK_ENTERING
+            = "android.app.action.ACTION_LOCK_TASK_ENTERING";
 
     /**
-     * A boolean describing whether the device is currently entering or exiting
-     * lock task mode.
+     * Action sent to a device administrator to notify that the device is exiting
+     * lock task mode from an authorized package.
      *
-     * @see #ACTION_LOCK_TASK_CHANGED
+     * @see DevicePolicyManager#isLockTaskPermitted(String)
+     *
+     * <p>The calling device admin must be the device owner or profile
+     * owner to receive this broadcast.
      */
-    public static final String EXTRA_LOCK_TASK_ENTERING =
-            "android.app.extra.LOCK_TASK_ENTERING";
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_LOCK_TASK_EXITING
+            = "android.app.action.ACTION_LOCK_TASK_EXITING";
 
     /**
      * A boolean describing whether the device is currently entering or exiting
@@ -380,16 +382,24 @@
     }
 
     /**
-     * Called when a device is entering or exiting lock task mode by a package
-     * authorized by {@link DevicePolicyManager#isLockTaskPermitted(String)}
+     * Called when a device is entering lock task mode by a package authorized
+     * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
-     * @param isEnteringLockTask Whether the device is entering or exiting lock task mode.
      * @param pkg If entering, the authorized package using lock task mode, otherwise null.
      */
-    public void onLockTaskModeChanged(Context context, Intent intent, boolean isEnteringLockTask,
-            String pkg) {
+    public void onLockTaskModeEntering(Context context, Intent intent, String pkg) {
+    }
+
+    /**
+     * Called when a device is exiting lock task mode by a package authorized
+     * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
+     *
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     */
+    public void onLockTaskModeExiting(Context context, Intent intent) {
     }
 
     /**
@@ -421,10 +431,11 @@
             onPasswordExpiring(context, intent);
         } else if (ACTION_PROFILE_PROVISIONING_COMPLETE.equals(action)) {
             onProfileProvisioningComplete(context, intent);
-        } else if (ACTION_LOCK_TASK_CHANGED.equals(action)) {
-            boolean isEntering = intent.getBooleanExtra(EXTRA_LOCK_TASK_ENTERING, false);
+        } else if (ACTION_LOCK_TASK_ENTERING.equals(action)) {
             String pkg = intent.getStringExtra(EXTRA_LOCK_TASK_PACKAGE);
-            onLockTaskModeChanged(context, intent, isEntering, pkg);
+            onLockTaskModeEntering(context, intent, pkg);
+        } else if (ACTION_LOCK_TASK_EXITING.equals(action)) {
+            onLockTaskModeExiting(context, intent);
         }
     }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5350d70..f3f0c4d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2943,15 +2943,17 @@
      *
      * This function can only be called by the device owner.
      * @param packages The list of packages allowed to enter lock task mode
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      *
      * @see Activity#startLockTask()
      * @see DeviceAdminReceiver#onLockTaskModeChanged(Context, Intent, boolean, String)
      * @see UserManager#DISALLOW_CREATE_WINDOWS
      */
-    public void setLockTaskPackages(String[] packages) throws SecurityException {
+    public void setLockTaskPackages(ComponentName admin, String[] packages)
+            throws SecurityException {
         if (mService != null) {
             try {
-                mService.setLockTaskPackages(packages);
+                mService.setLockTaskPackages(admin, packages);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2960,12 +2962,14 @@
 
     /**
      * This function returns the list of packages allowed to start the lock task mode.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @hide
      */
-    public String[] getLockTaskPackages() {
+    public String[] getLockTaskPackages(ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getLockTaskPackages();
+                return mService.getLockTaskPackages(admin);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8954c0d..324b963 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -153,8 +153,8 @@
     String[] getAccountTypesWithManagementDisabled();
     String[] getAccountTypesWithManagementDisabledAsUser(int userId);
 
-    void setLockTaskPackages(in String[] packages);
-    String[] getLockTaskPackages();
+    void setLockTaskPackages(in ComponentName who, in String[] packages);
+    String[] getLockTaskPackages(in ComponentName who);
     boolean isLockTaskPermitted(in String pkg);
 
     void setGlobalSetting(in ComponentName who, in String setting, in String value);
diff --git a/core/java/android/app/backup/BackupDataInput.java b/core/java/android/app/backup/BackupDataInput.java
index 03205fb..26f9e3e 100644
--- a/core/java/android/app/backup/BackupDataInput.java
+++ b/core/java/android/app/backup/BackupDataInput.java
@@ -16,6 +16,8 @@
 
 package android.app.backup;
 
+import android.annotation.SystemApi;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 
@@ -70,6 +72,7 @@
     }
 
     /** @hide */
+    @SystemApi
     public BackupDataInput(FileDescriptor fd) {
         if (fd == null) throw new NullPointerException();
         mBackupReader = ctor(fd);
@@ -79,6 +82,7 @@
     }
 
     /** @hide */
+    @Override
     protected void finalize() throws Throwable {
         try {
             dtor(mBackupReader);
@@ -174,7 +178,7 @@
      * for further processing.  This allows a {@link android.app.backup.BackupAgent} to
      * efficiently discard obsolete or otherwise uninteresting records during the
      * restore operation.
-     * 
+     *
      * @throws IOException if an error occurred when trying to read the restore data stream
      */
     public void skipEntityData() throws IOException {
diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java
index fc5fb3d..048a4bb 100644
--- a/core/java/android/app/backup/BackupDataOutput.java
+++ b/core/java/android/app/backup/BackupDataOutput.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.annotation.SystemApi;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 
@@ -66,6 +67,7 @@
     long mBackupWriter;
 
     /** @hide */
+    @SystemApi
     public BackupDataOutput(FileDescriptor fd) {
         if (fd == null) throw new NullPointerException();
         mBackupWriter = ctor(fd);
@@ -115,6 +117,7 @@
     }
 
     /** @hide */
+    @Override
     protected void finalize() throws Throwable {
         try {
             dtor(mBackupWriter);
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 6cfabf0..70bb5e4 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -51,7 +51,7 @@
     public static final int AGENT_UNKNOWN = -1004;
 
     IBackupTransport mBinderImpl = new TransportImpl();
-    /** @hide */
+
     public IBinder getBinder() {
         return mBinderImpl.asBinder();
     }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0ca800f..b13792b 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1612,7 +1612,7 @@
      * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
      */
     public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
-        notifyChange(uri, observer, syncToNetwork, UserHandle.getCallingUserId());
+        notifyChange(uri, observer, syncToNetwork, UserHandle.myUserId());
     }
 
     /**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5f046c5..a13a928 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -45,6 +45,7 @@
 import android.util.AttributeSet;
 import android.view.DisplayAdjustments;
 import android.view.Display;
+import android.view.ViewDebug;
 import android.view.WindowManager;
 
 import java.io.File;
@@ -420,6 +421,7 @@
     /**
      * Return the Theme object associated with this Context.
      */
+    @ViewDebug.ExportedProperty(deepExport = true)
     public abstract Resources.Theme getTheme();
 
     /**
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index e3c5449..1240a23 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -564,6 +564,11 @@
         return mDataTypes != null && findMimeType(type);
     }
 
+    /** @hide */
+    public final boolean hasExactDataType(String type) {
+        return mDataTypes != null && mDataTypes.contains(type);
+    }
+
     /**
      * Return the number of data types in the filter.
      */
@@ -681,6 +686,20 @@
             return mPort;
         }
 
+        /** @hide */
+        public boolean match(AuthorityEntry other) {
+            if (mWild != other.mWild) {
+                return false;
+            }
+            if (!mHost.equals(other.mHost)) {
+                return false;
+            }
+            if (mPort != other.mPort) {
+                return false;
+            }
+            return true;
+        }
+
         /**
          * Determine whether this AuthorityEntry matches the given data Uri.
          * <em>Note that this comparison is case-sensitive, unlike formal
@@ -792,6 +811,21 @@
         return false;
     }
 
+    /** @hide */
+    public final boolean hasDataSchemeSpecificPart(PatternMatcher ssp) {
+        if (mDataSchemeSpecificParts == null) {
+            return false;
+        }
+        final int numDataSchemeSpecificParts = mDataSchemeSpecificParts.size();
+        for (int i = 0; i < numDataSchemeSpecificParts; i++) {
+            final PatternMatcher pe = mDataSchemeSpecificParts.get(i);
+            if (pe.getType() == ssp.getType() && pe.getPath().equals(ssp.getPath())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Return an iterator over the filter's data scheme specific parts.
      */
@@ -860,6 +894,20 @@
         return matchDataAuthority(data) >= 0;
     }
 
+    /** @hide */
+    public final boolean hasDataAuthority(AuthorityEntry auth) {
+        if (mDataAuthorities == null) {
+            return false;
+        }
+        final int numDataAuthorities = mDataAuthorities.size();
+        for (int i = 0; i < numDataAuthorities; i++) {
+            if (mDataAuthorities.get(i).match(auth)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Return an iterator over the filter's data authorities.
      */
@@ -942,6 +990,21 @@
         return false;
     }
 
+    /** @hide */
+    public final boolean hasDataPath(PatternMatcher path) {
+        if (mDataPaths == null) {
+            return false;
+        }
+        final int numDataPaths = mDataPaths.size();
+        for (int i = 0; i < numDataPaths; i++) {
+            final PatternMatcher pe = mDataPaths.get(i);
+            if (pe.getType() == path.getType() && pe.getPath().equals(path.getPath())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Return an iterator over the filter's data paths.
      */
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 268919c..f9370b3 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -64,7 +64,7 @@
     /**
      * Callbacks for package changes to this and related managed profiles.
      */
-    public static abstract class OnAppsChangedCallback {
+    public static abstract class Callback {
         /**
          * Indicates that a package was removed from the specified profile.
          *
@@ -207,17 +207,17 @@
     }
 
     /**
-     * Starts an activity in the specified profile.
+     * Starts a Main activity in the specified profile.
      *
      * @param component The ComponentName of the activity to launch
      * @param user The UserHandle of the profile
      * @param sourceBounds The Rect containing the source bounds of the clicked icon
      * @param opts Options to pass to startActivity
      */
-    public void startActivityForProfile(ComponentName component, UserHandle user, Rect sourceBounds,
+    public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
             Bundle opts) {
         if (DEBUG) {
-            Log.i(TAG, "StartActivityForProfile " + component + " " + user.getIdentifier());
+            Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
         }
         try {
             mService.startActivityAsUser(component, sourceBounds, opts, user);
@@ -235,7 +235,7 @@
      * @param sourceBounds The Rect containing the source bounds of the clicked icon
      * @param opts Options to pass to startActivity
      */
-    public void showAppDetailsForProfile(ComponentName component, UserHandle user,
+    public void startAppDetailsActivity(ComponentName component, UserHandle user,
             Rect sourceBounds, Bundle opts) {
         try {
             mService.showAppDetailsAsUser(component, sourceBounds, opts, user);
@@ -252,7 +252,7 @@
      *
      * @return true if the package exists and is enabled.
      */
-    public boolean isPackageEnabledForProfile(String packageName, UserHandle user) {
+    public boolean isPackageEnabled(String packageName, UserHandle user) {
         try {
             return mService.isPackageEnabled(packageName, user);
         } catch (RemoteException re) {
@@ -268,7 +268,7 @@
      *
      * @return true if the activity exists and is enabled.
      */
-    public boolean isActivityEnabledForProfile(ComponentName component, UserHandle user) {
+    public boolean isActivityEnabled(ComponentName component, UserHandle user) {
         try {
             return mService.isActivityEnabled(component, user);
         } catch (RemoteException re) {
@@ -282,8 +282,8 @@
      *
      * @param callback The callback to add.
      */
-    public void addOnAppsChangedCallback(OnAppsChangedCallback callback) {
-        addOnAppsChangedCallback(callback, null);
+    public void addCallback(Callback callback) {
+        addCallback(callback, null);
     }
 
     /**
@@ -292,7 +292,7 @@
      * @param callback The callback to add.
      * @param handler that should be used to post callbacks on, may be null.
      */
-    public void addOnAppsChangedCallback(OnAppsChangedCallback callback, Handler handler) {
+    public void addCallback(Callback callback, Handler handler) {
         synchronized (this) {
             if (callback != null && !mCallbacks.contains(callback)) {
                 boolean addedFirstCallback = mCallbacks.size() == 0;
@@ -311,9 +311,9 @@
      * Removes a callback that was previously added.
      *
      * @param callback The callback to remove.
-     * @see #addOnAppsChangedListener(OnAppsChangedCallback)
+     * @see #addCallback(Callback)
      */
-    public void removeOnAppsChangedCallback(OnAppsChangedCallback callback) {
+    public void removeCallback(Callback callback) {
         synchronized (this) {
             removeCallbackLocked(callback);
             if (mCallbacks.size() == 0) {
@@ -325,7 +325,7 @@
         }
     }
 
-    private void removeCallbackLocked(OnAppsChangedCallback callback) {
+    private void removeCallbackLocked(Callback callback) {
         if (callback == null) {
             throw new IllegalArgumentException("Callback cannot be null");
         }
@@ -338,7 +338,7 @@
         }
     }
 
-    private void addCallbackLocked(OnAppsChangedCallback callback, Handler handler) {
+    private void addCallbackLocked(Callback callback, Handler handler) {
         // Remove if already present.
         removeCallbackLocked(callback);
         if (handler == null) {
@@ -421,7 +421,7 @@
         private static final int MSG_AVAILABLE = 4;
         private static final int MSG_UNAVAILABLE = 5;
 
-        private OnAppsChangedCallback mCallback;
+        private LauncherApps.Callback mCallback;
 
         private static class CallbackInfo {
             String[] packageNames;
@@ -430,7 +430,7 @@
             UserHandle user;
         }
 
-        public CallbackMessageHandler(Looper looper, OnAppsChangedCallback callback) {
+        public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
             super(looper, null, true);
             mCallback = callback;
         }
@@ -499,4 +499,45 @@
             obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
         }
     }
+
+    /** Remove after unbundled apps have migrated STOP SHIP */
+    public static abstract class OnAppsChangedCallback extends Callback {
+    }
+
+    /** Remove after unbundled apps have migrated STOP SHIP */
+    public void addOnAppsChangedCallback(OnAppsChangedCallback callback) {
+        addCallback(callback, null);
+    }
+
+    /** Remove after unbundled apps have migrated STOP SHIP */
+    public void addOnAppsChangedCallback(OnAppsChangedCallback callback, Handler handler) {
+        addCallback(callback, handler);
+    }
+
+    /** Remove after unbundled apps have migrated STOP SHIP */
+    public void removeOnAppsChangedCallback(OnAppsChangedCallback callback) {
+        removeCallback(callback);
+    }
+
+    /** Remove after unbundled apps have migrated STOP SHIP */
+    public void startActivityForProfile(ComponentName component, UserHandle user, Rect sourceBounds,
+            Bundle opts) {
+        startMainActivity(component, user, sourceBounds, opts);
+    }
+
+    /** Remove after unbundled apps have migrated STOP SHIP */
+    public void showAppDetailsForProfile(ComponentName component, UserHandle user,
+            Rect sourceBounds, Bundle opts) {
+        startAppDetailsActivity(component, user, sourceBounds, opts);
+    }
+
+    /** Remove after unbundled apps have migrated STOP SHIP */
+    public boolean isPackageEnabledForProfile(String packageName, UserHandle user) {
+        return isPackageEnabled(packageName, user);
+    }
+
+    /** Remove after unbundled apps have migrated STOP SHIP */
+    public boolean isActivityEnabledForProfile(ComponentName component, UserHandle user) {
+        return isActivityEnabled(component, user);
+    }
 }
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index a0e3c4a..765b2a9 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -227,19 +227,6 @@
     public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2;
 
     /**
-     * Flag for {@link #requiredForProfile}
-     * The application will always be installed for a restricted profile.
-     * @hide
-     */
-    public static final int RESTRICTED_PROFILE = 1;
-    /**
-     * Flag for {@link #requiredForProfile}
-     * The application will always be installed for a managed profile.
-     * @hide
-     */
-    public static final int MANAGED_PROFILE = 2;
-
-    /**
      * The install location requested by the package. From the
      * {@link android.R.attr#installLocation} attribute, one of
      * {@link #INSTALL_LOCATION_AUTO}, {@link #INSTALL_LOCATION_INTERNAL_ONLY},
@@ -247,12 +234,6 @@
      */
     public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY;
 
-    /**
-     * Defines which profiles this app is required for.
-     * @hide
-     */
-    public int requiredForProfile;
-
     /** @hide */
     public boolean requiredForAllUsers;
 
@@ -313,7 +294,6 @@
         dest.writeTypedArray(featureGroups, parcelableFlags);
         dest.writeInt(installLocation);
         dest.writeInt(requiredForAllUsers ? 1 : 0);
-        dest.writeInt(requiredForProfile);
         dest.writeString(restrictedAccountType);
         dest.writeString(requiredAccountType);
         dest.writeString(overlayTarget);
@@ -358,7 +338,6 @@
         featureGroups = source.createTypedArray(FeatureGroupInfo.CREATOR);
         installLocation = source.readInt();
         requiredForAllUsers = source.readInt() != 0;
-        requiredForProfile = source.readInt();
         restrictedAccountType = source.readString();
         requiredAccountType = source.readString();
         overlayTarget = source.readString();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index aa4ea45..4ac701f 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -129,7 +129,7 @@
      *
      * @see Intent#getParcelableExtra(String)
      */
-    public static final int STATUS_USER_ACTION_REQUIRED = -1;
+    public static final int STATUS_PENDING_USER_ACTION = -1;
 
     /**
      * The operation succeeded.
@@ -152,7 +152,7 @@
      *
      * @see #EXTRA_STATUS_MESSAGE
      */
-    public static final int STATUS_FAILURE_BLOCKED = 1;
+    public static final int STATUS_FAILURE_BLOCKED = 2;
 
     /**
      * The operation failed because it was actively aborted. For example, the
@@ -161,7 +161,7 @@
      *
      * @see #EXTRA_STATUS_MESSAGE
      */
-    public static final int STATUS_FAILURE_ABORTED = 2;
+    public static final int STATUS_FAILURE_ABORTED = 3;
 
     /**
      * The operation failed because one or more of the APKs was invalid. For
@@ -170,7 +170,7 @@
      *
      * @see #EXTRA_STATUS_MESSAGE
      */
-    public static final int STATUS_FAILURE_INVALID = 3;
+    public static final int STATUS_FAILURE_INVALID = 4;
 
     /**
      * The operation failed because it conflicts (or is inconsistent with) with
@@ -183,7 +183,7 @@
      *
      * @see #EXTRA_STATUS_MESSAGE
      */
-    public static final int STATUS_FAILURE_CONFLICT = 4;
+    public static final int STATUS_FAILURE_CONFLICT = 5;
 
     /**
      * The operation failed because of storage issues. For example, the device
@@ -192,7 +192,7 @@
      *
      * @see #EXTRA_STATUS_MESSAGE
      */
-    public static final int STATUS_FAILURE_STORAGE = 5;
+    public static final int STATUS_FAILURE_STORAGE = 6;
 
     /**
      * The operation failed because it is fundamentally incompatible with this
@@ -202,7 +202,7 @@
      *
      * @see #EXTRA_STATUS_MESSAGE
      */
-    public static final int STATUS_FAILURE_INCOMPATIBLE = 6;
+    public static final int STATUS_FAILURE_INCOMPATIBLE = 7;
 
     private final Context mContext;
     private final PackageManager mPm;
@@ -584,9 +584,12 @@
          * This returns all names which have been previously written through
          * {@link #openWrite(String, long, long)} as part of this session.
          */
-        public @NonNull String[] getNames() {
+        public @NonNull String[] getNames() throws IOException {
             try {
                 return mSession.getNames();
+            } catch (RuntimeException e) {
+                ExceptionUtils.maybeUnwrapIOException(e);
+                throw e;
             } catch (RemoteException e) {
                 throw e.rethrowAsRuntimeException();
             }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index cddefb5..2c50f25 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -413,7 +413,6 @@
         if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0
                 || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
             pi.requiredForAllUsers = p.mRequiredForAllUsers;
-            pi.requiredForProfile = p.mRequiredForProfile;
         }
         pi.restrictedAccountType = p.mRestrictedAccountType;
         pi.requiredAccountType = p.mRequiredAccountType;
@@ -2477,8 +2476,6 @@
                 false)) {
             owner.mRequiredForAllUsers = true;
         }
-        owner.mRequiredForProfile = sa.getInt(
-                com.android.internal.R.styleable.AndroidManifestApplication_requiredForProfile, 0);
 
         String restrictedAccountType = sa.getString(com.android.internal.R.styleable
                 .AndroidManifestApplication_restrictedAccountType);
@@ -4269,9 +4266,6 @@
         /* An app that's required for all users and cannot be uninstalled for a user */
         public boolean mRequiredForAllUsers;
 
-        /* For which types of profile this app is required */
-        public int mRequiredForProfile;
-
         /* The restricted account authenticator type that is used by this application */
         public String mRestrictedAccountType;
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index fff21aa..31813c10 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -16,6 +16,7 @@
 
 package android.content.res;
 
+import android.view.ViewDebug;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -1638,12 +1639,41 @@
         /*package*/ String getKey() {
             return mKey;
         }
+
+        private String getResourceNameFromHexString(String hexString) {
+            return getResourceName(Integer.parseInt(hexString, 16));
+        }
+
+        /**
+         * Parses {@link #mKey} and returns a String array that holds pairs of adjacent Theme data:
+         * resource name followed by whether or not it was forced, as specified by
+         * {@link #applyStyle(int, boolean)}.
+         *
+         * @hide
+         */
+        @ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true)
+        public String[] getTheme() {
+            String[] themeData = mKey.split(" ");
+            String[] themes = new String[themeData.length * 2];
+            String theme;
+            boolean forced;
+
+            for (int i = 0, j = themeData.length - 1; i < themes.length; i += 2, --j) {
+                theme = themeData[j];
+                forced = theme.endsWith("!");
+                themes[i] = forced ?
+                        getResourceNameFromHexString(theme.substring(0, theme.length() - 1)) :
+                        getResourceNameFromHexString(theme);
+                themes[i + 1] = forced ? "forced" : "not forced";
+            }
+            return themes;
+        }
     }
 
     /**
      * Generate a new Theme object for this set of Resources.  It initially
      * starts out empty.
-     * 
+     *
      * @return Theme The newly created Theme container.
      */
     public final Theme newTheme() {
@@ -1653,7 +1683,7 @@
     /**
      * Retrieve a set of basic attribute values from an AttributeSet, not
      * performing styling of them using a theme and/or style resources.
-     * 
+     *
      * @param set The current attribute values to retrieve.
      * @param attrs The specific attributes to be retrieved.
      * @return Returns a TypedArray holding an array of the attribute values.
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index eadfa73..310ab76 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1558,6 +1558,26 @@
         return _enableShutterSound(enabled);
     }
 
+    /**
+     * Disable the shutter sound unconditionally.
+     *
+     * <p>
+     * This is only guaranteed to work for legacy cameras
+     * (i.e. initialized with {@link #cameraInitUnspecified}). Trying to call this on
+     * a regular camera will force a conditional check in the camera service.
+     * </p>
+     *
+     * @return {@code true} if the shutter sound state was successfully
+     *         changed. {@code false} if the shutter sound state could not be
+     *         changed. {@code true} is also returned if shutter sound playback
+     *         is already set to the requested state.
+     *
+     * @hide
+     */
+    public final boolean disableShutterSound() {
+        return _enableShutterSound(/*enabled*/false);
+    }
+
     private native final boolean _enableShutterSound(boolean enabled);
 
     /**
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index c68d8c3..5cbf109 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -56,6 +56,7 @@
  * Keep up to date with ICameraDeviceUser.aidl.
  * </p>
  */
+@SuppressWarnings("deprecation")
 public class CameraDeviceUserShim implements ICameraDeviceUser {
     private static final String TAG = "CameraDeviceUserShim";
 
@@ -259,6 +260,7 @@
                 super(l);
             }
 
+            @Override
             public void handleMessage(Message msg) {
                 try {
                     switch (msg.what) {
@@ -320,6 +322,9 @@
         // Check errors old HAL initialization
         CameraBinderDecorator.throwOnError(initErrors);
 
+        // Disable shutter sounds (this will work unconditionally) for api2 clients
+        legacyCamera.disableShutterSound();
+
         CameraInfo info = new CameraInfo();
         Camera.getCameraInfo(cameraId, info);
 
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index fbe26e5..ee0ca9c 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -1207,6 +1207,9 @@
             m.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, bestRange);
         }
 
+        // control.sceneMode -- DISABLED is always available
+        m.set(CaptureRequest.CONTROL_SCENE_MODE, CONTROL_SCENE_MODE_DISABLED);
+
         /*
          * statistics.*
          */
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 2e6b9ae..c0b7967 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -339,6 +339,11 @@
      * @see #isOutputSupportedFor(Class)
      */
     public <T> Size[] getOutputSizes(Class<T> klass) {
+        // Image reader is "supported", but never for implementation-defined formats; return empty
+        if (android.media.ImageReader.class.isAssignableFrom(klass)) {
+            return new Size[0];
+        }
+
         if (isOutputSupportedFor(klass) == false) {
             return null;
         }
diff --git a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
index 97da3a2..7abea36 100644
--- a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
@@ -230,7 +230,7 @@
         mDeviceType = DEVICE_RESERVED;
         mVendorId = 0;
         mDevicePowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
-        mDisplayName = "MHL";
+        mDisplayName = "Mobile";
 
         mDeviceId = adopterId;
         mAdopterId = deviceId;
@@ -416,7 +416,8 @@
         switch (mHdmiDeviceType) {
             case HDMI_DEVICE_TYPE_CEC:
                 s.append("CEC: ");
-                s.append("logical_address: ").append(mLogicalAddress).append(" ");
+                s.append("logical_address: ").append(String.format("0x%02X", mLogicalAddress));
+                s.append(" ");
                 s.append("device_type: ").append(mDeviceType).append(" ");
                 s.append("vendor_id: ").append(mVendorId).append(" ");
                 s.append("display_name: ").append(mDisplayName).append(" ");
@@ -424,8 +425,8 @@
                 break;
             case HDMI_DEVICE_TYPE_MHL:
                 s.append("MHL: ");
-                s.append("device_id: ").append(mDeviceId).append(" ");
-                s.append("adopter_id: ").append(mAdopterId).append(" ");
+                s.append("device_id: ").append(String.format("0x%04X", mDeviceId)).append(" ");
+                s.append("adopter_id: ").append(String.format("0x%04X", mAdopterId)).append(" ");
                 break;
 
             case HDMI_DEVICE_TYPE_HARDWARE:
@@ -434,7 +435,8 @@
             default:
                 return "";
         }
-        s.append("physical_address: ").append(String.format("0x04X", mPhysicalAddress)).append(" ");
+        s.append("physical_address: ").append(String.format("0x%04X", mPhysicalAddress));
+        s.append(" ");
         s.append("port_id: ").append(mPortId);
         return s.toString();
     }
diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java
index 2d82cba..7dd105a 100644
--- a/core/java/android/hardware/location/GeofenceHardware.java
+++ b/core/java/android/hardware/location/GeofenceHardware.java
@@ -15,6 +15,7 @@
  */
 package android.hardware.location;
 
+import android.annotation.SystemApi;
 import android.location.Location;
 import android.os.Build;
 import android.os.RemoteException;
@@ -43,7 +44,10 @@
  * an appropriate transition would be triggered. The "reasonably confident" parameter
  * depends on the hardware system and the positioning algorithms used.
  * For instance, {@link #MONITORING_TYPE_GPS_HARDWARE} uses 95% as a confidence level.
+ *
+ * @hide
  */
+@SystemApi
 public final class GeofenceHardware {
     private IGeofenceHardware mService;
 
@@ -162,9 +166,7 @@
     private HashMap<GeofenceHardwareMonitorCallback, GeofenceHardwareMonitorCallbackWrapper>
             mMonitorCallbacks = new HashMap<GeofenceHardwareMonitorCallback,
                     GeofenceHardwareMonitorCallbackWrapper>();
-    /**
-     * @hide
-     */
+
     public GeofenceHardware(IGeofenceHardware service) {
         mService = service;
     }
diff --git a/core/java/android/hardware/location/GeofenceHardwareCallback.java b/core/java/android/hardware/location/GeofenceHardwareCallback.java
index 6cad3da..a2a7ed0 100644
--- a/core/java/android/hardware/location/GeofenceHardwareCallback.java
+++ b/core/java/android/hardware/location/GeofenceHardwareCallback.java
@@ -16,11 +16,15 @@
 
 package android.hardware.location;
 
+import android.annotation.SystemApi;
 import android.location.Location;
 
 /**
  * The callback class associated with the APIs in {@link GeofenceHardware}
+ *
+ * @hide
  */
+@SystemApi
 public abstract class GeofenceHardwareCallback {
     /**
      * The callback called when there is a transition to report for the specific
diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java
index f927027..d7daa10 100644
--- a/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java
+++ b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java
@@ -16,12 +16,16 @@
 
 package android.hardware.location;
 
+import android.annotation.SystemApi;
 import android.location.Location;
 
 /**
  * The callback class associated with the status change of hardware monitors
  * in {@link GeofenceHardware}
+ *
+ * @hide
  */
+@SystemApi
 public abstract class GeofenceHardwareMonitorCallback {
     /**
      * The callback called when the state of a monitoring system changes.
diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java b/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java
index 9c460d2..7079237 100644
--- a/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java
+++ b/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java
@@ -16,13 +16,17 @@
 
 package android.hardware.location;
 
+import android.annotation.SystemApi;
 import android.location.Location;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
  * A class that represents an event for each change in the state of a monitoring system.
+ *
+ * @hide
  */
+@SystemApi
 public class GeofenceHardwareMonitorEvent implements Parcelable {
     private final int mMonitoringType;
     private final int mMonitoringStatus;
diff --git a/core/java/android/hardware/location/GeofenceHardwareRequest.java b/core/java/android/hardware/location/GeofenceHardwareRequest.java
index 887c4ad..68545a8 100644
--- a/core/java/android/hardware/location/GeofenceHardwareRequest.java
+++ b/core/java/android/hardware/location/GeofenceHardwareRequest.java
@@ -16,12 +16,16 @@
 
 package android.hardware.location;
 
+import android.annotation.SystemApi;
+
 /**
  * This class represents the characteristics of the geofence.
  *
  * <p> Use this in conjunction with {@link GeofenceHardware} APIs.
+ *
+ * @hide
  */
-
+@SystemApi
 public final class GeofenceHardwareRequest {
     static final int GEOFENCE_TYPE_CIRCLE = 0;
     private int mType;
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 49a307e..71df60a 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -16,13 +16,15 @@
 
 package android.net;
 
+import android.net.NetworkUtils;
 import android.os.Parcelable;
 import android.os.Parcel;
 import android.text.TextUtils;
 import android.util.Log;
 
 import java.net.InetAddress;
-import java.net.UnknownHostException;
+import java.net.Inet4Address;
+import java.util.Objects;
 
 /**
  * A simple object for retrieving the results of a DHCP request.
@@ -30,38 +32,34 @@
  * TODO - remove when DhcpInfo is deprecated.  Move the remaining api to LinkProperties.
  * @hide
  */
-public class DhcpResults implements Parcelable {
+public class DhcpResults extends StaticIpConfiguration {
     private static final String TAG = "DhcpResults";
 
-    public final LinkProperties linkProperties;
-
     public InetAddress serverAddress;
 
-    /**
-     * Vendor specific information (from RFC 2132).
-     */
+    /** Vendor specific information (from RFC 2132). */
     public String vendorInfo;
 
     public int leaseDuration;
 
     public DhcpResults() {
-        linkProperties = new LinkProperties();
+        super();
+    }
+
+    public DhcpResults(StaticIpConfiguration source) {
+        super(source);
     }
 
     /** copy constructor */
     public DhcpResults(DhcpResults source) {
-        if (source != null) {
-            linkProperties = new LinkProperties(source.linkProperties);
-            serverAddress = source.serverAddress;
-            leaseDuration = source.leaseDuration;
-            vendorInfo = source.vendorInfo;
-        } else {
-            linkProperties = new LinkProperties();
-        }
-    }
+        super(source);
 
-    public DhcpResults(LinkProperties lp) {
-        linkProperties = new LinkProperties(lp);
+        if (source != null) {
+            // All these are immutable, so no need to make copies.
+            serverAddress = source.serverAddress;
+            vendorInfo = source.vendorInfo;
+            leaseDuration = source.leaseDuration;
+        }
     }
 
     /**
@@ -70,14 +68,10 @@
      * being empty.
      */
     public void updateFromDhcpRequest(DhcpResults orig) {
-        if (orig == null || orig.linkProperties == null) return;
-        if (linkProperties.getRoutes().size() == 0) {
-            for (RouteInfo r : orig.linkProperties.getRoutes()) linkProperties.addRoute(r);
-        }
-        if (linkProperties.getDnsServers().size() == 0) {
-            for (InetAddress d : orig.linkProperties.getDnsServers()) {
-                linkProperties.addDnsServer(d);
-            }
+        if (orig == null) return;
+        if (gateway == null) gateway = orig.gateway;
+        if (dnsServers.size() == 0) {
+            dnsServers.addAll(orig.dnsServers);
         }
     }
 
@@ -94,15 +88,14 @@
     }
 
     public void clear() {
-        linkProperties.clear();
-        serverAddress = null;
+        super.clear();
         vendorInfo = null;
         leaseDuration = 0;
     }
 
     @Override
     public String toString() {
-        StringBuffer str = new StringBuffer(linkProperties.toString());
+        StringBuffer str = new StringBuffer(super.toString());
 
         str.append(" DHCP server ").append(serverAddress);
         str.append(" Vendor info ").append(vendorInfo);
@@ -119,58 +112,19 @@
 
         DhcpResults target = (DhcpResults)obj;
 
-        if (linkProperties == null) {
-            if (target.linkProperties != null) return false;
-        } else if (!linkProperties.equals(target.linkProperties)) return false;
-        if (serverAddress == null) {
-            if (target.serverAddress != null) return false;
-        } else if (!serverAddress.equals(target.serverAddress)) return false;
-        if (vendorInfo == null) {
-            if (target.vendorInfo != null) return false;
-        } else if (!vendorInfo.equals(target.vendorInfo)) return false;
-        if (leaseDuration != target.leaseDuration) return false;
-
-        return true;
-    }
-
-    /** Implement the Parcelable interface */
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface */
-    public void writeToParcel(Parcel dest, int flags) {
-        linkProperties.writeToParcel(dest, flags);
-
-        dest.writeInt(leaseDuration);
-
-        if (serverAddress != null) {
-            dest.writeByte((byte)1);
-            dest.writeByteArray(serverAddress.getAddress());
-        } else {
-            dest.writeByte((byte)0);
-        }
-
-        dest.writeString(vendorInfo);
+        return super.equals((StaticIpConfiguration) obj) &&
+                Objects.equals(serverAddress, target.serverAddress) &&
+                Objects.equals(vendorInfo, target.vendorInfo) &&
+                leaseDuration == target.leaseDuration;
     }
 
     /** Implement the Parcelable interface */
     public static final Creator<DhcpResults> CREATOR =
         new Creator<DhcpResults>() {
             public DhcpResults createFromParcel(Parcel in) {
-                DhcpResults prop = new DhcpResults((LinkProperties)in.readParcelable(null));
-
-                prop.leaseDuration = in.readInt();
-
-                if (in.readByte() == 1) {
-                    try {
-                        prop.serverAddress = InetAddress.getByAddress(in.createByteArray());
-                    } catch (UnknownHostException e) {}
-                }
-
-                prop.vendorInfo = in.readString();
-
-                return prop;
+                DhcpResults dhcpResults = new DhcpResults();
+                readFromParcel(dhcpResults, in);
+                return dhcpResults;
             }
 
             public DhcpResults[] newArray(int size) {
@@ -178,33 +132,39 @@
             }
         };
 
-    // Utils for jni population - false on success
-    public void setInterfaceName(String interfaceName) {
-        linkProperties.setInterfaceName(interfaceName);
+    /** Implement the Parcelable interface */
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(leaseDuration);
+        NetworkUtils.parcelInetAddress(dest, serverAddress, flags);
+        dest.writeString(vendorInfo);
     }
 
-    public boolean addLinkAddress(String addrString, int prefixLength) {
-        InetAddress addr;
+    private static void readFromParcel(DhcpResults dhcpResults, Parcel in) {
+        StaticIpConfiguration.readFromParcel(dhcpResults, in);
+        dhcpResults.leaseDuration = in.readInt();
+        dhcpResults.serverAddress = NetworkUtils.unparcelInetAddress(in);
+        dhcpResults.vendorInfo = in.readString();
+    }
+
+    // Utils for jni population - false on success
+    // Not part of the superclass because they're only used by the JNI iterface to the DHCP daemon.
+    public boolean setIpAddress(String addrString, int prefixLength) {
         try {
-            addr = NetworkUtils.numericToInetAddress(addrString);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "addLinkAddress failed with addrString " + addrString);
+            Inet4Address addr = (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
+            ipAddress = new LinkAddress(addr, prefixLength);
+        } catch (IllegalArgumentException|ClassCastException e) {
+            Log.e(TAG, "setIpAddress failed with addrString " + addrString + "/" + prefixLength);
             return true;
         }
-
-        LinkAddress linkAddress = new LinkAddress(addr, prefixLength);
-        linkProperties.addLinkAddress(linkAddress);
-
-        RouteInfo routeInfo = new RouteInfo(linkAddress);
-        linkProperties.addRoute(routeInfo);
         return false;
     }
 
-    public boolean addGateway(String addrString) {
+    public boolean setGateway(String addrString) {
         try {
-            linkProperties.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(addrString)));
+            gateway = NetworkUtils.numericToInetAddress(addrString);
         } catch (IllegalArgumentException e) {
-            Log.e(TAG, "addGateway failed with addrString " + addrString);
+            Log.e(TAG, "setGateway failed with addrString " + addrString);
             return true;
         }
         return false;
@@ -213,7 +173,7 @@
     public boolean addDns(String addrString) {
         if (TextUtils.isEmpty(addrString) == false) {
             try {
-                linkProperties.addDnsServer(NetworkUtils.numericToInetAddress(addrString));
+                dnsServers.add(NetworkUtils.numericToInetAddress(addrString));
             } catch (IllegalArgumentException e) {
                 Log.e(TAG, "addDns failed with addrString " + addrString);
                 return true;
@@ -241,6 +201,6 @@
     }
 
     public void setDomains(String domains) {
-        linkProperties.setDomains(domains);
+        domains = domains;
     }
 }
diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
index 608ca28..d965f27 100644
--- a/core/java/android/net/EthernetManager.java
+++ b/core/java/android/net/EthernetManager.java
@@ -21,7 +21,6 @@
 import android.net.IpConfiguration;
 import android.net.IpConfiguration.IpAssignment;
 import android.net.IpConfiguration.ProxySettings;
-import android.net.LinkProperties;
 import android.os.RemoteException;
 
 /**
@@ -52,16 +51,12 @@
      */
     public IpConfiguration getConfiguration() {
         if (mService == null) {
-            return new IpConfiguration(IpAssignment.UNASSIGNED,
-                                       ProxySettings.UNASSIGNED,
-                                       new LinkProperties());
+            return new IpConfiguration();
         }
         try {
             return mService.getConfiguration();
         } catch (RemoteException e) {
-            return new IpConfiguration(IpAssignment.UNASSIGNED,
-                                       ProxySettings.UNASSIGNED,
-                                       new LinkProperties());
+            return new IpConfiguration();
         }
     }
 
diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java
index 4730bab..fe69f296 100644
--- a/core/java/android/net/IpConfiguration.java
+++ b/core/java/android/net/IpConfiguration.java
@@ -16,7 +16,7 @@
 
 package android.net;
 
-import android.net.LinkProperties;
+import android.net.StaticIpConfiguration;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -31,7 +31,7 @@
 
     public enum IpAssignment {
         /* Use statically configured IP settings. Configuration can be accessed
-         * with linkProperties */
+         * with staticIpConfiguration */
         STATIC,
         /* Use dynamically configured IP settigns */
         DHCP,
@@ -42,12 +42,14 @@
 
     public IpAssignment ipAssignment;
 
+    public StaticIpConfiguration staticIpConfiguration;
+
     public enum ProxySettings {
         /* No proxy is to be used. Any existing proxy settings
          * should be cleared. */
         NONE,
         /* Use statically configured proxy. Configuration can be accessed
-         * with linkProperties */
+         * with httpProxy. */
         STATIC,
         /* no proxy details are assigned, this is used to indicate
          * that any existing proxy settings should be retained */
@@ -59,30 +61,69 @@
 
     public ProxySettings proxySettings;
 
-    public LinkProperties linkProperties;
+    public ProxyInfo httpProxy;
 
-    public IpConfiguration(IpConfiguration source) {
-        if (source != null) {
-            ipAssignment = source.ipAssignment;
-            proxySettings = source.proxySettings;
-            linkProperties = new LinkProperties(source.linkProperties);
-        } else {
-            ipAssignment = IpAssignment.UNASSIGNED;
-            proxySettings = ProxySettings.UNASSIGNED;
-            linkProperties = new LinkProperties();
-        }
+    private void init(IpAssignment ipAssignment,
+                      ProxySettings proxySettings,
+                      StaticIpConfiguration staticIpConfiguration,
+                      ProxyInfo httpProxy) {
+        this.ipAssignment = ipAssignment;
+        this.proxySettings = proxySettings;
+        this.staticIpConfiguration = (staticIpConfiguration == null) ?
+                null : new StaticIpConfiguration(staticIpConfiguration);
+        this.httpProxy = (httpProxy == null) ?
+                null : new ProxyInfo(httpProxy);
     }
 
     public IpConfiguration() {
-         this(null);
+        init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null);
     }
 
     public IpConfiguration(IpAssignment ipAssignment,
                            ProxySettings proxySettings,
-                           LinkProperties linkProperties) {
+                           StaticIpConfiguration staticIpConfiguration,
+                           ProxyInfo httpProxy) {
+        init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy);
+    }
+
+    public IpConfiguration(IpConfiguration source) {
+        this();
+        if (source != null) {
+            init(source.ipAssignment, source.proxySettings,
+                 source.staticIpConfiguration, source.httpProxy);
+        }
+    }
+
+    public IpAssignment getIpAssignment() {
+        return ipAssignment;
+    }
+
+    public void setIpAssignment(IpAssignment ipAssignment) {
         this.ipAssignment = ipAssignment;
+    }
+
+    public StaticIpConfiguration getStaticIpConfiguration() {
+        return staticIpConfiguration;
+    }
+
+    public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) {
+        this.staticIpConfiguration = staticIpConfiguration;
+    }
+
+    public ProxySettings getProxySettings() {
+        return proxySettings;
+    }
+
+    public void setProxySettings(ProxySettings proxySettings) {
         this.proxySettings = proxySettings;
-        this.linkProperties = new LinkProperties(linkProperties);
+    }
+
+    public ProxyInfo getHttpProxy() {
+        return httpProxy;
+    }
+
+    public void setHttpProxy(ProxyInfo httpProxy) {
+        this.httpProxy = httpProxy;
     }
 
     @Override
@@ -90,10 +131,16 @@
         StringBuilder sbuf = new StringBuilder();
         sbuf.append("IP assignment: " + ipAssignment.toString());
         sbuf.append("\n");
+        if (staticIpConfiguration != null) {
+            sbuf.append("Static configuration: " + staticIpConfiguration.toString());
+            sbuf.append("\n");
+        }
         sbuf.append("Proxy settings: " + proxySettings.toString());
         sbuf.append("\n");
-        sbuf.append(linkProperties.toString());
-        sbuf.append("\n");
+        if (httpProxy != null) {
+            sbuf.append("HTTP proxy: " + httpProxy.toString());
+            sbuf.append("\n");
+        }
 
         return sbuf.toString();
     }
@@ -111,14 +158,16 @@
         IpConfiguration other = (IpConfiguration) o;
         return this.ipAssignment == other.ipAssignment &&
                 this.proxySettings == other.proxySettings &&
-                Objects.equals(this.linkProperties, other.linkProperties);
+                Objects.equals(this.staticIpConfiguration, other.staticIpConfiguration) &&
+                Objects.equals(this.httpProxy, other.httpProxy);
     }
 
     @Override
     public int hashCode() {
-        return 13 + (linkProperties != null ? linkProperties.hashCode() : 0) +
+        return 13 + (staticIpConfiguration != null ? staticIpConfiguration.hashCode() : 0) +
                17 * ipAssignment.ordinal() +
-               47 * proxySettings.ordinal();
+               47 * proxySettings.ordinal() +
+               83 * httpProxy.hashCode();
     }
 
     /** Implement the Parcelable interface */
@@ -130,7 +179,8 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(ipAssignment.name());
         dest.writeString(proxySettings.name());
-        dest.writeParcelable(linkProperties, flags);
+        dest.writeParcelable(staticIpConfiguration, flags);
+        dest.writeParcelable(httpProxy, flags);
     }
 
     /** Implement the Parcelable interface */
@@ -140,7 +190,8 @@
                 IpConfiguration config = new IpConfiguration();
                 config.ipAssignment = IpAssignment.valueOf(in.readString());
                 config.proxySettings = ProxySettings.valueOf(in.readString());
-                config.linkProperties = in.readParcelable(null);
+                config.staticIpConfiguration = in.readParcelable(null);
+                config.httpProxy = in.readParcelable(null);
                 return config;
             }
 
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 663aa15..54d8676 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -23,6 +23,7 @@
 import java.util.Collection;
 import java.util.Locale;
 
+import android.os.Parcel;
 import android.util.Log;
 import android.util.Pair;
 
@@ -203,6 +204,32 @@
     }
 
     /**
+     * Writes an InetAddress to a parcel. The address may be null. This is likely faster than
+     * calling writeSerializable.
+     */
+    protected static void parcelInetAddress(Parcel parcel, InetAddress address, int flags) {
+        byte[] addressArray = (address != null) ? address.getAddress() : null;
+        parcel.writeByteArray(addressArray);
+    }
+
+    /**
+     * Reads an InetAddress from a parcel. Returns null if the address that was written was null
+     * or if the data is invalid.
+     */
+    protected static InetAddress unparcelInetAddress(Parcel in) {
+        byte[] addressArray = in.createByteArray();
+        if (addressArray == null) {
+            return null;
+        }
+        try {
+            return InetAddress.getByAddress(addressArray);
+        } catch (UnknownHostException e) {
+            return null;
+        }
+    }
+
+
+    /**
      *  Masks a raw IP address byte array with the specified prefix length.
      */
     public static void maskRawAddress(byte[] array, int prefixLength) {
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 12e8791..b0278d3 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -135,8 +135,7 @@
      * disabled, using an optional handshake timeout and SSL session cache.
      *
      * <p class="caution"><b>Warning:</b> Sockets created using this factory
-     * are vulnerable to man-in-the-middle attacks!</p>. The caller must implement
-     * its own verification.
+     * are vulnerable to man-in-the-middle attacks!</p>
      *
      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
      *         for none.  The socket timeout is reset to 0 after the handshake.
@@ -224,6 +223,8 @@
             if (mInsecureFactory == null) {
                 if (mSecure) {
                     Log.w(TAG, "*** BYPASSING SSL SECURITY CHECKS (socket.relaxsslcheck=yes) ***");
+                } else {
+                    Log.w(TAG, "Bypassing SSL security checks at caller's request");
                 }
                 mInsecureFactory = makeSocketFactory(mKeyManagers, INSECURE_TRUST_MANAGER);
             }
@@ -430,7 +431,6 @@
         s.setAlpnProtocols(mAlpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
-        s.setHostname(host);
         if (mSecure) {
             verifyHostname(s, host);
         }
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
new file mode 100644
index 0000000..5a273cf
--- /dev/null
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -0,0 +1,194 @@
+/*
+ * 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.net;
+
+import android.net.LinkAddress;
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Class that describes static IP configuration.
+ *
+ * This class is different from LinkProperties because it represents
+ * configuration intent. The general contract is that if we can represent
+ * a configuration here, then we should be able to configure it on a network.
+ * The intent is that it closely match the UI we have for configuring networks.
+ *
+ * In contrast, LinkProperties represents current state. It is much more
+ * expressive. For example, it supports multiple IP addresses, multiple routes,
+ * stacked interfaces, and so on. Because LinkProperties is so expressive,
+ * using it to represent configuration intent as well as current state causes
+ * problems. For example, we could unknowingly save a configuration that we are
+ * not in fact capable of applying, or we could save a configuration that the
+ * UI cannot display, which has the potential for malicious code to hide
+ * hostile or unexpected configuration from the user: see, for example,
+ * http://b/12663469 and http://b/16893413 .
+ *
+ * @hide
+ */
+public class StaticIpConfiguration implements Parcelable {
+    public LinkAddress ipAddress;
+    public InetAddress gateway;
+    public final ArrayList<InetAddress> dnsServers;
+    public String domains;
+
+    public StaticIpConfiguration() {
+        dnsServers = new ArrayList<InetAddress>();
+    }
+
+    public StaticIpConfiguration(StaticIpConfiguration source) {
+        this();
+        if (source != null) {
+            // All of these except dnsServers are immutable, so no need to make copies.
+            ipAddress = source.ipAddress;
+            gateway = source.gateway;
+            dnsServers.addAll(source.dnsServers);
+            domains = source.domains;
+        }
+    }
+
+    public void clear() {
+        ipAddress = null;
+        gateway = null;
+        dnsServers.clear();
+        domains = null;
+    }
+
+    /**
+     * Returns the network routes specified by this object. Will typically include a
+     * directly-connected route for the IP address's local subnet and a default route.
+     */
+    public List<RouteInfo> getRoutes(String iface) {
+        List<RouteInfo> routes = new ArrayList<RouteInfo>(2);
+        if (ipAddress != null) {
+            routes.add(new RouteInfo(ipAddress, null, iface));
+        }
+        if (gateway != null) {
+            routes.add(new RouteInfo((LinkAddress) null, gateway, iface));
+        }
+        return routes;
+    }
+
+    /**
+     * Returns a LinkProperties object expressing the data in this object. Note that the information
+     * contained in the LinkProperties will not be a complete picture of the link's configuration,
+     * because any configuration information that is obtained dynamically by the network (e.g.,
+     * IPv6 configuration) will not be included.
+     */
+    public LinkProperties toLinkProperties(String iface) {
+        LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(iface);
+        if (ipAddress != null) {
+            lp.addLinkAddress(ipAddress);
+        }
+        for (RouteInfo route : getRoutes(iface)) {
+            lp.addRoute(route);
+        }
+        for (InetAddress dns : dnsServers) {
+            lp.addDnsServer(dns);
+        }
+        return lp;
+    }
+
+    public String toString() {
+        StringBuffer str = new StringBuffer();
+
+        str.append("IP address ");
+        if (ipAddress != null ) str.append(ipAddress).append(" ");
+
+        str.append("Gateway ");
+        if (gateway != null) str.append(gateway.getHostAddress()).append(" ");
+
+        str.append(" DNS servers: [");
+        for (InetAddress dnsServer : dnsServers) {
+            str.append(" ").append(dnsServer.getHostAddress());
+        }
+
+        str.append(" ] Domains");
+        if (domains != null) str.append(domains);
+        return str.toString();
+    }
+
+    public int hashCode() {
+        int result = 13;
+        result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode());
+        result = 47 * result + (gateway == null ? 0 : gateway.hashCode());
+        result = 47 * result + (domains == null ? 0 : domains.hashCode());
+        result = 47 * result + dnsServers.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+
+        if (!(obj instanceof StaticIpConfiguration)) return false;
+
+        StaticIpConfiguration other = (StaticIpConfiguration) obj;
+
+        return other != null &&
+                Objects.equals(ipAddress, other.ipAddress) &&
+                Objects.equals(gateway, other.gateway) &&
+                dnsServers.equals(other.dnsServers) &&
+                Objects.equals(domains, other.domains);
+    }
+
+    /** Implement the Parcelable interface */
+    public static Creator<StaticIpConfiguration> CREATOR =
+        new Creator<StaticIpConfiguration>() {
+            public StaticIpConfiguration createFromParcel(Parcel in) {
+                StaticIpConfiguration s = new StaticIpConfiguration();
+                readFromParcel(s, in);
+                return s;
+            }
+
+            public StaticIpConfiguration[] newArray(int size) {
+                return new StaticIpConfiguration[size];
+            }
+        };
+
+    /** Implement the Parcelable interface */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(ipAddress, flags);
+        NetworkUtils.parcelInetAddress(dest, gateway, flags);
+        dest.writeInt(dnsServers.size());
+        for (InetAddress dnsServer : dnsServers) {
+            NetworkUtils.parcelInetAddress(dest, dnsServer, flags);
+        }
+    }
+
+    protected static void readFromParcel(StaticIpConfiguration s, Parcel in) {
+        s.ipAddress = in.readParcelable(null);
+        s.gateway = NetworkUtils.unparcelInetAddress(in);
+        s.dnsServers.clear();
+        int size = in.readInt();
+        for (int i = 0; i < size; i++) {
+            s.dnsServers.add(NetworkUtils.unparcelInetAddress(in));
+        }
+    }
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 7d086e1..fe9f79b 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1843,13 +1843,21 @@
         }
         pw.println();
     }
-    
+
+    /**
+     * Temporary for settings.
+     */
+    public final void dumpCheckinLocked(Context context, PrintWriter pw, int which, int reqUid) {
+        dumpCheckinLocked(context, pw, which, reqUid, BatteryStatsHelper.checkWifiOnly(context));
+    }
+
     /**
      * Checkin server version of dump to produce more compact, computer-readable log.
      * 
      * NOTE: all times are expressed in 'ms'.
      */
-    public final void dumpCheckinLocked(Context context, PrintWriter pw, int which, int reqUid) {
+    public final void dumpCheckinLocked(Context context, PrintWriter pw, int which, int reqUid,
+            boolean wifiOnly) {
         final long rawUptime = SystemClock.uptimeMillis() * 1000;
         final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
         final long batteryUptime = getBatteryUptime(rawUptime);
@@ -2046,7 +2054,7 @@
             }
         }
         
-        BatteryStatsHelper helper = new BatteryStatsHelper(context, false);
+        BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
         helper.create(this);
         helper.refreshStats(which, UserHandle.USER_ALL);
         List<BatterySipper> sippers = helper.getUsageList();
@@ -2315,9 +2323,17 @@
         printer.print(BatteryStatsHelper.makemAh(power));
     }
 
+    /**
+     * Temporary for settings.
+     */
+    public final void dumpLocked(Context context, PrintWriter pw, String prefix, int which,
+            int reqUid) {
+        dumpLocked(context, pw, prefix, which, reqUid, BatteryStatsHelper.checkWifiOnly(context));
+    }
+
     @SuppressWarnings("unused")
     public final void dumpLocked(Context context, PrintWriter pw, String prefix, final int which,
-            int reqUid) {
+            int reqUid, boolean wifiOnly) {
         final long rawUptime = SystemClock.uptimeMillis() * 1000;
         final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
         final long batteryUptime = getBatteryUptime(rawUptime);
@@ -2746,7 +2762,7 @@
             pw.println();
         }
 
-        BatteryStatsHelper helper = new BatteryStatsHelper(context, false);
+        BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
         helper.create(this);
         helper.refreshStats(which, UserHandle.USER_ALL);
         List<BatterySipper> sippers = helper.getUsageList();
@@ -3049,7 +3065,7 @@
                             "partial", which, linePrefix);
                     linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), rawRealtime,
                             "window", which, linePrefix);
-                    if (!linePrefix.equals(": ")) {
+                    if (true || !linePrefix.equals(": ")) {
                         sb.append(" realtime");
                         // Only print out wake locks that were held
                         pw.println(sb.toString());
@@ -3723,6 +3739,7 @@
     public static final int DUMP_HISTORY_ONLY = 1<<2;
     public static final int DUMP_INCLUDE_HISTORY = 1<<3;
     public static final int DUMP_VERBOSE = 1<<4;
+    public static final int DUMP_DEVICE_WIFI_ONLY = 1<<5;
 
     private void dumpHistoryLocked(PrintWriter pw, int flags, long histStart, boolean checkin) {
         final HistoryPrinter hprinter = new HistoryPrinter();
@@ -3918,12 +3935,14 @@
             pw.println("Statistics since last charge:");
             pw.println("  System starts: " + getStartCount()
                     + ", currently on battery: " + getIsOnBattery());
-            dumpLocked(context, pw, "", STATS_SINCE_CHARGED, reqUid);
+            dumpLocked(context, pw, "", STATS_SINCE_CHARGED, reqUid,
+                    (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
             pw.println();
         }
         if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) {
             pw.println("Statistics since last unplugged:");
-            dumpLocked(context, pw, "", STATS_SINCE_UNPLUGGED, reqUid);
+            dumpLocked(context, pw, "", STATS_SINCE_UNPLUGGED, reqUid,
+                    (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
         }
     }
     
@@ -4013,10 +4032,12 @@
                 dumpLine(pw, 0 /* uid */, "i" /* category */, CHARGE_TIME_REMAIN_DATA,
                         (Object[])lineArgs);
             }
-            dumpCheckinLocked(context, pw, STATS_SINCE_CHARGED, -1);
+            dumpCheckinLocked(context, pw, STATS_SINCE_CHARGED, -1,
+                    (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
         }
         if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) {
-            dumpCheckinLocked(context, pw, STATS_SINCE_UNPLUGGED, -1);
+            dumpCheckinLocked(context, pw, STATS_SINCE_UNPLUGGED, -1,
+                    (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
         }
     }
 }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 9d1a7bc..5189155 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -973,7 +973,7 @@
 
         if (badgeLocation != null) {
             if (badgeLocation.left < 0 || badgeLocation.top < 0
-                    || badgeLocation.right > badgedWidth || badgeLocation.bottom > badgedHeight) {
+                    || badgeLocation.width() > badgedWidth || badgeLocation.height() > badgedHeight) {
                 throw new IllegalArgumentException("Badge location " + badgeLocation
                         + " not in badged drawable bounds "
                         + new Rect(0, 0, badgedWidth, badgedHeight));
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 68b91cb..4cdafe1 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -619,6 +619,16 @@
     private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
 
     /**
+     * Return the number of available bytes until the given path is considered
+     * running low on storage.
+     *
+     * @hide
+     */
+    public long getStorageBytesUntilLow(File path) {
+        return path.getUsableSpace() - getStorageFullBytes(path);
+    }
+
+    /**
      * Return the number of available bytes at which the given path is
      * considered running low on storage.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cfa7ae7..52f1dd9 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -305,7 +305,7 @@
 
     /**
      * Activity Action: Show settings to allow configuration of
-     * {@link android.media.routing.MediaRouteService media route providers}.
+     * cast endpoints.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
      * safeguard against this.
@@ -3546,6 +3546,13 @@
         public static final String DISABLED_SYSTEM_INPUT_METHODS = "disabled_system_input_methods";
 
         /**
+         * Whether to show the IME when a hard keyboard is connected. This is a boolean that
+         * determines if the IME should be shown when a hard keyboard is attached.
+         * @hide
+         */
+        public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard";
+
+        /**
          * Host name and port for global http proxy. Uses ':' seperator for
          * between host and port.
          *
@@ -5132,6 +5139,13 @@
         public static final String UNLOCK_SOUND = "unlock_sound";
 
         /**
+         * URI for the "device is trusted" sound, which is played when the device enters the trusted
+         * state without unlocking.
+         * @hide
+         */
+        public static final String TRUSTED_SOUND = "trusted_sound";
+
+        /**
          * URI for the low battery sound file.
          * @hide
          */
@@ -5176,6 +5190,12 @@
         public static final String ADB_ENABLED = "adb_enabled";
 
         /**
+         * Whether Views are allowed to save their attribute data.
+         * @hide
+         */
+        public static final String DEBUG_VIEW_ATTRIBUTES = "debug_view_attributes";
+
+        /**
          * Whether assisted GPS should be enabled or not.
          * @hide
          */
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
index efcbdb3..6246cbe 100644
--- a/core/java/android/transition/ChangeBounds.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -16,13 +16,11 @@
 
 package android.transition;
 
-import android.animation.TypeConverter;
 import android.content.Context;
 import android.graphics.PointF;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.RectEvaluator;
@@ -119,9 +117,11 @@
         values.values.put(PROPNAME_BOUNDS, new Rect(view.getLeft(), view.getTop(),
                 view.getRight(), view.getBottom()));
         values.values.put(PROPNAME_PARENT, values.view.getParent());
-        values.view.getLocationInWindow(tempLocation);
-        values.values.put(PROPNAME_WINDOW_X, tempLocation[0]);
-        values.values.put(PROPNAME_WINDOW_Y, tempLocation[1]);
+        if (mReparent) {
+            values.view.getLocationInWindow(tempLocation);
+            values.values.put(PROPNAME_WINDOW_X, tempLocation[0]);
+            values.values.put(PROPNAME_WINDOW_Y, tempLocation[1]);
+        }
     }
 
     @Override
@@ -134,6 +134,19 @@
         captureValues(transitionValues);
     }
 
+    private boolean parentMatches(View startParent, View endParent) {
+        boolean parentMatches = true;
+        if (mReparent) {
+            TransitionValues endValues = getMatchedTransitionValues(startParent, true);
+            if (endValues == null) {
+                parentMatches = startParent == endParent;
+            } else {
+                parentMatches = endParent == endValues.view;
+            }
+        }
+        return parentMatches;
+    }
+
     @Override
     public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues,
             TransitionValues endValues) {
@@ -148,13 +161,7 @@
             return null;
         }
         final View view = endValues.view;
-        boolean parentsEqual = (startParent == endParent) ||
-                (startParent.getId() == endParent.getId());
-        // TODO: Might want reparenting to be separate/subclass transition, or at least
-        // triggered by a property on ChangeBounds. Otherwise, we're forcing the requirement that
-        // all parents in layouts have IDs to avoid layout-inflation resulting in a side-effect
-        // of reparenting the views.
-        if (!mReparent || parentsEqual) {
+        if (parentMatches(startParent, endParent)) {
             Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
             Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
             int startLeft = startBounds.left;
diff --git a/core/java/android/transition/ChangeImageTransform.java b/core/java/android/transition/ChangeImageTransform.java
index 2b26756..4b230eb 100644
--- a/core/java/android/transition/ChangeImageTransform.java
+++ b/core/java/android/transition/ChangeImageTransform.java
@@ -182,6 +182,7 @@
             if (endMatrix == null) {
                 endMatrix = Matrix.IDENTITY_MATRIX;
             }
+            ANIMATED_TRANSFORM_PROPERTY.set(imageView, startMatrix);
             animator = createMatrixAnimator(imageView, startMatrix, endMatrix);
         }
         return animator;
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 2fa8d2a..0d32d40 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -192,6 +192,8 @@
     private TransitionValuesMaps mEndValues = new TransitionValuesMaps();
     TransitionSet mParent = null;
     private int[] mMatchOrder = DEFAULT_MATCH_ORDER;
+    ArrayList<TransitionValues> mStartValuesList; // only valid after playTransition starts
+    ArrayList<TransitionValues> mEndValuesList; // only valid after playTransitions starts
 
     // Per-animator information used for later canceling when future transitions overlap
     private static ThreadLocal<ArrayMap<Animator, AnimationInfo>> sRunningAnimators =
@@ -518,32 +520,28 @@
     }
 
     /**
-     * Match start/end values by View instance. Adds matched values to startValuesList
-     * and endValuesList and removes them from unmatchedStart and unmatchedEnd.
+     * Match start/end values by View instance. Adds matched values to mStartValuesList
+     * and mEndValuesList and removes them from unmatchedStart and unmatchedEnd.
      */
-    private void matchInstances(ArrayList<TransitionValues> startValuesList,
-            ArrayList<TransitionValues> endValuesList,
-            ArrayMap<View, TransitionValues> unmatchedStart,
+    private void matchInstances(ArrayMap<View, TransitionValues> unmatchedStart,
             ArrayMap<View, TransitionValues> unmatchedEnd) {
         for (int i = unmatchedStart.size() - 1; i >= 0; i--) {
             View view = unmatchedStart.keyAt(i);
             TransitionValues end = unmatchedEnd.remove(view);
             if (end != null) {
                 TransitionValues start = unmatchedStart.removeAt(i);
-                startValuesList.add(start);
-                endValuesList.add(end);
+                mStartValuesList.add(start);
+                mEndValuesList.add(end);
             }
         }
     }
 
     /**
-     * Match start/end values by Adapter item ID. Adds matched values to startValuesList
-     * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+     * Match start/end values by Adapter item ID. Adds matched values to mStartValuesList
+     * and mEndValuesList and removes them from unmatchedStart and unmatchedEnd, using
      * startItemIds and endItemIds as a guide for which Views have unique item IDs.
      */
-    private void matchItemIds(ArrayList<TransitionValues> startValuesList,
-            ArrayList<TransitionValues> endValuesList,
-            ArrayMap<View, TransitionValues> unmatchedStart,
+    private void matchItemIds(ArrayMap<View, TransitionValues> unmatchedStart,
             ArrayMap<View, TransitionValues> unmatchedEnd,
             LongSparseArray<View> startItemIds, LongSparseArray<View> endItemIds) {
         int numStartIds = startItemIds.size();
@@ -555,8 +553,8 @@
                     TransitionValues startValues = unmatchedStart.get(startView);
                     TransitionValues endValues = unmatchedEnd.get(endView);
                     if (startValues != null && endValues != null) {
-                        startValuesList.add(startValues);
-                        endValuesList.add(endValues);
+                        mStartValuesList.add(startValues);
+                        mEndValuesList.add(endValues);
                         unmatchedStart.remove(startView);
                         unmatchedEnd.remove(endView);
                     }
@@ -566,13 +564,11 @@
     }
 
     /**
-     * Match start/end values by Adapter view ID. Adds matched values to startValuesList
-     * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+     * Match start/end values by Adapter view ID. Adds matched values to mStartValuesList
+     * and mEndValuesList and removes them from unmatchedStart and unmatchedEnd, using
      * startIds and endIds as a guide for which Views have unique IDs.
      */
-    private void matchIds(ArrayList<TransitionValues> startValuesList,
-            ArrayList<TransitionValues> endValuesList,
-            ArrayMap<View, TransitionValues> unmatchedStart,
+    private void matchIds(ArrayMap<View, TransitionValues> unmatchedStart,
             ArrayMap<View, TransitionValues> unmatchedEnd,
             SparseArray<View> startIds, SparseArray<View> endIds) {
         int numStartIds = startIds.size();
@@ -584,8 +580,8 @@
                     TransitionValues startValues = unmatchedStart.get(startView);
                     TransitionValues endValues = unmatchedEnd.get(endView);
                     if (startValues != null && endValues != null) {
-                        startValuesList.add(startValues);
-                        endValuesList.add(endValues);
+                        mStartValuesList.add(startValues);
+                        mEndValuesList.add(endValues);
                         unmatchedStart.remove(startView);
                         unmatchedEnd.remove(endView);
                     }
@@ -595,13 +591,11 @@
     }
 
     /**
-     * Match start/end values by Adapter transitionName. Adds matched values to startValuesList
-     * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+     * Match start/end values by Adapter transitionName. Adds matched values to mStartValuesList
+     * and mEndValuesList and removes them from unmatchedStart and unmatchedEnd, using
      * startNames and endNames as a guide for which Views have unique transitionNames.
      */
-    private void matchNames(ArrayList<TransitionValues> startValuesList,
-            ArrayList<TransitionValues> endValuesList,
-            ArrayMap<View, TransitionValues> unmatchedStart,
+    private void matchNames(ArrayMap<View, TransitionValues> unmatchedStart,
             ArrayMap<View, TransitionValues> unmatchedEnd,
             ArrayMap<String, View> startNames, ArrayMap<String, View> endNames) {
         int numStartNames = startNames.size();
@@ -613,8 +607,8 @@
                     TransitionValues startValues = unmatchedStart.get(startView);
                     TransitionValues endValues = unmatchedEnd.get(endView);
                     if (startValues != null && endValues != null) {
-                        startValuesList.add(startValues);
-                        endValuesList.add(endValues);
+                        mStartValuesList.add(startValues);
+                        mEndValuesList.add(endValues);
                         unmatchedStart.remove(startView);
                         unmatchedEnd.remove(endView);
                     }
@@ -624,30 +618,26 @@
     }
 
     /**
-     * Adds all values from unmatchedStart and unmatchedEnd to startValuesList and endValuesList,
+     * Adds all values from unmatchedStart and unmatchedEnd to mStartValuesList and mEndValuesList,
      * assuming that there is no match between values in the list.
      */
-    private void addUnmatched(ArrayList<TransitionValues> startValuesList,
-            ArrayList<TransitionValues> endValuesList,
-            ArrayMap<View, TransitionValues> unmatchedStart,
+    private void addUnmatched(ArrayMap<View, TransitionValues> unmatchedStart,
             ArrayMap<View, TransitionValues> unmatchedEnd) {
         // Views that only exist in the start Scene
         for (int i = 0; i < unmatchedStart.size(); i++) {
-            startValuesList.add(unmatchedStart.valueAt(i));
-            endValuesList.add(null);
+            mStartValuesList.add(unmatchedStart.valueAt(i));
+            mEndValuesList.add(null);
         }
 
         // Views that only exist in the end Scene
         for (int i = 0; i < unmatchedEnd.size(); i++) {
-            endValuesList.add(unmatchedEnd.valueAt(i));
-            startValuesList.add(null);
+            mEndValuesList.add(unmatchedEnd.valueAt(i));
+            mStartValuesList.add(null);
         }
     }
 
     private void matchStartAndEnd(TransitionValuesMaps startValues,
-            TransitionValuesMaps endValues,
-            ArrayList<TransitionValues> startValuesList,
-            ArrayList<TransitionValues> endValuesList) {
+            TransitionValuesMaps endValues) {
         ArrayMap<View, TransitionValues> unmatchedStart =
                 new ArrayMap<View, TransitionValues>(startValues.viewValues);
         ArrayMap<View, TransitionValues> unmatchedEnd =
@@ -656,23 +646,23 @@
         for (int i = 0; i < mMatchOrder.length; i++) {
             switch (mMatchOrder[i]) {
                 case MATCH_INSTANCE:
-                    matchInstances(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
+                    matchInstances(unmatchedStart, unmatchedEnd);
                     break;
                 case MATCH_NAME:
-                    matchNames(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+                    matchNames(unmatchedStart, unmatchedEnd,
                             startValues.nameValues, endValues.nameValues);
                     break;
                 case MATCH_ID:
-                    matchIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+                    matchIds(unmatchedStart, unmatchedEnd,
                             startValues.idValues, endValues.idValues);
                     break;
                 case MATCH_ITEM_ID:
-                    matchItemIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+                    matchItemIds(unmatchedStart, unmatchedEnd,
                             startValues.itemIdValues, endValues.itemIdValues);
                     break;
             }
         }
-        addUnmatched(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
+        addUnmatched(unmatchedStart, unmatchedEnd);
     }
 
     /**
@@ -687,19 +677,17 @@
      * @hide
      */
     protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
-            TransitionValuesMaps endValues) {
+            TransitionValuesMaps endValues, ArrayList<TransitionValues> startValuesList,
+            ArrayList<TransitionValues> endValuesList) {
         if (DBG) {
             Log.d(LOG_TAG, "createAnimators() for " + this);
         }
-        ArrayList<TransitionValues> startValuesList = new ArrayList<TransitionValues>();
-        ArrayList<TransitionValues> endValuesList = new ArrayList<TransitionValues>();
-        matchStartAndEnd(startValues, endValues, startValuesList, endValuesList);
-
         ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
         long minStartDelay = Long.MAX_VALUE;
         int minAnimator = mAnimators.size();
         SparseLongArray startDelays = new SparseLongArray();
-        for (int i = 0; i < startValuesList.size(); ++i) {
+        int startValuesListCount = startValuesList.size();
+        for (int i = 0; i < startValuesListCount; ++i) {
             TransitionValues start = startValuesList.get(i);
             TransitionValues end = endValuesList.get(i);
             // Only bother trying to animate with valid values that differ between start/end
@@ -1523,11 +1511,13 @@
             mStartValues.idValues.clear();
             mStartValues.itemIdValues.clear();
             mStartValues.nameValues.clear();
+            mStartValuesList = null;
         } else {
             mEndValues.viewValues.clear();
             mEndValues.idValues.clear();
             mEndValues.itemIdValues.clear();
             mEndValues.nameValues.clear();
+            mEndValuesList = null;
         }
     }
 
@@ -1613,6 +1603,45 @@
     }
 
     /**
+     * Find the matched start or end value for a given View. This is only valid
+     * after playTransition starts. For example, it will be valid in
+     * {@link #createAnimator(android.view.ViewGroup, TransitionValues, TransitionValues)}, but not
+     * in {@link #captureStartValues(TransitionValues)}.
+     *
+     * @param view The view to find the match for.
+     * @param viewInStart Is View from the start values or end values.
+     * @return The matching TransitionValues for view in either start or end values, depending
+     * on viewInStart or null if there is no match for the given view.
+     */
+    TransitionValues getMatchedTransitionValues(View view, boolean viewInStart) {
+        if (mParent != null) {
+            return mParent.getMatchedTransitionValues(view, viewInStart);
+        }
+        ArrayList<TransitionValues> lookIn = viewInStart ? mStartValuesList : mEndValuesList;
+        if (lookIn == null) {
+            return null;
+        }
+        int count = lookIn.size();
+        int index = -1;
+        for (int i = 0; i < count; i++) {
+            TransitionValues values = lookIn.get(i);
+            if (values == null) {
+                return null;
+            }
+            if (values.view == view) {
+                index = i;
+                break;
+            }
+        }
+        TransitionValues values = null;
+        if (index >= 0) {
+            ArrayList<TransitionValues> matchIn = viewInStart ? mEndValuesList : mStartValuesList;
+            values = matchIn.get(index);
+        }
+        return values;
+    }
+
+    /**
      * Pauses this transition, sending out calls to {@link
      * TransitionListener#onTransitionPause(Transition)} to all listeners
      * and pausing all running animators started by this transition.
@@ -1684,6 +1713,10 @@
      * runAnimations() to actually start the animations.
      */
     void playTransition(ViewGroup sceneRoot) {
+        mStartValuesList = new ArrayList<TransitionValues>();
+        mEndValuesList = new ArrayList<TransitionValues>();
+        matchStartAndEnd(mStartValues, mEndValues);
+
         ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
         int numOldAnims = runningAnimators.size();
         WindowId windowId = sceneRoot.getWindowId();
@@ -1694,7 +1727,7 @@
                 if (oldInfo != null && oldInfo.view != null && oldInfo.windowId == windowId) {
                     TransitionValues oldValues = oldInfo.values;
                     View oldView = oldInfo.view;
-                    TransitionValues newValues = mEndValues.viewValues.get(oldView);
+                    TransitionValues newValues = getMatchedTransitionValues(oldView, true);
                     boolean cancel = oldInfo.transition.areValuesChanged(oldValues, newValues);
                     if (cancel) {
                         if (anim.isRunning() || anim.isStarted()) {
@@ -1713,7 +1746,7 @@
             }
         }
 
-        createAnimators(sceneRoot, mStartValues, mEndValues);
+        createAnimators(sceneRoot, mStartValues, mEndValues, mStartValuesList, mEndValuesList);
         runAnimators();
     }
 
@@ -2055,6 +2088,8 @@
             clone.mAnimators = new ArrayList<Animator>();
             clone.mStartValues = new TransitionValuesMaps();
             clone.mEndValues = new TransitionValuesMaps();
+            clone.mStartValuesList = null;
+            clone.mEndValuesList = null;
         } catch (CloneNotSupportedException e) {}
 
         return clone;
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 83c60af..f6499ae 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -151,6 +151,31 @@
     }
 
     /**
+     * Returns the number of child transitions in the TransitionSet.
+     *
+     * @return The number of child transitions in the TransitionSet.
+     * @see #addTransition(Transition)
+     * @see #getTransitionAt(int)
+     */
+    public int getTransitionCount() {
+        return mTransitions.size();
+    }
+
+    /**
+     * Returns the child Transition at the specified position in the TransitionSet.
+     *
+     * @param index The position of the Transition to retrieve.
+     * @see #addTransition(Transition)
+     * @see #getTransitionCount()
+     */
+    public Transition getTransitionAt(int index) {
+        if (index < 0 || index >= mTransitions.size()) {
+            return null;
+        }
+        return mTransitions.get(index);
+    }
+
+    /**
      * Setting a non-negative duration on a TransitionSet causes all of the child
      * transitions (current and future) to inherit this duration.
      *
@@ -361,11 +386,13 @@
      */
     @Override
     protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
-            TransitionValuesMaps endValues) {
+            TransitionValuesMaps endValues, ArrayList<TransitionValues> startValuesList,
+            ArrayList<TransitionValues> endValuesList) {
         startValues = removeExcludes(startValues);
         endValues = removeExcludes(endValues);
         for (Transition childTransition : mTransitions) {
-            childTransition.createAnimators(sceneRoot, startValues, endValues);
+            childTransition.createAnimators(sceneRoot, startValues, endValues, startValuesList,
+                    endValuesList);
         }
     }
 
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 2dfbcb5..e706c9c 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -258,8 +258,8 @@
     /**
      * Change both the numeric and alphabetic shortcut associated with this
      * item. Note that the shortcut will be triggered when the key that
-     * generates the given character is pressed alone or along with with the alt
-     * key. Also note that case is not significant and that alphabetic shortcut
+     * generates the given character is pressed along with the ctrl key.
+     * Also note that case is not significant and that alphabetic shortcut
      * characters will be displayed in lower case.
      * <p>
      * See {@link Menu} for the menu types that support shortcuts.
@@ -293,9 +293,9 @@
     /**
      * Change the alphabetic shortcut associated with this item. The shortcut
      * will be triggered when the key that generates the given character is
-     * pressed alone or along with with the alt key. Case is not significant and
-     * shortcut characters will be displayed in lower case. Note that menu items
-     * with the characters '\b' or '\n' as shortcuts will get triggered by the
+     * pressed along with the ctrl key. Case is not significant and shortcut
+     * characters will be displayed in lower case. Note that menu items with
+     * the characters '\b' or '\n' as shortcuts will get triggered by the
      * Delete key or Carriage Return key, respectively.
      * <p>
      * See {@link Menu} for the menu types that support shortcuts.
@@ -596,4 +596,4 @@
      * @return This menu item instance for call chaining
      */
     public MenuItem setOnActionExpandListener(OnActionExpandListener listener);
-}
\ No newline at end of file
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 01c7467..3adc41a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -89,7 +89,6 @@
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
 import com.android.internal.view.menu.MenuBuilder;
-
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -701,6 +700,13 @@
     public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout";
 
     /**
+     * When set to true, this view will save its attribute data.
+     *
+     * @hide
+     */
+    public static boolean mDebugViewAttributes = false;
+
+    /**
      * Used to mark a View that has no ID.
      */
     public static final int NO_ID = -1;
@@ -3255,6 +3261,7 @@
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
      */
+    @ViewDebug.ExportedProperty(deepExport = true)
     protected Context mContext;
 
     private final Resources mResources;
@@ -3525,6 +3532,18 @@
     GhostView mGhostView;
 
     /**
+     * Holds pairs of adjacent attribute data: attribute name followed by its value.
+     * @hide
+     */
+    @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true)
+    public String[] mAttributes;
+
+    /**
+     * Maps a Resource id to its name.
+     */
+    private static SparseArray<String> mAttributeMap;
+
+    /**
      * Simple constructor to use when creating a view from code.
      *
      * @param context The Context the view is running in, through which it can
@@ -3642,6 +3661,10 @@
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);
 
+        if (mDebugViewAttributes) {
+            saveAttributeData(attrs, a);
+        }
+
         Drawable background = null;
 
         int leftPadding = -1;
@@ -4137,6 +4160,51 @@
         mRenderNode = RenderNode.create(getClass().getName());
     }
 
+    private static SparseArray<String> getAttributeMap() {
+        if (mAttributeMap == null) {
+            mAttributeMap = new SparseArray<String>();
+        }
+        return mAttributeMap;
+    }
+
+    private void saveAttributeData(AttributeSet attrs, TypedArray a) {
+        int length = ((attrs == null ? 0 : attrs.getAttributeCount()) + a.getIndexCount()) * 2;
+        mAttributes = new String[length];
+
+        int i = 0;
+        if (attrs != null) {
+            for (i = 0; i < attrs.getAttributeCount(); i += 2) {
+                mAttributes[i] = attrs.getAttributeName(i);
+                mAttributes[i + 1] = attrs.getAttributeValue(i);
+            }
+
+        }
+
+        SparseArray<String> attributeMap = getAttributeMap();
+        for (int j = 0; j < a.length(); ++j) {
+            if (a.hasValue(j)) {
+                try {
+                    int resourceId = a.getResourceId(j, 0);
+                    if (resourceId == 0) {
+                        continue;
+                    }
+
+                    String resourceName = attributeMap.get(resourceId);
+                    if (resourceName == null) {
+                        resourceName = a.getResources().getResourceName(resourceId);
+                        attributeMap.put(resourceId, resourceName);
+                    }
+
+                    mAttributes[i] = resourceName;
+                    mAttributes[i + 1] = a.getText(j).toString();
+                    i += 2;
+                } catch (Resources.NotFoundException e) {
+                    // if we can't get the resource name, we just ignore it
+                }
+            }
+        }
+    }
+
     public String toString() {
         StringBuilder out = new StringBuilder(128);
         out.append(getClass().getName());
@@ -13763,6 +13831,7 @@
                     } else {
                         draw(canvas);
                     }
+                    drawAccessibilityFocus(canvas);
                 }
             } finally {
                 renderNode.end(canvas);
@@ -14057,6 +14126,7 @@
             } else {
                 draw(canvas);
             }
+            drawAccessibilityFocus(canvas);
 
             canvas.restoreToCount(restoreCount);
             canvas.setBitmap(null);
@@ -14131,6 +14201,7 @@
         } else {
             draw(canvas);
         }
+        drawAccessibilityFocus(canvas);
 
         mPrivateFlags = flags;
 
@@ -14704,8 +14775,10 @@
             if (layerType == LAYER_TYPE_HARDWARE && !usingRenderNodeProperties) {
                 final HardwareLayer layer = getHardwareLayer();
                 if (layer != null && layer.isValid()) {
+                    int restoreAlpha = mLayerPaint.getAlpha();
                     mLayerPaint.setAlpha((int) (alpha * 255));
                     ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, mLayerPaint);
+                    mLayerPaint.setAlpha(restoreAlpha);
                     layerRendered = true;
                 } else {
                     final int scrollX = hasDisplayList ? 0 : sx;
@@ -14722,9 +14795,13 @@
                     if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                         mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                         dispatchDraw(canvas);
+                        if (mOverlay != null && !mOverlay.isEmpty()) {
+                            mOverlay.getOverlayView().draw(canvas);
+                        }
                     } else {
                         draw(canvas);
                     }
+                    drawAccessibilityFocus(canvas);
                 } else {
                     mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                     ((HardwareCanvas) canvas).drawRenderNode(renderNode, null, flags);
@@ -14733,6 +14810,7 @@
         } else if (cache != null) {
             mPrivateFlags &= ~PFLAG_DIRTY_MASK;
             Paint cachePaint;
+            int restoreAlpha = 0;
 
             if (layerType == LAYER_TYPE_NONE) {
                 cachePaint = parent.mCachePaint;
@@ -14741,18 +14819,13 @@
                     cachePaint.setDither(false);
                     parent.mCachePaint = cachePaint;
                 }
-                if (alpha < 1) {
-                    cachePaint.setAlpha((int) (alpha * 255));
-                    parent.mGroupFlags |= ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE;
-                } else if  ((flags & ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE) != 0) {
-                    cachePaint.setAlpha(255);
-                    parent.mGroupFlags &= ~ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE;
-                }
             } else {
                 cachePaint = mLayerPaint;
-                cachePaint.setAlpha((int) (alpha * 255));
+                restoreAlpha = mLayerPaint.getAlpha();
             }
+            cachePaint.setAlpha((int) (alpha * 255));
             canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
+            cachePaint.setAlpha(restoreAlpha);
         }
 
         if (restoreTo >= 0) {
@@ -14980,6 +15053,45 @@
     }
 
     /**
+     * Draws the accessibility focus rect onto the specified canvas.
+     *
+     * @param canvas Canvas on which to draw the focus rect
+     */
+    private void drawAccessibilityFocus(Canvas canvas) {
+        if (mAttachInfo == null) {
+            return;
+        }
+
+        final Rect bounds = mAttachInfo.mTmpInvalRect;
+        final ViewRootImpl viewRoot = getViewRootImpl();
+        if (viewRoot == null || viewRoot.getAccessibilityFocusedHost() != this) {
+            return;
+        }
+
+        final AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
+        if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
+            return;
+        }
+
+        final Drawable drawable = viewRoot.getAccessibilityFocusedDrawable();
+        if (drawable == null) {
+            return;
+        }
+
+        final AccessibilityNodeInfo virtualView = viewRoot.getAccessibilityFocusedVirtualView();
+        if (virtualView != null) {
+            virtualView.getBoundsInParent(bounds);
+        } else {
+            bounds.set(0, 0, mRight - mLeft, mBottom - mTop);
+        }
+
+        canvas.translate(mScrollX, mScrollY);
+        drawable.setBounds(bounds);
+        drawable.draw(canvas);
+        canvas.translate(-mScrollX, -mScrollY);
+    }
+
+    /**
      * Draws the background onto the specified canvas.
      *
      * @param canvas Canvas on which to draw the background
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 4d9a8cc..6c66eb0 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -187,6 +187,15 @@
          * @return true if the supported values should be formatted as a hex string.
          */
         boolean formatToHexString() default false;
+
+        /**
+         * Indicates whether or not the key to value mappings are held in adjacent indices.
+         *
+         * Note: Applies only to fields and methods that return String[].
+         *
+         * @return true if the key to value mappings are held in adjacent indices.
+         */
+        boolean hasAdjacentMapping() default false;
     }
 
     /**
@@ -1056,7 +1065,6 @@
             Class<?> klass, String prefix) throws IOException {
 
         final Method[] methods = getExportedPropertyMethods(klass);
-
         int count = methods.length;
         for (int i = 0; i < count; i++) {
             final Method method = methods[i];
@@ -1108,6 +1116,19 @@
                     exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
 
                     continue;
+                } else if (returnType == String[].class) {
+                    final String[] array = (String[]) methodValue;
+                    if (property.hasAdjacentMapping() && array != null) {
+                        for (int j = 0; j < array.length; j += 2) {
+                            if (array[j] != null) {
+                                writeEntry(out, categoryPrefix + prefix, array[j], "()",
+                                        array[j + 1] == null ? "null" : array[j + 1]);
+                            }
+
+                        }
+                    }
+
+                    continue;
                 } else if (!returnType.isPrimitive()) {
                     if (property.deepExport()) {
                         dumpViewProperties(context, methodValue, out, prefix + property.prefix());
@@ -1187,6 +1208,18 @@
                     exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
 
                     continue;
+                } else if (type == String[].class) {
+                    final String[] array = (String[]) field.get(view);
+                    if (property.hasAdjacentMapping() && array != null) {
+                        for (int j = 0; j < array.length; j += 2) {
+                            if (array[j] != null) {
+                                writeEntry(out, categoryPrefix + prefix, array[j], "",
+                                        array[j + 1] == null ? "null" : array[j + 1]);
+                            }
+                        }
+                    }
+
+                    continue;
                 } else if (!type.isPrimitive()) {
                     if (property.deepExport()) {
                         dumpViewProperties(context, field.get(view), out, prefix +
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7f15381..19dd583 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -279,9 +279,7 @@
      */
     protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
 
-    // When the previous drawChild() invocation used an alpha value that was lower than
-    // 1.0 and set it in mCachePaint
-    static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
+    // UNUSED FLAG VALUE: 0x1000;
 
     /**
      * When set, this ViewGroup's drawable states also include those
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 92e0245..bb469a3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2244,7 +2244,6 @@
             canvas.drawHardwareLayer(mResizeBuffer, mHardwareXOffset, mHardwareYOffset,
                     mResizePaint);
         }
-        drawAccessibilityFocusedDrawableIfNeeded(canvas);
     }
 
     /**
@@ -2462,25 +2461,9 @@
                 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
                     mHardwareYOffset = yOffset;
                     mHardwareXOffset = xOffset;
-                    invalidateRoot = true;
-                }
-                mResizeAlpha = resizeAlpha;
-
-                if (!invalidateRoot) {
-                    // If accessibility focus moved, invalidate the root.
-                    final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
-                    if (drawable != null) {
-                        final Rect bounds = mAttachInfo.mTmpInvalRect;
-                        if (getAccessibilityFocusedRect(bounds)
-                                && !bounds.equals(drawable.getBounds())) {
-                            invalidateRoot = true;
-                        }
-                    }
-                }
-
-                if (invalidateRoot) {
                     mAttachInfo.mHardwareRenderer.invalidateRoot();
                 }
+                mResizeAlpha = resizeAlpha;
 
                 dirty.setEmpty();
 
@@ -2600,8 +2583,6 @@
                 attachInfo.mSetIgnoreDirtyState = false;
 
                 mView.draw(canvas);
-
-                drawAccessibilityFocusedDrawableIfNeeded(canvas);
             } finally {
                 if (!attachInfo.mSetIgnoreDirtyState) {
                     // Only clear the flag if it was not set during the mView.draw() call
@@ -2625,54 +2606,7 @@
         return true;
     }
 
-    /**
-     * We want to draw a highlight around the current accessibility focused.
-     * Since adding a style for all possible view is not a viable option we
-     * have this specialized drawing method.
-     *
-     * Note: We are doing this here to be able to draw the highlight for
-     *       virtual views in addition to real ones.
-     *
-     * @param canvas The canvas on which to draw.
-     */
-    private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
-        final Rect bounds = mAttachInfo.mTmpInvalRect;
-        if (getAccessibilityFocusedRect(bounds)) {
-            final Drawable drawable = getAccessibilityFocusedDrawable();
-            if (drawable != null) {
-                drawable.setBounds(bounds);
-                drawable.draw(canvas);
-            }
-        }
-    }
-
-    private boolean getAccessibilityFocusedRect(Rect bounds) {
-        final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
-        if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
-            return false;
-        }
-
-        final View host = mAccessibilityFocusedHost;
-        if (host == null || host.mAttachInfo == null) {
-            return false;
-        }
-
-        final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
-        if (provider == null) {
-            host.getBoundsOnScreen(bounds);
-        } else if (mAccessibilityFocusedVirtualView != null) {
-            mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
-        } else {
-            return false;
-        }
-
-        final AttachInfo attachInfo = mAttachInfo;
-        bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
-        bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth, attachInfo.mViewRootImpl.mHeight);
-        return true;
-    }
-
-    private Drawable getAccessibilityFocusedDrawable() {
+    Drawable getAccessibilityFocusedDrawable() {
         // Lazily load the accessibility focus drawable.
         if (mAttachInfo.mAccessibilityFocusDrawable == null) {
             final TypedValue value = new TypedValue();
diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java
new file mode 100644
index 0000000..35a6a76
--- /dev/null
+++ b/core/java/android/view/WindowCallbackWrapper.java
@@ -0,0 +1,144 @@
+/*
+ * 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.view;
+
+import android.view.accessibility.AccessibilityEvent;
+
+/**
+ * A simple decorator stub for Window.Callback that passes through any calls
+ * to the wrapped instance as a base implementation. Call super.foo() to call into
+ * the wrapped callback for any subclasses.
+ *
+ * @hide for internal use
+ */
+public class WindowCallbackWrapper implements Window.Callback {
+    private Window.Callback mWrapped;
+
+    public WindowCallbackWrapper(Window.Callback wrapped) {
+        if (wrapped == null) {
+            throw new IllegalArgumentException("Window callback may not be null");
+        }
+        mWrapped = wrapped;
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        return mWrapped.dispatchKeyEvent(event);
+    }
+
+    @Override
+    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+        return mWrapped.dispatchKeyShortcutEvent(event);
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent event) {
+        return mWrapped.dispatchTouchEvent(event);
+    }
+
+    @Override
+    public boolean dispatchTrackballEvent(MotionEvent event) {
+        return mWrapped.dispatchTrackballEvent(event);
+    }
+
+    @Override
+    public boolean dispatchGenericMotionEvent(MotionEvent event) {
+        return mWrapped.dispatchGenericMotionEvent(event);
+    }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        return mWrapped.dispatchPopulateAccessibilityEvent(event);
+    }
+
+    @Override
+    public View onCreatePanelView(int featureId) {
+        return mWrapped.onCreatePanelView(featureId);
+    }
+
+    @Override
+    public boolean onCreatePanelMenu(int featureId, Menu menu) {
+        return mWrapped.onCreatePanelMenu(featureId, menu);
+    }
+
+    @Override
+    public boolean onPreparePanel(int featureId, View view, Menu menu) {
+        return mWrapped.onPreparePanel(featureId, view, menu);
+    }
+
+    @Override
+    public boolean onMenuOpened(int featureId, Menu menu) {
+        return mWrapped.onMenuOpened(featureId, menu);
+    }
+
+    @Override
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+        return mWrapped.onMenuItemSelected(featureId, item);
+    }
+
+    @Override
+    public void onWindowAttributesChanged(WindowManager.LayoutParams attrs) {
+        mWrapped.onWindowAttributesChanged(attrs);
+    }
+
+    @Override
+    public void onContentChanged() {
+        mWrapped.onContentChanged();
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        mWrapped.onWindowFocusChanged(hasFocus);
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        mWrapped.onAttachedToWindow();
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        mWrapped.onDetachedFromWindow();
+    }
+
+    @Override
+    public void onPanelClosed(int featureId, Menu menu) {
+        mWrapped.onPanelClosed(featureId, menu);
+    }
+
+    @Override
+    public boolean onSearchRequested() {
+        return mWrapped.onSearchRequested();
+    }
+
+    @Override
+    public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
+        return mWrapped.onWindowStartingActionMode(callback);
+    }
+
+    @Override
+    public void onActionModeStarted(ActionMode mode) {
+        mWrapped.onActionModeStarted(mode);
+    }
+
+    @Override
+    public void onActionModeFinished(ActionMode mode) {
+        mWrapped.onActionModeFinished(mode);
+    }
+}
+
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b37ee06..3f5f045 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3158,6 +3158,7 @@
         // Offset from touch position to mPosition
         private float mTouchToWindowOffsetX, mTouchToWindowOffsetY;
         protected int mHotspotX;
+        protected int mHorizontalGravity;
         // Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up
         private float mTouchOffsetY;
         // Where the touch position should be on the handle to ensure a maximum cursor visibility
@@ -3172,6 +3173,8 @@
         private boolean mPositionHasChanged = true;
         // Used to delay the appearance of the action popup window
         private Runnable mActionPopupShower;
+        // Minimum touch target size for handles
+        private int mMinSize;
 
         public HandleView(Drawable drawableLtr, Drawable drawableRtl) {
             super(mTextView.getContext());
@@ -3184,10 +3187,12 @@
 
             mDrawableLtr = drawableLtr;
             mDrawableRtl = drawableRtl;
+            mMinSize = mTextView.getContext().getResources().getDimensionPixelSize(
+                    com.android.internal.R.dimen.text_handle_min_size);
 
             updateDrawable();
 
-            final int handleHeight = mDrawable.getIntrinsicHeight();
+            final int handleHeight = getPreferredHeight();
             mTouchOffsetY = -0.3f * handleHeight;
             mIdealVerticalOffset = 0.7f * handleHeight;
         }
@@ -3197,9 +3202,11 @@
             final boolean isRtlCharAtOffset = mTextView.getLayout().isRtlCharAt(offset);
             mDrawable = isRtlCharAtOffset ? mDrawableRtl : mDrawableLtr;
             mHotspotX = getHotspotX(mDrawable, isRtlCharAtOffset);
+            mHorizontalGravity = getHorizontalGravity(isRtlCharAtOffset);
         }
 
         protected abstract int getHotspotX(Drawable drawable, boolean isRtlRun);
+        protected abstract int getHorizontalGravity(boolean isRtlRun);
 
         // Touch-up filter: number of previous positions remembered
         private static final int HISTORY_SIZE = 5;
@@ -3244,7 +3251,15 @@
 
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            setMeasuredDimension(mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
+            setMeasuredDimension(getPreferredWidth(), getPreferredHeight());
+        }
+
+        private int getPreferredWidth() {
+            return Math.max(mDrawable.getIntrinsicWidth(), mMinSize);
+        }
+
+        private int getPreferredHeight() {
+            return Math.max(mDrawable.getIntrinsicHeight(), mMinSize);
         }
 
         public void show() {
@@ -3336,7 +3351,8 @@
                 }
                 final int line = layout.getLineForOffset(offset);
 
-                mPositionX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX);
+                mPositionX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX -
+                        getHorizontalOffset() + getCursorOffset());
                 mPositionY = layout.getLineBottom(line);
 
                 // Take TextView's padding and scroll into account.
@@ -3385,10 +3401,36 @@
 
         @Override
         protected void onDraw(Canvas c) {
-            mDrawable.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
+            final int drawWidth = mDrawable.getIntrinsicWidth();
+            final int left = getHorizontalOffset();
+
+            mDrawable.setBounds(left, 0, left + drawWidth, mDrawable.getIntrinsicHeight());
             mDrawable.draw(c);
         }
 
+        private int getHorizontalOffset() {
+            final int width = getPreferredWidth();
+            final int drawWidth = mDrawable.getIntrinsicWidth();
+            final int left;
+            switch (mHorizontalGravity) {
+                case Gravity.LEFT:
+                    left = 0;
+                    break;
+                default:
+                case Gravity.CENTER:
+                    left = (width - drawWidth) / 2;
+                    break;
+                case Gravity.RIGHT:
+                    left = width - drawWidth;
+                    break;
+            }
+            return left;
+        }
+
+        protected int getCursorOffset() {
+            return 0;
+        }
+
         @Override
         public boolean onTouchEvent(MotionEvent ev) {
             switch (ev.getActionMasked()) {
@@ -3508,6 +3550,22 @@
         }
 
         @Override
+        protected int getHorizontalGravity(boolean isRtlRun) {
+            return Gravity.CENTER_HORIZONTAL;
+        }
+
+        @Override
+        protected int getCursorOffset() {
+            int offset = super.getCursorOffset();
+            final Drawable cursor = mCursorCount > 0 ? mCursorDrawable[0] : null;
+            if (cursor != null) {
+                cursor.getPadding(mTempRect);
+                offset += (cursor.getIntrinsicWidth() - mTempRect.left - mTempRect.right) / 2;
+            }
+            return offset;
+        }
+
+        @Override
         public boolean onTouchEvent(MotionEvent ev) {
             final boolean result = super.onTouchEvent(ev);
 
@@ -3594,6 +3652,11 @@
         }
 
         @Override
+        protected int getHorizontalGravity(boolean isRtlRun) {
+            return isRtlRun ? Gravity.RIGHT : Gravity.LEFT;
+        }
+
+        @Override
         public int getCurrentCursorOffset() {
             return mTextView.getSelectionStart();
         }
@@ -3637,6 +3700,11 @@
         }
 
         @Override
+        protected int getHorizontalGravity(boolean isRtlRun) {
+            return isRtlRun ? Gravity.LEFT : Gravity.RIGHT;
+        }
+
+        @Override
         public int getCurrentCursorOffset() {
             return mTextView.getSelectionEnd();
         }
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index c0961fd..06b7a93 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -79,6 +79,7 @@
     // Positions for preview image and text.
     private static final int OVERLAY_FLOATING = 0;
     private static final int OVERLAY_AT_THUMB = 1;
+    private static final int OVERLAY_ABOVE_THUMB = 2;
 
     // Indices for mPreviewResId.
     private static final int PREVIEW_LEFT = 0;
@@ -189,8 +190,9 @@
     /**
      * Position for the preview image and text. One of:
      * <ul>
-     * <li>{@link #OVERLAY_AT_THUMB}
      * <li>{@link #OVERLAY_FLOATING}
+     * <li>{@link #OVERLAY_AT_THUMB}
+     * <li>{@link #OVERLAY_ABOVE_THUMB}
      * </ul>
      */
     private int mOverlayPosition;
@@ -310,8 +312,10 @@
         final int textMinSize = Math.max(0, mPreviewMinHeight);
         mPrimaryText.setMinimumWidth(textMinSize);
         mPrimaryText.setMinimumHeight(textMinSize);
+        mPrimaryText.setIncludeFontPadding(false);
         mSecondaryText.setMinimumWidth(textMinSize);
         mSecondaryText.setMinimumHeight(textMinSize);
+        mSecondaryText.setIncludeFontPadding(false);
 
         refreshDrawablePressedState();
     }
@@ -595,10 +599,10 @@
         margins.right = mPreviewImage.getPaddingRight();
         margins.bottom = mPreviewImage.getPaddingBottom();
 
-        if (mOverlayPosition == OVERLAY_AT_THUMB) {
-            measureViewToSide(v, mThumbImage, margins, out);
-        } else {
+        if (mOverlayPosition == OVERLAY_FLOATING) {
             measureFloating(v, margins, out);
+        } else {
+            measureViewToSide(v, mThumbImage, margins, out);
         }
     }
 
@@ -1147,11 +1151,23 @@
         final float thumbMiddle = position * range + offset;
         thumbImage.setTranslationY(thumbMiddle - thumbImage.getHeight() / 2);
 
-        final float previewPos = mOverlayPosition == OVERLAY_AT_THUMB ? thumbMiddle : 0;
-
-        // Center the preview on the thumb, constrained to the list bounds.
         final View previewImage = mPreviewImage;
         final float previewHalfHeight = previewImage.getHeight() / 2f;
+        final float previewPos;
+        switch (mOverlayPosition) {
+            case OVERLAY_AT_THUMB:
+                previewPos = thumbMiddle;
+                break;
+            case OVERLAY_ABOVE_THUMB:
+                previewPos = thumbMiddle - previewHalfHeight;
+                break;
+            case OVERLAY_FLOATING:
+            default:
+                previewPos = 0;
+                break;
+        }
+
+        // Center the preview on the thumb, constrained to the list bounds.
         final float minP = top + previewHalfHeight;
         final float maxP = bottom - previewHalfHeight;
         final float previewMiddle = MathUtils.constrain(previewPos, minP, maxP);
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 4dd7e07..23f911c 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1501,7 +1501,7 @@
                     mRules[ALIGN_PARENT_START] = 0;
                 }
 
-                if (mRules[ALIGN_PARENT_RIGHT] == 0) {
+                if (mRules[ALIGN_PARENT_END] != 0) {
                     if (mRules[ALIGN_PARENT_RIGHT] == 0) {
                         // "right" rule is not defined but "end" rule is: use the "end" rule as the
                         // "right" rule
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 8aef304..05ff151 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2656,7 +2656,7 @@
         if (UserHandle.getUserId(applicationInfo.uid) != userId
                 || !applicationInfo.packageName.equals(packageName)) {
             try {
-                Context context = application.getApplicationContext().createPackageContextAsUser(
+                Context context = application.getBaseContext().createPackageContextAsUser(
                         packageName, 0, new UserHandle(userId));
                 applicationInfo = context.getApplicationInfo();
             } catch (NameNotFoundException nnfe) {
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index cd922a1..5267811 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -60,6 +60,7 @@
                 initialIntents[i] = in;
             }
         }
+        setSafeForwardingMode(true);
         super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
                 null, false);
     }
diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
index 7a3ffdf..81ea191 100644
--- a/core/java/com/android/internal/app/IMediaContainerService.aidl
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -25,10 +25,7 @@
             boolean isExternal, boolean isForwardLocked, String abiOverride);
     int copyPackage(String packagePath, in IParcelFileDescriptorFactory target);
 
-    PackageInfoLite getMinimalPackageInfo(String packagePath, int flags, long threshold,
-            String abiOverride);
-    boolean checkInternalFreeStorage(String packagePath, boolean isForwardLocked, long threshold);
-    boolean checkExternalFreeStorage(String packagePath, boolean isForwardLocked, String abiOverride);
+    PackageInfoLite getMinimalPackageInfo(String packagePath, int flags, String abiOverride);
     ObbInfo getObbInfo(String filename);
     long calculateDirectorySize(String directory);
     /** Return file system stats: [0] is total bytes, [1] is available bytes */
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index af38b3e..d9493752 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -76,17 +76,19 @@
         }
         Intent newIntent = new Intent(intentReceived);
         newIntent.setComponent(null);
+        // Apps should not be allowed to target a specific package in the target user.
+        newIntent.setPackage(null);
         newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
                 |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
         int callingUserId = getUserId();
         IPackageManager ipm = AppGlobals.getPackageManager();
         String resolvedType = newIntent.resolveTypeIfNeeded(getContentResolver());
         boolean canForward = false;
+        Intent selector = newIntent.getSelector();
+        if (selector == null) {
+            selector = newIntent;
+        }
         try {
-            Intent selector = newIntent.getSelector();
-            if (selector == null) {
-                selector = newIntent;
-            }
             canForward = ipm.canForwardTo(selector, resolvedType, callingUserId,
                     userDest.getIdentifier());
         } catch (RemoteException e) {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index b1727fa..636c712 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -17,10 +17,13 @@
 package com.android.internal.app;
 
 import android.app.Activity;
+import android.app.ActivityThread;
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
 import android.os.AsyncTask;
+import android.provider.Settings;
 import android.util.ArrayMap;
+import android.util.Slog;
 import android.widget.AbsListView;
 import android.widget.GridView;
 import com.android.internal.R;
@@ -83,6 +86,7 @@
     private int mLaunchedFromUid;
     private ResolveListAdapter mAdapter;
     private PackageManager mPm;
+    private boolean mSafeForwardingMode;
     private boolean mAlwaysUseOption;
     private boolean mShowExtended;
     private GridView mGridView;
@@ -175,6 +179,8 @@
             titleResource = 0;
         }
 
+        setSafeForwardingMode(true);
+
         onCreate(savedInstanceState, intent,
                 titleResource != 0 ? getResources().getText(titleResource) : null, titleResource,
                 null, null, true);
@@ -247,7 +253,7 @@
 
             resizeGrid();
         } else if (count == 1) {
-            startActivity(mAdapter.intentForPosition(0, false));
+            safelyStartActivity(mAdapter.intentForPosition(0, false));
             mPackageMonitor.unregister();
             mRegistered = false;
             finish();
@@ -303,6 +309,22 @@
         }
     }
 
+    /**
+     * Turn on launch mode that is safe to use when forwarding intents received from
+     * applications and running in system processes.  This mode uses Activity.startActivityAsCaller
+     * instead of the normal Activity.startActivity for launching the activity selected
+     * by the user.
+     *
+     * <p>This mode is set to true by default if the activity is initialized through
+     * {@link #onCreate(android.os.Bundle)}.  If a subclass calls one of the other onCreate
+     * methods, it is set to false by default.  You must set it before calling one of the
+     * more detailed onCreate methods, so that it will be set correctly in the case where
+     * there is only one intent to resolve and it is thus started immediately.</p>
+     */
+    public void setSafeForwardingMode(boolean safeForwarding) {
+        mSafeForwardingMode = safeForwarding;
+    }
+
     protected CharSequence getTitleForAction(String action, int defaultTitleRes) {
         final ActionTitle title = ActionTitle.forAction(action);
         final boolean named = mAdapter.hasFilteredItem();
@@ -605,12 +627,33 @@
         }
 
         if (intent != null) {
+            safelyStartActivity(intent);
+        }
+    }
+
+    public void safelyStartActivity(Intent intent) {
+        if (!mSafeForwardingMode) {
             startActivity(intent);
+            return;
+        }
+        try {
+            startActivityAsCaller(intent, null);
+        } catch (RuntimeException e) {
+            String launchedFromPackage;
+            try {
+                launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
+                        getActivityToken());
+            } catch (RemoteException e2) {
+                launchedFromPackage = "??";
+            }
+            Slog.wtf(TAG, "Unable to launch as uid " + mLaunchedFromUid
+                    + " package " + launchedFromPackage + ", while running in "
+                    + ActivityThread.currentProcessName(), e);
         }
     }
 
     void showAppDetails(ResolveInfo ri) {
-        Intent in = new Intent().setAction("android.settings.APPLICATION_DETAILS_SETTINGS")
+        Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                 .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
                 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
         startActivity(in);
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 96d7192..13eb182 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -29,6 +29,7 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.Window;
+import android.view.WindowCallbackWrapper;
 import android.widget.SpinnerAdapter;
 import android.widget.Toolbar;
 import com.android.internal.view.menu.MenuBuilder;
@@ -40,6 +41,7 @@
 public class ToolbarActionBar extends ActionBar {
     private Toolbar mToolbar;
     private DecorToolbar mDecorToolbar;
+    private boolean mToolbarMenuPrepared;
     private Window.Callback mWindowCallback;
 
     private boolean mLastMenuVisibility;
@@ -64,12 +66,16 @@
     public ToolbarActionBar(Toolbar toolbar, CharSequence title, Window.Callback windowCallback) {
         mToolbar = toolbar;
         mDecorToolbar = new ToolbarWidgetWrapper(toolbar, false);
-        mWindowCallback = windowCallback;
+        mWindowCallback = new ToolbarCallbackWrapper(windowCallback);
         mDecorToolbar.setWindowCallback(mWindowCallback);
         toolbar.setOnMenuItemClickListener(mMenuClicker);
         mDecorToolbar.setWindowTitle(title);
     }
 
+    public Window.Callback getWrappedWindowCallback() {
+        return mWindowCallback;
+    }
+
     @Override
     public void setCustomView(View view) {
         setCustomView(view, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
@@ -465,4 +471,20 @@
             mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
         }
     }
+
+    private class ToolbarCallbackWrapper extends WindowCallbackWrapper {
+        public ToolbarCallbackWrapper(Window.Callback wrapped) {
+            super(wrapped);
+        }
+
+        @Override
+        public boolean onPreparePanel(int featureId, View view, Menu menu) {
+            final boolean result = super.onPreparePanel(featureId, view, menu);
+            if (result && !mToolbarMenuPrepared) {
+                mDecorToolbar.setMenuPrepared();
+                mToolbarMenuPrepared = true;
+            }
+            return result;
+        }
+    }
 }
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index eff6684..fd96f64 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -16,14 +16,21 @@
 
 package com.android.internal.content;
 
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Environment;
 import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
 import android.os.storage.StorageResultCode;
 import android.util.Log;
 
+import libcore.io.IoUtils;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -33,8 +40,6 @@
 import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
 
-import libcore.io.IoUtils;
-
 /**
  * Constants used internally between the PackageManager
  * and media container service transports.
@@ -298,4 +303,78 @@
         }
         return false;
     }
+
+    /**
+     * Given a requested {@link PackageInfo#installLocation} and calculated
+     * install size, pick the actual location to install the app.
+     */
+    public static int resolveInstallLocation(Context context, int installLocation, long sizeBytes,
+            int installFlags) {
+        final int prefer;
+        final boolean checkBoth;
+        if ((installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
+            prefer = RECOMMEND_INSTALL_INTERNAL;
+            checkBoth = false;
+        } else if ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+            prefer = RECOMMEND_INSTALL_EXTERNAL;
+            checkBoth = false;
+        } else if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+            prefer = RECOMMEND_INSTALL_INTERNAL;
+            checkBoth = false;
+        } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
+            prefer = RECOMMEND_INSTALL_EXTERNAL;
+            checkBoth = true;
+        } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
+            prefer = RECOMMEND_INSTALL_INTERNAL;
+            checkBoth = true;
+        } else {
+            prefer = RECOMMEND_INSTALL_INTERNAL;
+            checkBoth = false;
+        }
+
+        final boolean emulated = Environment.isExternalStorageEmulated();
+        final StorageManager storage = StorageManager.from(context);
+
+        boolean fitsOnInternal = false;
+        if (checkBoth || prefer == RECOMMEND_INSTALL_INTERNAL) {
+            fitsOnInternal = (sizeBytes
+                    <= storage.getStorageBytesUntilLow(Environment.getDataDirectory()));
+        }
+
+        boolean fitsOnExternal = false;
+        if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL)) {
+            fitsOnExternal = (sizeBytes
+                    <= storage.getStorageBytesUntilLow(Environment.getExternalStorageDirectory()));
+        }
+
+        if (prefer == RECOMMEND_INSTALL_INTERNAL) {
+            if (fitsOnInternal) {
+                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+            }
+        } else if (!emulated && prefer == RECOMMEND_INSTALL_EXTERNAL) {
+            if (fitsOnExternal) {
+                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
+            }
+        }
+
+        if (checkBoth) {
+            if (fitsOnInternal) {
+                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+            } else if (!emulated && fitsOnExternal) {
+                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
+            }
+        }
+
+        /*
+         * If they requested to be on the external media by default, return that
+         * the media was unavailable. Otherwise, indicate there was insufficient
+         * storage space available.
+         */
+        if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL)
+                && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
+            return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE;
+        } else {
+            return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
+        }
+    }
 }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index d801571..6eb0099 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -974,6 +974,16 @@
             }
         }
 
+        public boolean isShowImeWithHardKeyboardEnabled() {
+                return Settings.Secure.getIntForUser(mResolver,
+                        Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mCurrentUserId) == 1;
+        }
+
+        public void setShowImeWithHardKeyboard(boolean show) {
+            Settings.Secure.putIntForUser(mResolver, Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
+                    show ? 1 : 0, mCurrentUserId);
+        }
+
         public int getCurrentUserId() {
             return mCurrentUserId;
         }
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 63be2d4..ee406bd 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -74,6 +74,7 @@
 
     final private Context mContext;
     final private boolean mCollectBatteryBroadcast;
+    final private boolean mWifiOnly;
 
     private IBatteryStats mBatteryInfo;
     private BatteryStats mStats;
@@ -123,6 +124,19 @@
     public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast) {
         mContext = context;
         mCollectBatteryBroadcast = collectBatteryBroadcast;
+        mWifiOnly = checkWifiOnly(context);
+    }
+
+    public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast, boolean wifiOnly) {
+        mContext = context;
+        mCollectBatteryBroadcast = collectBatteryBroadcast;
+        mWifiOnly = wifiOnly;
+    }
+
+    public static boolean checkWifiOnly(Context context) {
+        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        return !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
     }
 
     public void storeStatsHistoryInFile(String fname) {
@@ -870,9 +884,7 @@
         addBluetoothUsage();
         addIdleUsage(); // Not including cellular idle power
         // Don't compute radio usage if it's a wifi-only device
-        ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
-        if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) {
+        if (!mWifiOnly) {
             addRadioUsage();
         }
     }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index a745b20..299b0e6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -49,6 +49,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.LogWriter;
+import android.util.MutableInt;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 import android.util.Slog;
@@ -104,9 +105,7 @@
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
     // in to one common name.
-    private static final int MAX_WAKELOCKS_PER_UID = 50;
-
-    private static final String BATCHED_WAKELOCK_NAME = "*overflow*";
+    private static final int MAX_WAKELOCKS_PER_UID = 100;
 
     private static int sNumSpeedSteps;
 
@@ -1551,6 +1550,140 @@
         }
     }
 
+    public abstract class OverflowArrayMap<T> {
+        private static final String OVERFLOW_NAME = "*overflow*";
+
+        final ArrayMap<String, T> mMap = new ArrayMap<>();
+        T mCurOverflow;
+        ArrayMap<String, MutableInt> mActiveOverflow;
+
+        public OverflowArrayMap() {
+        }
+
+        public ArrayMap<String, T> getMap() {
+            return mMap;
+        }
+
+        public void clear() {
+            mMap.clear();
+            mCurOverflow = null;
+            mActiveOverflow = null;
+        }
+
+        public void add(String name, T obj) {
+            mMap.put(name, obj);
+            if (OVERFLOW_NAME.equals(name)) {
+                mCurOverflow = obj;
+            }
+        }
+
+        public void cleanup() {
+            if (mActiveOverflow != null) {
+                if (mActiveOverflow.size() == 0) {
+                    mActiveOverflow = null;
+                }
+            }
+            if (mActiveOverflow == null) {
+                // There is no currently active overflow, so we should no longer have
+                // an overflow entry.
+                if (mMap.containsKey(OVERFLOW_NAME)) {
+                    Slog.wtf(TAG, "Cleaning up with no active overflow, but have overflow entry "
+                            + mMap.get(OVERFLOW_NAME));
+                    mMap.remove(OVERFLOW_NAME);
+                }
+                mCurOverflow = null;
+            } else {
+                // There is currently active overflow, so we should still have an overflow entry.
+                if (mCurOverflow == null || !mMap.containsKey(OVERFLOW_NAME)) {
+                    Slog.wtf(TAG, "Cleaning up with active overflow, but no overflow entry: cur="
+                            + mCurOverflow + " map=" + mMap.get(OVERFLOW_NAME));
+                }
+            }
+        }
+
+        public T startObject(String name) {
+            T obj = mMap.get(name);
+            if (obj != null) {
+                return obj;
+            }
+
+            // No object exists for the given name, but do we currently have it
+            // running as part of the overflow?
+            if (mActiveOverflow != null) {
+                MutableInt over = mActiveOverflow.get(name);
+                if (over != null) {
+                    // We are already actively counting this name in the overflow object.
+                    obj = mCurOverflow;
+                    if (obj == null) {
+                        // Shouldn't be here, but we'll try to recover.
+                        Slog.wtf(TAG, "Have active overflow " + name + " but null overflow");
+                        obj = mCurOverflow = instantiateObject();
+                        mMap.put(OVERFLOW_NAME, obj);
+                    }
+                    over.value++;
+                    return obj;
+                }
+            }
+
+            // No object exists for given name nor in the overflow; we need to make
+            // a new one.
+            final int N = mMap.size();
+            if (N >= MAX_WAKELOCKS_PER_UID) {
+                // Went over the limit on number of objects to track; this one goes
+                // in to the overflow.
+                obj = mCurOverflow;
+                if (obj == null) {
+                    // Need to start overflow now...
+                    obj = mCurOverflow = instantiateObject();
+                    mMap.put(OVERFLOW_NAME, obj);
+                }
+                if (mActiveOverflow == null) {
+                    mActiveOverflow = new ArrayMap<>();
+                }
+                mActiveOverflow.put(name, new MutableInt(1));
+                return obj;
+            }
+
+            // Normal case where we just need to make a new object.
+            obj = instantiateObject();
+            mMap.put(name, obj);
+            return obj;
+        }
+
+        public T stopObject(String name) {
+            T obj = mMap.get(name);
+            if (obj != null) {
+                return obj;
+            }
+
+            // No object exists for the given name, but do we currently have it
+            // running as part of the overflow?
+            if (mActiveOverflow != null) {
+                MutableInt over = mActiveOverflow.get(name);
+                if (over != null) {
+                    // We are already actively counting this name in the overflow object.
+                    obj = mCurOverflow;
+                    if (obj != null) {
+                        over.value--;
+                        if (over.value <= 0) {
+                            mActiveOverflow.remove(name);
+                        }
+                        return obj;
+                    }
+                }
+            }
+
+            // Huh, they are stopping an active operation but we can't find one!
+            // That's not good.
+            Slog.wtf(TAG, "Unable to find object for " + name + " mapsize="
+                    + mMap.size() + " activeoverflow=" + mActiveOverflow
+                    + " curoverflow=" + mCurOverflow);
+            return null;
+        }
+
+        public abstract T instantiateObject();
+    }
+
     /*
      * Get the wakeup reason counter, and create a new one if one
      * doesn't already exist.
@@ -3995,17 +4128,27 @@
         /**
          * The statistics we have collected for this uid's wake locks.
          */
-        final ArrayMap<String, Wakelock> mWakelockStats = new ArrayMap<String, Wakelock>();
+        final OverflowArrayMap<Wakelock> mWakelockStats = new OverflowArrayMap<Wakelock>() {
+            @Override public Wakelock instantiateObject() { return new Wakelock(); }
+        };
 
         /**
          * The statistics we have collected for this uid's syncs.
          */
-        final ArrayMap<String, StopwatchTimer> mSyncStats = new ArrayMap<String, StopwatchTimer>();
+        final OverflowArrayMap<StopwatchTimer> mSyncStats = new OverflowArrayMap<StopwatchTimer>() {
+            @Override public StopwatchTimer instantiateObject() {
+                return new StopwatchTimer(Uid.this, SYNC, null, mOnBatteryTimeBase);
+            }
+        };
 
         /**
          * The statistics we have collected for this uid's jobs.
          */
-        final ArrayMap<String, StopwatchTimer> mJobStats = new ArrayMap<String, StopwatchTimer>();
+        final OverflowArrayMap<StopwatchTimer> mJobStats = new OverflowArrayMap<StopwatchTimer>() {
+            @Override public StopwatchTimer instantiateObject() {
+                return new StopwatchTimer(Uid.this, JOB, null, mOnBatteryTimeBase);
+            }
+        };
 
         /**
          * The statistics we have collected for this uid's sensor activations.
@@ -4043,17 +4186,17 @@
 
         @Override
         public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
-            return mWakelockStats;
+            return mWakelockStats.getMap();
         }
 
         @Override
         public Map<String, ? extends BatteryStats.Timer> getSyncStats() {
-            return mSyncStats;
+            return mSyncStats.getMap();
         }
 
         @Override
         public Map<String, ? extends BatteryStats.Timer> getJobStats() {
-            return mJobStats;
+            return mJobStats.getMap();
         }
 
         @Override
@@ -4567,32 +4710,38 @@
                 mMobileRadioActiveCount.reset(false);
             }
 
-            for (int iw=mWakelockStats.size()-1; iw>=0; iw--) {
-                Wakelock wl = mWakelockStats.valueAt(iw);
+            final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap();
+            for (int iw=wakeStats.size()-1; iw>=0; iw--) {
+                Wakelock wl = wakeStats.valueAt(iw);
                 if (wl.reset()) {
-                    mWakelockStats.removeAt(iw);
+                    wakeStats.removeAt(iw);
                 } else {
                     active = true;
                 }
             }
-            for (int is=mSyncStats.size()-1; is>=0; is--) {
-                StopwatchTimer timer = mSyncStats.valueAt(is);
+            mWakelockStats.cleanup();
+            final ArrayMap<String, StopwatchTimer> syncStats = mSyncStats.getMap();
+            for (int is=syncStats.size()-1; is>=0; is--) {
+                StopwatchTimer timer = syncStats.valueAt(is);
                 if (timer.reset(false)) {
-                    mSyncStats.removeAt(is);
+                    syncStats.removeAt(is);
                     timer.detach();
                 } else {
                     active = true;
                 }
             }
-            for (int ij=mJobStats.size()-1; ij>=0; ij--) {
-                StopwatchTimer timer = mJobStats.valueAt(ij);
+            mSyncStats.cleanup();
+            final ArrayMap<String, StopwatchTimer> jobStats = mJobStats.getMap();
+            for (int ij=jobStats.size()-1; ij>=0; ij--) {
+                StopwatchTimer timer = jobStats.valueAt(ij);
                 if (timer.reset(false)) {
-                    mJobStats.removeAt(ij);
+                    jobStats.removeAt(ij);
                     timer.detach();
                 } else {
                     active = true;
                 }
             }
+            mJobStats.cleanup();
             for (int ise=mSensorStats.size()-1; ise>=0; ise--) {
                 Sensor s = mSensorStats.valueAt(ise);
                 if (s.reset()) {
@@ -4687,27 +4836,30 @@
         }
 
         void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
-            int NW = mWakelockStats.size();
+            final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap();
+            int NW = wakeStats.size();
             out.writeInt(NW);
             for (int iw=0; iw<NW; iw++) {
-                out.writeString(mWakelockStats.keyAt(iw));
-                Uid.Wakelock wakelock = mWakelockStats.valueAt(iw);
+                out.writeString(wakeStats.keyAt(iw));
+                Uid.Wakelock wakelock = wakeStats.valueAt(iw);
                 wakelock.writeToParcelLocked(out, elapsedRealtimeUs);
             }
 
-            int NS = mSyncStats.size();
+            final ArrayMap<String, StopwatchTimer> syncStats = mSyncStats.getMap();
+            int NS = syncStats.size();
             out.writeInt(NS);
             for (int is=0; is<NS; is++) {
-                out.writeString(mSyncStats.keyAt(is));
-                StopwatchTimer timer = mSyncStats.valueAt(is);
+                out.writeString(syncStats.keyAt(is));
+                StopwatchTimer timer = syncStats.valueAt(is);
                 Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs);
             }
 
-            int NJ = mJobStats.size();
+            final ArrayMap<String, StopwatchTimer> jobStats = mJobStats.getMap();
+            int NJ = jobStats.size();
             out.writeInt(NJ);
             for (int ij=0; ij<NJ; ij++) {
-                out.writeString(mJobStats.keyAt(ij));
-                StopwatchTimer timer = mJobStats.valueAt(ij);
+                out.writeString(jobStats.keyAt(ij));
+                StopwatchTimer timer = jobStats.valueAt(ij);
                 Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs);
             }
 
@@ -4826,10 +4978,7 @@
                 String wakelockName = in.readString();
                 Uid.Wakelock wakelock = new Wakelock();
                 wakelock.readFromParcelLocked(timeBase, screenOffTimeBase, in);
-                // We will just drop some random set of wakelocks if
-                // the previous run of the system was an older version
-                // that didn't impose a limit.
-                mWakelockStats.put(wakelockName, wakelock);
+                mWakelockStats.add(wakelockName, wakelock);
             }
 
             int numSyncs = in.readInt();
@@ -4837,7 +4986,7 @@
             for (int j = 0; j < numSyncs; j++) {
                 String syncName = in.readString();
                 if (in.readInt() != 0) {
-                    mSyncStats.put(syncName,
+                    mSyncStats.add(syncName,
                             new StopwatchTimer(Uid.this, SYNC, null, timeBase, in));
                 }
             }
@@ -4847,7 +4996,7 @@
             for (int j = 0; j < numJobs; j++) {
                 String jobName = in.readString();
                 if (in.readInt() != 0) {
-                    mJobStats.put(jobName, new StopwatchTimer(Uid.this, JOB, null, timeBase, in));
+                    mJobStats.add(jobName, new StopwatchTimer(Uid.this, JOB, null, timeBase, in));
                 }
             }
 
@@ -5058,6 +5207,38 @@
                 default: throw new IllegalArgumentException("type = " + type);
                 }
             }
+
+            public StopwatchTimer getStopwatchTimer(int type) {
+                StopwatchTimer t;
+                switch (type) {
+                    case WAKE_TYPE_PARTIAL:
+                        t = mTimerPartial;
+                        if (t == null) {
+                            t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
+                                    mPartialTimers, mOnBatteryScreenOffTimeBase);
+                            mTimerPartial = t;
+                        }
+                        return t;
+                    case WAKE_TYPE_FULL:
+                        t = mTimerFull;
+                        if (t == null) {
+                            t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
+                                    mFullTimers, mOnBatteryTimeBase);
+                            mTimerFull = t;
+                        }
+                        return t;
+                    case WAKE_TYPE_WINDOW:
+                        t = mTimerWindow;
+                        if (t == null) {
+                            t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
+                                    mWindowTimers, mOnBatteryTimeBase);
+                            mTimerWindow = t;
+                        }
+                        return t;
+                    default:
+                        throw new IllegalArgumentException("type=" + type);
+                }
+            }
         }
 
         public final class Sensor extends BatteryStats.Uid.Sensor {
@@ -5925,79 +6106,29 @@
             return ss;
         }
 
-        public StopwatchTimer getSyncTimerLocked(String name) {
-            StopwatchTimer t = mSyncStats.get(name);
-            if (t == null) {
-                final int N = mSyncStats.size();
-                if (N > MAX_WAKELOCKS_PER_UID) {
-                    name = BATCHED_WAKELOCK_NAME;
-                    t = mSyncStats.get(name);
-                }
-                if (t == null) {
-                    t = new StopwatchTimer(Uid.this, SYNC, null, mOnBatteryTimeBase);
-                    mSyncStats.put(name, t);
-                }
-            }
-            return t;
+        public void readSyncSummaryFromParcelLocked(String name, Parcel in) {
+            StopwatchTimer timer = mSyncStats.instantiateObject();
+            timer.readSummaryFromParcelLocked(in);
+            mSyncStats.add(name, timer);
         }
 
-        public StopwatchTimer getJobTimerLocked(String name) {
-            StopwatchTimer t = mJobStats.get(name);
-            if (t == null) {
-                final int N = mJobStats.size();
-                if (N > MAX_WAKELOCKS_PER_UID) {
-                    name = BATCHED_WAKELOCK_NAME;
-                    t = mJobStats.get(name);
-                }
-                if (t == null) {
-                    t = new StopwatchTimer(Uid.this, JOB, null, mOnBatteryTimeBase);
-                    mJobStats.put(name, t);
-                }
-            }
-            return t;
+        public void readJobSummaryFromParcelLocked(String name, Parcel in) {
+            StopwatchTimer timer = mJobStats.instantiateObject();
+            timer.readSummaryFromParcelLocked(in);
+            mJobStats.add(name, timer);
         }
 
-        public StopwatchTimer getWakeTimerLocked(String name, int type) {
-            Wakelock wl = mWakelockStats.get(name);
-            if (wl == null) {
-                final int N = mWakelockStats.size();
-                if (N > MAX_WAKELOCKS_PER_UID) {
-                    name = BATCHED_WAKELOCK_NAME;
-                    wl = mWakelockStats.get(name);
-                }
-                if (wl == null) {
-                    wl = new Wakelock();
-                    mWakelockStats.put(name, wl);
-                }
+        public void readWakeSummaryFromParcelLocked(String wlName, Parcel in) {
+            Wakelock wl = new Wakelock();
+            mWakelockStats.add(wlName, wl);
+            if (in.readInt() != 0) {
+                wl.getStopwatchTimer(WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
             }
-            StopwatchTimer t = null;
-            switch (type) {
-                case WAKE_TYPE_PARTIAL:
-                    t = wl.mTimerPartial;
-                    if (t == null) {
-                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
-                                mPartialTimers, mOnBatteryScreenOffTimeBase);
-                        wl.mTimerPartial = t;
-                    }
-                    return t;
-                case WAKE_TYPE_FULL:
-                    t = wl.mTimerFull;
-                    if (t == null) {
-                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
-                                mFullTimers, mOnBatteryTimeBase);
-                        wl.mTimerFull = t;
-                    }
-                    return t;
-                case WAKE_TYPE_WINDOW:
-                    t = wl.mTimerWindow;
-                    if (t == null) {
-                        t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
-                                mWindowTimers, mOnBatteryTimeBase);
-                        wl.mTimerWindow = t;
-                    }
-                    return t;
-                default:
-                    throw new IllegalArgumentException("type=" + type);
+            if (in.readInt() != 0) {
+                wl.getStopwatchTimer(WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
+            }
+            if (in.readInt() != 0) {
+                wl.getStopwatchTimer(WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
             }
         }
 
@@ -6025,37 +6156,37 @@
         }
 
         public void noteStartSyncLocked(String name, long elapsedRealtimeMs) {
-            StopwatchTimer t = getSyncTimerLocked(name);
+            StopwatchTimer t = mSyncStats.startObject(name);
             if (t != null) {
                 t.startRunningLocked(elapsedRealtimeMs);
             }
         }
 
         public void noteStopSyncLocked(String name, long elapsedRealtimeMs) {
-            StopwatchTimer t = getSyncTimerLocked(name);
+            StopwatchTimer t = mSyncStats.stopObject(name);
             if (t != null) {
                 t.stopRunningLocked(elapsedRealtimeMs);
             }
         }
 
         public void noteStartJobLocked(String name, long elapsedRealtimeMs) {
-            StopwatchTimer t = getJobTimerLocked(name);
+            StopwatchTimer t = mJobStats.stopObject(name);
             if (t != null) {
                 t.startRunningLocked(elapsedRealtimeMs);
             }
         }
 
         public void noteStopJobLocked(String name, long elapsedRealtimeMs) {
-            StopwatchTimer t = getJobTimerLocked(name);
+            StopwatchTimer t = mJobStats.stopObject(name);
             if (t != null) {
                 t.stopRunningLocked(elapsedRealtimeMs);
             }
         }
 
         public void noteStartWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) {
-            StopwatchTimer t = getWakeTimerLocked(name, type);
-            if (t != null) {
-                t.startRunningLocked(elapsedRealtimeMs);
+            Wakelock wl = mWakelockStats.startObject(name);
+            if (wl != null) {
+                wl.getStopwatchTimer(type).startRunningLocked(elapsedRealtimeMs);
             }
             if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
                 Pid p = getPidStatsLocked(pid);
@@ -6066,9 +6197,9 @@
         }
 
         public void noteStopWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) {
-            StopwatchTimer t = getWakeTimerLocked(name, type);
-            if (t != null) {
-                t.stopRunningLocked(elapsedRealtimeMs);
+            Wakelock wl = mWakelockStats.stopObject(name);
+            if (wl != null) {
+                wl.getStopwatchTimer(type).stopRunningLocked(elapsedRealtimeMs);
             }
             if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
                 Pid p = mPids.get(pid);
@@ -7774,15 +7905,7 @@
             }
             for (int iw = 0; iw < NW; iw++) {
                 String wlName = in.readString();
-                if (in.readInt() != 0) {
-                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
-                }
-                if (in.readInt() != 0) {
-                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
-                }
-                if (in.readInt() != 0) {
-                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
-                }
+                u.readWakeSummaryFromParcelLocked(wlName, in);
             }
 
             int NS = in.readInt();
@@ -7792,7 +7915,7 @@
             }
             for (int is = 0; is < NS; is++) {
                 String name = in.readString();
-                u.getSyncTimerLocked(name).readSummaryFromParcelLocked(in);
+                u.readSyncSummaryFromParcelLocked(name, in);
             }
 
             int NJ = in.readInt();
@@ -7802,7 +7925,7 @@
             }
             for (int ij = 0; ij < NJ; ij++) {
                 String name = in.readString();
-                u.getJobTimerLocked(name).readSummaryFromParcelLocked(in);
+                u.readJobSummaryFromParcelLocked(name, in);
             }
 
             int NP = in.readInt();
@@ -8066,11 +8189,12 @@
                 u.mMobileRadioActiveCount.writeSummaryFromParcelLocked(out);
             }
 
-            int NW = u.mWakelockStats.size();
+            final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap();
+            int NW = wakeStats.size();
             out.writeInt(NW);
             for (int iw=0; iw<NW; iw++) {
-                out.writeString(u.mWakelockStats.keyAt(iw));
-                Uid.Wakelock wl = u.mWakelockStats.valueAt(iw);
+                out.writeString(wakeStats.keyAt(iw));
+                Uid.Wakelock wl = wakeStats.valueAt(iw);
                 if (wl.mTimerFull != null) {
                     out.writeInt(1);
                     wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -8091,18 +8215,20 @@
                 }
             }
 
-            int NS = u.mSyncStats.size();
+            final ArrayMap<String, StopwatchTimer> syncStats = u.mSyncStats.getMap();
+            int NS = syncStats.size();
             out.writeInt(NS);
             for (int is=0; is<NS; is++) {
-                out.writeString(u.mSyncStats.keyAt(is));
-                u.mSyncStats.valueAt(is).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+                out.writeString(syncStats.keyAt(is));
+                syncStats.valueAt(is).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
             }
 
-            int NJ = u.mJobStats.size();
+            final ArrayMap<String, StopwatchTimer> jobStats = u.mJobStats.getMap();
+            int NJ = jobStats.size();
             out.writeInt(NJ);
             for (int ij=0; ij<NJ; ij++) {
-                out.writeString(u.mJobStats.keyAt(ij));
-                u.mJobStats.valueAt(ij).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+                out.writeString(jobStats.keyAt(ij));
+                jobStats.valueAt(ij).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
             }
 
             int NSE = u.mSensorStats.size();
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 32cf286..5bd38f3 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -69,9 +69,8 @@
  */
 static struct fieldIds {
     jmethodID clear;
-    jmethodID setInterfaceName;
-    jmethodID addLinkAddress;
-    jmethodID addGateway;
+    jmethodID setIpAddress;
+    jmethodID setGateway;
     jmethodID addDns;
     jmethodID setDomains;
     jmethodID setServerAddress;
@@ -130,21 +129,16 @@
     if (result == 0) {
         env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear);
 
-        // set mIfaceName
-        // dhcpResults->setInterfaceName(ifname)
-        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setInterfaceName, ifname);
-
         // set the linkAddress
         // dhcpResults->addLinkAddress(inetAddress, prefixLength)
-        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.addLinkAddress,
+        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setIpAddress,
                 env->NewStringUTF(ipaddr), prefixLength);
     }
 
     if (result == 0) {
         // set the gateway
-        // dhcpResults->addGateway(gateway)
         result = env->CallBooleanMethod(dhcpResults,
-                dhcpResultsFieldIds.addGateway, env->NewStringUTF(gateway));
+                dhcpResultsFieldIds.setGateway, env->NewStringUTF(gateway));
     }
 
     if (result == 0) {
@@ -279,12 +273,10 @@
     LOG_FATAL_IF(dhcpResultsClass == NULL, "Unable to find class android/net/DhcpResults");
     dhcpResultsFieldIds.clear =
             env->GetMethodID(dhcpResultsClass, "clear", "()V");
-    dhcpResultsFieldIds.setInterfaceName =
-            env->GetMethodID(dhcpResultsClass, "setInterfaceName", "(Ljava/lang/String;)V");
-    dhcpResultsFieldIds.addLinkAddress =
-            env->GetMethodID(dhcpResultsClass, "addLinkAddress", "(Ljava/lang/String;I)Z");
-    dhcpResultsFieldIds.addGateway =
-            env->GetMethodID(dhcpResultsClass, "addGateway", "(Ljava/lang/String;)Z");
+    dhcpResultsFieldIds.setIpAddress =
+            env->GetMethodID(dhcpResultsClass, "setIpAddress", "(Ljava/lang/String;I)Z");
+    dhcpResultsFieldIds.setGateway =
+            env->GetMethodID(dhcpResultsClass, "setGateway", "(Ljava/lang/String;)Z");
     dhcpResultsFieldIds.addDns =
             env->GetMethodID(dhcpResultsClass, "addDns", "(Ljava/lang/String;)Z");
     dhcpResultsFieldIds.setDomains =
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index aee3090..7809c71 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1249,13 +1249,13 @@
         android:description="@string/permdesc_use_sip"
         android:label="@string/permlab_use_sip" />
 
-    <!-- @SystemApi Allows an application to request CallHandlerService implementations.
+    <!-- @SystemApi Allows an application to bind to InCallService implementations.
          @hide -->
-    <permission android:name="android.permission.BIND_CALL_SERVICE"
+    <permission android:name="android.permission.BIND_INCALL_SERVICE"
         android:permissionGroup="android.permission-group.PHONE_CALLS"
         android:protectionLevel="system|signature"
-        android:description="@string/permdesc_bind_call_service"
-        android:label="@string/permlab_bind_call_service" />
+        android:description="@string/permdesc_bind_incall_service"
+        android:label="@string/permlab_bind_incall_service" />
 
     <!-- @SystemApi Allows an application to bind to ConnectionService implementations.
          @hide -->
@@ -1265,6 +1265,14 @@
                 android:description="@string/permdesc_bind_connection_service"
                 android:label="@string/permlab_bind_connection_service" />
 
+    <!-- @SystemApi Allows an application to control the in-call experience.
+         @hide -->
+    <permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"
+                android:permissionGroup="android.permission-group.PHONE_CALLS"
+                android:protectionLevel="system|signature"
+                android:description="@string/permdesc_control_incall_experience"
+                android:label="@string/permlab_control_incall_experience" />
+
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
     <!-- ================================== -->
@@ -2202,14 +2210,6 @@
         android:description="@string/permdesc_modifyParentalControls"
         android:protectionLevel="signature" />
 
-    <!-- Must be required by a {@link android.media.routing.MediaRouteService}
-         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"
-        android:protectionLevel="signature" />
-
     <!-- Must be required by device administration receiver, to ensure that only the
          system can interact with it. -->
     <permission android:name="android.permission.BIND_DEVICE_ADMIN"
@@ -2775,13 +2775,6 @@
         android:description="@string/permdesc_bindConditionProviderService"
         android:protectionLevel="signature" />
 
-    <!-- Must be required by a {@link android.media.routing.MediaRouteService},
-         to ensure that only the system can bind to it. -->
-    <permission android:name="android.permission.BIND_MEDIA_ROUTE_SERVICE"
-        android:label="@string/permlab_bindMediaRouteService"
-        android:description="@string/permdesc_bindMediaRouteService"
-        android:protectionLevel="signature" />
-
     <!-- Must be required by an {@link android.service.dreams.DreamService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_DREAM_SERVICE"
@@ -2811,11 +2804,11 @@
         android:description="@string/permdesc_accessDrmCertificates"
         android:protectionLevel="signature|system" />
 
-    <!-- Api Allows an application to create media projection sessions.
+    <!-- Api Allows an application to manage media projection sessions.
          @hide This is not a third-party API (intended for system apps). -->
-    <permission android:name="android.permission.CREATE_MEDIA_PROJECTION"
-        android:label="@string/permlab_createMediaProjection"
-        android:description="@string/permdesc_createMediaProjection"
+    <permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"
+        android:label="@string/permlab_manageMediaProjection"
+        android:description="@string/permdesc_manageMediaProjection"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to read install sessions
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00001.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00001.9.png
index 9076900..c31194e 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00001.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00001.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00002.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00002.9.png
index 3c72bf8..52ed6b2 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00002.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00002.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00003.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00003.9.png
index d31e113..7b7cde586 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00003.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00003.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00004.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00004.9.png
index d0c693e..859642a 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00004.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00004.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00005.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00005.9.png
index dfa19b4..5b71dda 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00005.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00005.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00006.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00006.9.png
index 151f205..378d82d 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00006.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00006.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00007.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00007.9.png
index ad3ee2c..43c995a 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00007.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00007.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00008.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00008.9.png
index 43d66d7..c937837 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00008.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00008.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00009.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00009.9.png
index 13e4f8b..a60a127 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00009.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00009.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00010.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00010.9.png
index a09b6b2..db0bf2d 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00010.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00010.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00011.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00011.9.png
index be02e53..4a6adbe 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00011.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00011.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00012.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00012.9.png
index 655d387..98983ef 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00012.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00012.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00001.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00001.9.png
index e870a0a..8e7b62f 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00001.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00001.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00002.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00002.9.png
index 1d8f805..479a26e 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00002.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00002.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00003.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00003.9.png
index d348871..77d3130 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00003.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00003.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00004.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00004.9.png
index 941e91e..cfe684f 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00004.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00004.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00005.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00005.9.png
index adee78d..4a64a36 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00005.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00005.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00006.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00006.9.png
index e6b4ca3..29591ff 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00006.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00006.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00007.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00007.9.png
index 6c2bc0d..cf7cf49 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00007.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00007.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00008.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00008.9.png
index 763833c..2a2a9af 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00008.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00008.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00009.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00009.9.png
index 9a87fbc..1f7fe5f 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00009.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00009.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00010.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00010.9.png
index 6ccf70b..f5d7093 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00010.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00010.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00011.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00011.9.png
index d1c14a5..3878386 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00011.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00011.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00012.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00012.9.png
index c2290f0..adcb9e9 100644
--- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00012.9.png
+++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00012.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00001.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00001.9.png
index 0238898..36ed954 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00001.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00001.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00002.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00002.9.png
index ada1be9..863eee1 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00002.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00002.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00003.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00003.9.png
index 82aec64..63e93a8 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00003.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00003.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00004.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00004.9.png
index 1c6ea9f..85c851d 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00004.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00004.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00005.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00005.9.png
index ac11400..8637636 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00005.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00005.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00006.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00006.9.png
index 2025972..2945c29 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00006.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00006.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00007.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00007.9.png
index 7420fd8..678a6c8 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00007.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00007.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00008.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00008.9.png
index 1f40832..238a6f1 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00008.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00008.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00009.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00009.9.png
index cf58e44..4a342a6 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00009.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00009.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00010.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00010.9.png
index 930a280..5842b19 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00010.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00010.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00011.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00011.9.png
index ed9bc37..3e1bd2d 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00011.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00011.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00012.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00012.9.png
index cddb5b0..73ed10b 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00012.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00012.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00001.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00001.9.png
index bc1f979..03d3dfb 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00001.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00001.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00002.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00002.9.png
index e6fdbcc..25085ce 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00002.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00002.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00003.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00003.9.png
index 3d60b43..9e4d2f3 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00003.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00003.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00004.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00004.9.png
index b9afdc2..ab5bd1e 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00004.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00004.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00005.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00005.9.png
index c3c8bf2..f5297ce 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00005.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00005.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00006.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00006.9.png
index 1c7e5e1..1ad56e9 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00006.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00006.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00007.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00007.9.png
index 6329b73..4bad055 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00007.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00007.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00008.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00008.9.png
index 424202c..d908034 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00008.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00008.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00009.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00009.9.png
index 313beca..8ed4fb4 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00009.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00009.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00010.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00010.9.png
index f18d86a..61d3ced 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00010.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00010.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00011.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00011.9.png
index 8ab48c0..dec2a82 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00011.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00011.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00012.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00012.9.png
index fbc2c16..6635830 100644
--- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00012.9.png
+++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00012.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00001.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00001.9.png
index 265aeb7..df73ef7 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00001.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00001.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00002.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00002.9.png
index 2f036ad..baf52ed 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00002.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00002.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00003.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00003.9.png
index bb26440..c8f3b1c 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00003.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00003.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00004.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00004.9.png
index 1b70047..fe715cf 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00004.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00004.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00005.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00005.9.png
index b544b98..8e66e11 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00005.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00005.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00006.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00006.9.png
index c461f3d..537496e 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00006.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00006.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00007.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00007.9.png
index f57da14..2722a98 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00007.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00007.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00008.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00008.9.png
index 22c6fbc..81fad09 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00008.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00008.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00009.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00009.9.png
index cd21ac9..cda20c8 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00009.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00009.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00010.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00010.9.png
index a38dc87..a61ad4b 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00010.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00010.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00011.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00011.9.png
index d84a342..d6e8e4c 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00011.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00011.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00012.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00012.9.png
index b82a2eb..785168e 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00012.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00012.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00001.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00001.9.png
index 6a33ebf..8a648b8 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00001.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00001.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00002.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00002.9.png
index dafc250..03063d4 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00002.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00002.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00003.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00003.9.png
index 27df6ff..6159dec 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00003.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00003.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00004.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00004.9.png
index cb4121c..6f1c96c 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00004.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00004.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00005.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00005.9.png
index c5cbb75..2eaff46 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00005.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00005.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00006.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00006.9.png
index c69ef41..c4d9db8 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00006.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00006.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00007.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00007.9.png
index aff03d1..f276f16 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00007.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00007.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00008.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00008.9.png
index fb56ae6..cf9133e 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00008.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00008.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00009.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00009.9.png
index 88b9d28..8f1a6a8 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00009.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00009.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00010.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00010.9.png
index 8451958..5080c46 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00010.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00010.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00011.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00011.9.png
index 6f57654..5e39408 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00011.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00011.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00012.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00012.9.png
index 21bfc28..435ce21 100644
--- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00012.9.png
+++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00012.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00001.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00001.9.png
index c30cb5a..1eca9a9 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00001.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00001.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00002.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00002.9.png
index eaba558..5427211 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00002.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00002.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00003.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00003.9.png
index 17c18c9..43c06ab 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00003.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00003.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00004.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00004.9.png
index 0fce07a..6db3f1e 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00004.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00004.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00005.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00005.9.png
index c29b837..53b3a62 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00005.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00005.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00006.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00006.9.png
index ae56a41..7add520 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00006.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00006.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00007.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00007.9.png
index 85290ac..a4d57de 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00007.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00007.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00008.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00008.9.png
index 1e8513b..4b3a023 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00008.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00008.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00009.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00009.9.png
index 8810a12..a4caa65 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00009.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00009.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00010.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00010.9.png
index 717207f..2ab46c0 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00010.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00010.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00011.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00011.9.png
index db046f3..5c06e44 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00011.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00011.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00012.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00012.9.png
index c5c07a4..60d8c11 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00012.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00012.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00001.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00001.9.png
index c9bdf1f..b149e47 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00001.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00001.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00002.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00002.9.png
index 6bfd943..6a12a1f 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00002.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00002.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00003.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00003.9.png
index a1d3fbb..2803c7c 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00003.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00003.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00004.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00004.9.png
index 40c3a5b..032f6ea 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00004.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00004.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00005.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00005.9.png
index 26b8736..ea83c35 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00005.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00005.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00006.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00006.9.png
index 88c027e..2801f29 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00006.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00006.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00007.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00007.9.png
index 02567c6..66b89b3 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00007.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00007.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00008.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00008.9.png
index 037d3bf..1f8770c 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00008.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00008.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00009.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00009.9.png
index 0252769..0d6a95b 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00009.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00009.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00010.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00010.9.png
index 3ae501d..8e602db 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00010.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00010.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00011.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00011.9.png
index ecf2831..3143c1f 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00011.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00011.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00012.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00012.9.png
index 0877749..00fb83e 100644
--- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00012.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00012.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00001.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00001.9.png
index bc21279..786f493 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00001.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00001.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00002.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00002.9.png
index b57b592..c6e1ac1f 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00002.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00002.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00003.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00003.9.png
index 0fb9277..2a65baa 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00003.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00003.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00004.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00004.9.png
index 340722d..efce521 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00004.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00004.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00005.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00005.9.png
index 8554a76..5566524 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00005.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00005.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00006.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00006.9.png
index a05e335..ee676a6 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00006.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00006.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00007.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00007.9.png
index a5ded14..e0bb175 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00007.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00007.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00008.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00008.9.png
index 0300a49..de9eada 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00008.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00008.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00009.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00009.9.png
index 37dd7ce..3c59ad8 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00009.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00009.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00010.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00010.9.png
index 6bc549a..d524098 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00010.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00010.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00011.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00011.9.png
index b026d5d..7c08d71 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00011.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00011.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00012.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00012.9.png
index 89238dc..017c2e1 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00012.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00012.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00001.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00001.9.png
index 1d309fe..d3f2a9a 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00001.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00001.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00002.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00002.9.png
index 2e58fa9..cb75295a 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00002.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00002.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00003.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00003.9.png
index 2ebe7a7..445644e 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00003.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00003.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00004.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00004.9.png
index 04bab76..5819f90 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00004.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00004.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00005.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00005.9.png
index 3497e48..91cb90f 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00005.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00005.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00006.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00006.9.png
index 42333b4..cf6147c 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00006.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00006.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00007.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00007.9.png
index 732e175..75fca7c 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00007.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00007.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00008.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00008.9.png
index 12eddd8..b71a0b4 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00008.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00008.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00009.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00009.9.png
index 95cbc61..edb7671 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00009.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00009.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00010.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00010.9.png
index 105ec07..5e0be17 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00010.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00010.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00011.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00011.9.png
index fac253a..b727eda 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00011.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00011.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00012.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00012.9.png
index 1b8d11c..a3caefb 100644
--- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00012.9.png
+++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00012.9.png
Binary files differ
diff --git a/core/res/res/drawable/fastscroll_label_left_material.xml b/core/res/res/drawable/fastscroll_label_left_material.xml
new file mode 100644
index 0000000..430d1b0
--- /dev/null
+++ b/core/res/res/drawable/fastscroll_label_left_material.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners
+        android:topLeftRadius="44dp"
+        android:topRightRadius="44dp"
+        android:bottomRightRadius="44dp" />
+    <padding
+        android:paddingLeft="22dp"
+        android:paddingRight="22dp" />
+    <solid android:color="?attr/colorControlActivated" />
+</shape>
diff --git a/core/res/res/drawable/fastscroll_label_right_material.xml b/core/res/res/drawable/fastscroll_label_right_material.xml
new file mode 100644
index 0000000..6e61397
--- /dev/null
+++ b/core/res/res/drawable/fastscroll_label_right_material.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners
+        android:topLeftRadius="44dp"
+        android:topRightRadius="44dp"
+        android:bottomLeftRadius="44dp" />
+    <padding
+        android:paddingLeft="22dp"
+        android:paddingRight="22dp" />
+    <solid android:color="?attr/colorControlActivated" />
+</shape>
diff --git a/core/res/res/drawable/stat_notify_disabled_data.xml b/core/res/res/drawable/stat_notify_disabled_data.xml
index 2f6ffaf..9089d08 100644
--- a/core/res/res/drawable/stat_notify_disabled_data.xml
+++ b/core/res/res/drawable/stat_notify_disabled_data.xml
@@ -18,17 +18,7 @@
         android:height="24dp"
         android:viewportWidth="48.0"
         android:viewportHeight="48.0">
-
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M40.709,4.5l-6.604,7.337 0.0,16.601 6.604,6.604z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M32.305,13.838l-6.0629997,6.7370005 6.0629997,6.0629997z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M15.498,40.5l0.0,-7.9869995 -7.205,7.9869995z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M10.265,9.72l-2.5460005,2.545 9.971001,9.971 3.7139988,3.7140007 -4.105999,4.5619984 0.0,9.988001 6.6019993,0.0 0.0,-12.054001 1.8029995,1.8030014 0.0,10.250999 6.602001,0.0 0.0,-3.6479988 1.7999992,1.7999992 1.8479996,1.8479996 4.670002,4.669998 2.5459976,-2.5459976z"/>
+        android:pathData="M26.000000,4.100000l0.000000,6.100000c6.800000,1.000000 12.000000,6.800000 12.000000,13.800000c0.000000,1.800000 -0.400000,3.500000 -1.000000,5.100000l5.200000,3.100000c1.100000,-2.500000 1.800000,-5.200000 1.800000,-8.100000C44.000000,13.600000 36.099998,5.100000 26.000000,4.100000zM24.000000,38.000000c-7.700000,0.000000 -14.000000,-6.300000 -14.000000,-14.000000c0.000000,-7.100000 5.200000,-12.900000 12.000000,-13.800000L22.000000,4.100000C11.900000,5.100000 4.000000,13.600000 4.000000,24.000000c0.000000,11.000000 8.900000,20.000000 20.000000,20.000000c6.600000,0.000000 12.500000,-3.200000 16.100000,-8.200000l-5.200000,-3.100000C32.299999,36.000000 28.400000,38.000000 24.000000,38.000000z"/>
 </vector>
diff --git a/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml b/core/res/res/layout/alert_dialog_leanback_button_panel_side.xml
similarity index 80%
rename from core/res/res/layout/alert_dialog_leanback_button_panel_right.xml
rename to core/res/res/layout/alert_dialog_leanback_button_panel_side.xml
index 829d5aa..c6e8b3b 100644
--- a/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml
+++ b/core/res/res/layout/alert_dialog_leanback_button_panel_side.xml
@@ -20,13 +20,7 @@
     android:id="@+id/parentPanel"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    android:background="@drawable/dialog_background_material"
-    android:translationZ="@dimen/floating_window_z"
-    android:layout_marginLeft="@dimen/leanback_alert_dialog_horizontal_margin"
-    android:layout_marginTop="@dimen/leanback_alert_dialog_vertical_margin"
-    android:layout_marginRight="@dimen/leanback_alert_dialog_horizontal_margin"
-    android:layout_marginBottom="@dimen/leanback_alert_dialog_vertical_margin">
+    android:orientation="horizontal">
 
    <LinearLayout
        android:id="@+id/leftPanel"
@@ -46,14 +40,15 @@
             android:gravity="center_vertical|start"
             android:paddingStart="16dip"
             android:paddingEnd="16dip"
-            android:paddingTop="16dip">
+            android:paddingTop="16dip"
+            android:paddingBottom="8dip">
             <ImageView android:id="@+id/icon"
                 android:layout_width="32dip"
                 android:layout_height="32dip"
                 android:layout_marginEnd="8dip"
                 android:scaleType="fitCenter"
                 android:src="@null" />
-            <TextView android:id="@+id/alertTitle"
+            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
                 style="?attr/windowTitleStyle"
                 android:singleLine="true"
                 android:ellipsize="end"
@@ -81,7 +76,7 @@
                 android:paddingStart="16dip"
                 android:paddingEnd="16dip"
                 android:paddingTop="16dip"
-		android:paddingBottom="16dip" />
+                android:paddingBottom="16dip" />
         </ScrollView>
     </LinearLayout>
 
@@ -90,41 +85,38 @@
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:minHeight="64dp">
-        <FrameLayout android:id="@+android:id/custom"
+        <FrameLayout android:id="@+id/custom"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
     </FrameLayout>
     </LinearLayout>
 
     <LinearLayout android:id="@+id/buttonPanel"
+        style="?attr/buttonBarStyle"
         android:layout_width="wrap_content"
-android:background="#ffffff"
         android:layout_height="wrap_content"
-	android:layout_gravity="center_vertical"
-        android:minHeight="@dimen/alert_dialog_button_bar_height"
+        android:layout_gravity="center_vertical"
         android:orientation="vertical"
-        android:gravity="end"
-        android:padding="16dip">
+        android:gravity="end">
         <LinearLayout
-            style="?attr/buttonBarStyle"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layoutDirection="locale"
-	    android:orientation="vertical">
+            android:orientation="vertical">
             <Button android:id="@+id/button3"
-                style="?attr/buttonBarButtonStyle"
+                style="?attr/buttonBarNeutralButtonStyle"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:maxLines="2"
                 android:minHeight="@dimen/alert_dialog_button_bar_height" />
             <Button android:id="@+id/button2"
-                style="?attr/buttonBarButtonStyle"
+                style="?attr/buttonBarNegativeButtonStyle"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:maxLines="2"
                 android:minHeight="@dimen/alert_dialog_button_bar_height" />
             <Button android:id="@+id/button1"
-                style="?attr/buttonBarButtonStyle"
+                style="?attr/buttonBarPositiveButtonStyle"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:maxLines="2"
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index c3f9c76..5f9066a 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -31,9 +31,9 @@
             android:layout_height="wrap_content"
             android:orientation="horizontal"
             android:gravity="center_vertical|start"
-            android:paddingStart="16dip"
-            android:paddingEnd="16dip"
-            android:paddingTop="16dip"
+            android:paddingStart="@dimen/alert_dialog_padding_material"
+            android:paddingEnd="@dimen/alert_dialog_padding_material"
+            android:paddingTop="@dimen/alert_dialog_padding_material"
             android:paddingBottom="8dip">
             <ImageView android:id="@+id/icon"
                 android:layout_width="32dip"
@@ -66,10 +66,10 @@
                 style="?attr/textAppearanceMedium"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:paddingStart="16dip"
-                android:paddingEnd="16dip"
-                android:paddingTop="16dip"
-                android:paddingBottom="16dip" />
+                android:paddingStart="@dimen/alert_dialog_padding_material"
+                android:paddingEnd="@dimen/alert_dialog_padding_material"
+                android:paddingTop="@dimen/alert_dialog_padding_material"
+                android:paddingBottom="@dimen/alert_dialog_padding_material" />
         </ScrollView>
     </LinearLayout>
 
@@ -87,35 +87,33 @@
         style="?attr/buttonBarStyle"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:gravity="end">
-        <LinearLayout
-            android:layout_width="match_parent"
+        android:layoutDirection="locale"
+        android:orientation="horizontal"
+        android:paddingStart="6dp"
+        android:paddingEnd="6dp"
+        android:paddingBottom="6dp">
+        <Button android:id="@+id/button3"
+            style="?attr/buttonBarNeutralButtonStyle"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layoutDirection="locale">
-            <Button android:id="@+id/button3"
-                style="?attr/buttonBarNeutralButtonStyle"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:maxLines="2"
-                android:minHeight="@dimen/alert_dialog_button_bar_height" />
-            <Space
-                android:layout_width="0dp"
-                android:layout_height="0dp"
-                android:layout_weight="1"
-                android:visibility="invisible" />
-            <Button android:id="@+id/button2"
-                style="?attr/buttonBarNegativeButtonStyle"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:maxLines="2"
-                android:minHeight="@dimen/alert_dialog_button_bar_height" />
-            <Button android:id="@+id/button1"
-                style="?attr/buttonBarPositiveButtonStyle"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:maxLines="2"
-                android:minHeight="@dimen/alert_dialog_button_bar_height" />
-        </LinearLayout>
-     </LinearLayout>
+            android:maxLines="2"
+            android:minHeight="@dimen/alert_dialog_button_bar_height" />
+        <Space
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:visibility="invisible" />
+        <Button android:id="@+id/button2"
+            style="?attr/buttonBarNegativeButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:maxLines="2"
+            android:minHeight="@dimen/alert_dialog_button_bar_height" />
+        <Button android:id="@+id/button1"
+            style="?attr/buttonBarPositiveButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:maxLines="2"
+            android:minHeight="@dimen/alert_dialog_button_bar_height" />
+    </LinearLayout>
 </LinearLayout>
diff --git a/core/res/res/layout/time_picker_legacy_leanback.xml b/core/res/res/layout/time_picker_legacy_leanback.xml
deleted file mode 100644
index b4e5e3e..0000000
--- a/core/res/res/layout/time_picker_legacy_leanback.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/timePickerLayout"
-    android:orientation="horizontal"
-    android:layout_gravity="center_horizontal"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:paddingStart="8dip"
-    android:paddingEnd="8dip">
-
-    <LinearLayout android:orientation="horizontal"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:paddingStart="8dip"
-        android:paddingEnd="8dip"
-        android:layoutDirection="ltr">
-
-        <!-- hour -->
-        <NumberPicker
-            android:id="@+id/hour"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="16dip"
-            android:layout_marginBottom="16dip"
-            android:focusable="true"
-            android:focusableInTouchMode="true"
-            />
-
-        <!-- divider -->
-        <TextView
-            android:id="@+id/divider"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="6dip"
-            android:layout_marginEnd="6dip"
-            android:layout_gravity="center_vertical"
-            android:importantForAccessibility="no"
-            />
-
-        <!-- minute -->
-        <NumberPicker
-            android:id="@+id/minute"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="16dip"
-            android:layout_marginBottom="16dip"
-            android:focusable="true"
-            android:focusableInTouchMode="true"
-            />
-
-    </LinearLayout>
-
-    <!-- AM / PM -->
-    <NumberPicker
-        android:id="@+id/amPm"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dip"
-        android:layout_marginBottom="16dip"
-        android:layout_marginStart="8dip"
-        android:layout_marginEnd="8dip"
-        android:focusable="true"
-        android:focusableInTouchMode="true"
-        />
-
-</LinearLayout>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index e3d8420..1c83644 100644
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -38,4 +38,9 @@
         be disabled) but individual Features can be disabled using ImsConfig.setFeatureValue() -->
     <bool name="imsServiceAllowTurnOff">false</bool>
 
+    <!-- Flag specifying whether VoLTE & VT should be allowed on device: independent of the
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_mobile_allow_volte_vt">false</bool>
+
 </resources>
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
index f92ff40..a501fac 100644
--- a/core/res/res/values-television/themes.xml
+++ b/core/res/res/values-television/themes.xml
@@ -20,4 +20,6 @@
     <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
     <style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
     <style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+    <style name="Theme.Material.Dialog" parent="Theme.Leanback.Dialog" />
+    <style name="Theme.Material.Light.Dialog" parent="Theme.Leanback.Light.Dialog" />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 89bda82..f9ea5d8 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -733,6 +733,7 @@
         <attr name="fastScrollOverlayPosition">
             <enum name="floating" value="0" />
             <enum name="atThumb" value="1" />
+            <enum name="aboveThumb" value="2" />
         </attr>
         <!-- Text color for the fast scroll index overlay. Make sure it
              plays nicely with fastScrollPreviewBackground[Left|Right]. -->
@@ -3196,6 +3197,8 @@
             <enum name="floating" value="0" />
             <!-- Pinned alongside the thumb. -->
             <enum name="atThumb" value="1" />
+            <!-- Pinned above the thumb. -->
+            <enum name="aboveThumb" value="2" />
         </attr>
         <attr name="textAppearance" />
         <attr name="textColor" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 7d4c37e..e905a3a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -277,17 +277,6 @@
          applications can request this feature. Default value is false. -->
     <attr name="requiredForAllUsers" format="boolean" />
 
-    <!-- Flag to specifiy for which types of profile this application needs to be present.
-         Only pre-installed applications can request this feature. Default is none. -->
-    <attr name="requiredForProfile">
-        <!-- This application needs to be present for restricted profiles -->
-        <flag name="restricted" value="0x0001" />
-        <!-- This application needs to be present for managed profiles -->
-        <flag name="managed" value="0x0002" />
-        <!-- This application needs to be present for all types of profiles -->
-        <flag name="all" value="0xFFFF" />
-    </attr>
-
     <!-- Flag indicating whether the application can be debugged, even when
          running on a device that is running in user mode. -->
     <attr name="debuggable" format="boolean" />
@@ -1073,7 +1062,6 @@
         <attr name="hasCode" format="boolean" />
         <attr name="persistent" />
         <attr name="requiredForAllUsers" />
-        <attr name="requiredForProfile" />
         <!-- Specify whether the components in this application are enabled or not (that is, can be
              instantiated by the system).
              If "false", it overrides any component specific values (a value of "true" will not
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index dd316ed..d538352 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -128,7 +128,7 @@
     <drawable name="notification_template_icon_bg">#3333B5E5</drawable>
     <drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
 
-    <color name="notification_icon_bg_color">#ffa3a3a3</color>
+    <color name="notification_icon_bg_color">#ff9e9e9e</color>
     <color name="notification_action_legacy_color_filter">#ff555555</color>
 
     <color name="notification_media_action_bg">#00000000</color>
@@ -142,5 +142,8 @@
 
     <color name="accessibility_focus_highlight">#bf39b500</color>
 
+    <color name="system_notification_accent_color">#ff607D8B</color>
+    <color name="battery_saver_mode_color">#fff4511e</color><!-- deep orange 600 -->
+
 </resources>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bf97ca5..a59a489 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1641,6 +1641,11 @@
         be disabled) but individual Features can be disabled using ImsConfig.setFeatureValue() -->
     <bool name="imsServiceAllowTurnOff">true</bool>
 
+    <!-- Flag specifying whether VoLTE & VT should be allowed on device: independent of the
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_mobile_allow_volte_vt">true</bool>
+
     <bool name="config_networkSamplingWakesDevice">true</bool>
 
     <string-array translatable="false" name="config_cdma_home_system" />
@@ -1656,4 +1661,11 @@
     <!-- Package name providing WebView implementation. -->
     <string name="config_webViewPackageName" translatable="false">com.android.webview</string>
 
+    <!-- If EMS is not supported, framework breaks down EMS into single segment SMS
+         and adds page info " x/y". This config is used to set which carrier doesn't
+         support EMS and whether page info should be added at the beginning or the end.
+         We use tag 'prefix' for position beginning and 'suffix' for position end.
+         Examples: <item>311480;prefix</item> <item>310260;suffix</item>
+    -->
+    <string-array translatable="false" name="no_ems_support_sim_operators" />
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index a29a34c..d170fd4 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -394,4 +394,7 @@
      <dimen name="lock_pattern_dot_line_width">3dp</dimen>
      <dimen name="lock_pattern_dot_size">12dp</dimen>
      <dimen name="lock_pattern_dot_size_activated">28dp</dimen>
+
+     <dimen name="text_handle_min_size">40dp</dimen>
+
 </resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index e5a3c17..972ae5e 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -42,6 +42,8 @@
     <dimen name="text_size_headline_material">24sp</dimen>
     <dimen name="text_size_title_material">20sp</dimen>
     <dimen name="text_size_subhead_material">16sp</dimen>
+    <dimen name="text_size_title_material_toolbar">20dp</dimen>
+    <dimen name="text_size_subtitle_material_toolbar">16dp</dimen>
     <dimen name="text_size_menu_material">16sp</dimen>
     <dimen name="text_size_body_2_material">14sp</dimen>
     <dimen name="text_size_body_1_material">14sp</dimen>
@@ -71,4 +73,6 @@
 
     <!-- Default alpha value for disabled elements. -->
     <item name="disabled_alpha_material" format="float" type="dimen">0.26</item>
+
+    <dimen name="alert_dialog_padding_material">12dp</dimen>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c8edad0..7ade51d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2128,8 +2128,7 @@
   <public type="attr" name="strokeLineCap" />
   <public type="attr" name="strokeLineJoin" />
   <public type="attr" name="strokeMiterLimit" />
-  <public type="attr" name="requiredForProfile"/>
-  <public type="attr" name="colorControlNormal" />
+  <public type="attr" name="colorControlNormal" id="0x1010429"/>
   <public type="attr" name="colorControlActivated" />
   <public type="attr" name="colorButtonNormal" />
   <public type="attr" name="colorControlHighlight" />
@@ -2531,6 +2530,9 @@
   <public type="style" name="Widget.Material.Spinner.Form" />
   <public type="style" name="Widget.Material.Light.Spinner.Form" />
 
+  <public type="style" name="TextAppearance.Material.Widget.Toolbar.Title" />
+  <public type="style" name="TextAppearance.Material.Widget.Toolbar.Subtitle" />
+
   <public-padding type="string" name="l_resource_pad" end="0x01040030" />
 
   <public type="string" name="config_webSettingsDefaultTextEncoding" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c68f355..78ba738 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1160,12 +1160,6 @@
         interface of a widget service. Should never be needed for normal apps.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindRouteProvider">bind to a route provider service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindRouteProvider">Allows the holder to bind to any registered
-        route providers. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindDeviceAdmin">interact with a device admin</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindDeviceAdmin">Allows the holder to send intents to
@@ -2112,9 +2106,9 @@
     <string name="permdesc_use_sip">Allows the app to make and receive SIP calls.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bind_call_service">interact with in-call screen</string>
+    <string name="permlab_bind_incall_service">interact with in-call screen</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bind_call_service">Allows the app to control when and how the user sees the in-call screen.</string>
+    <string name="permdesc_bind_incall_service">Allows the app to control when and how the user sees the in-call screen.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bind_connection_service">interact with telephony services</string>
@@ -2122,6 +2116,11 @@
     <string name="permdesc_bind_connection_service">Allows the app to interact with telephony services to make/receive calls.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_control_incall_experience">provide an in-call user experience</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_control_incall_experience">Allows the app to provide an in-call user experience.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readNetworkUsageHistory">read historical network usage</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readNetworkUsageHistory">Allows the app to read historical network usage for specific networks and apps.</string>
@@ -2152,11 +2151,6 @@
     <string name="permdesc_bindConditionProviderService">Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindMediaRouteService">bind to a media route service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindMediaRouteService">Allows the holder to bind to the top-level interface of a media route service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindDreamService">bind to a dream service</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindDreamService">Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps.</string>
@@ -3899,10 +3893,10 @@
     <!-- Description of an application permission that lets it control keyguard. -->
     <string name="permdesc_recovery">Allows an application to interact with the recovery system and system updates.</string>
 
-    <!-- Title of an application permission that lets it create media projection sessions. -->
-    <string name="permlab_createMediaProjection">Create media projection sessions</string>
-    <!-- Description of an application permission that lets it create media projection sessions. -->
-    <string name="permdesc_createMediaProjection">Allows an application to create media projection sessions. These sessions can provide applications the ability to capture display and audio contents. Should never be needed by normal apps.</string>
+    <!-- Title of an application permission that lets it manage media projection sessions. -->
+    <string name="permlab_manageMediaProjection">Manage media projection sessions</string>
+    <!-- Description of an application permission that lets it manage media projection sessions. -->
+    <string name="permdesc_manageMediaProjection">Allows an application to manage media projection sessions. These sessions can provide applications the ability to capture display and audio contents. Should never be needed by normal apps.</string>
 
     <!-- Title of an application permission that lets it read install sessions. -->
     <string name="permlab_readInstallSessions">Read install sessions</string>
@@ -4245,15 +4239,15 @@
     <string name="data_usage_warning_body">Touch to view usage and settings.</string>
 
     <!-- Notification title when 2G-3G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
-    <string name="data_usage_3g_limit_title">2G-3G data is off</string>
+    <string name="data_usage_3g_limit_title">2G-3G data limit reached</string>
     <!-- Notification title when 4G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
-    <string name="data_usage_4g_limit_title">4G data is off</string>
+    <string name="data_usage_4g_limit_title">4G data limit reached</string>
     <!-- Notification title when mobile data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
-    <string name="data_usage_mobile_limit_title">Cellular data is off</string>
+    <string name="data_usage_mobile_limit_title">Cellular data limit reached</string>
     <!-- Notification title when Wi-Fi data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
-    <string name="data_usage_wifi_limit_title">Wi-Fi data is off</string>
+    <string name="data_usage_wifi_limit_title">Wi-Fi data limit reached</string>
     <!-- Notification body when data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
-    <string name="data_usage_limit_body">Limit reached</string>
+    <string name="data_usage_limit_body">Data paused for rest of cycle</string>
 
     <!-- Notification title when 2G-3G data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
     <string name="data_usage_3g_limit_snoozed_title">2G-3G data limit exceeded</string>
diff --git a/core/res/res/values/styles_leanback.xml b/core/res/res/values/styles_leanback.xml
index da83c36..7606c86 100644
--- a/core/res/res/values/styles_leanback.xml
+++ b/core/res/res/values/styles_leanback.xml
@@ -15,8 +15,7 @@
 -->
 <resources>
     <style name="AlertDialog.Leanback" parent="AlertDialog.Material">
-        <item name="layout">@android:layout/alert_dialog_leanback</item>
-        <item name="buttonPanelSideLayout">@android:layout/alert_dialog_leanback_button_panel_right</item>
+        <item name="buttonPanelSideLayout">@android:layout/alert_dialog_leanback_button_panel_side</item>
     </style>
 
     <style name="AlertDialog.Leanback.Light">
@@ -24,7 +23,6 @@
 
     <style name="Widget.Leanback.TimePicker" parent="Widget.Material.TimePicker">
         <item name="timePickerMode">spinner</item>
-        <item name="legacyLayout">@layout/time_picker_legacy_leanback</item>
     </style>
 
     <style name="Widget.Leanback.DatePicker" parent="Widget.Material.DatePicker">
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 0f27824..c8ea699 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -313,15 +313,38 @@
     </style>
 
     <style name="TextAppearance.Material.Widget.ActionMode"/>
-    <style name="TextAppearance.Material.Widget.ActionMode.Title" parent="TextAppearance.Material.Title" />
-    <style name="TextAppearance.Material.Widget.ActionMode.Title.Inverse" parent="TextAppearance.Material.Title.Inverse" />
-    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle" parent="TextAppearance.Material.Subhead" />
-    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Material.Subhead.Inverse" />
-
-    <style name="TextAppearance.Material.Widget.ActionBar.Title" parent="TextAppearance.Material.Title" />
-    <style name="TextAppearance.Material.Widget.ActionBar.Title.Inverse" parent="TextAppearance.Material.Title.Inverse" />
-    <style name="TextAppearance.Material.Widget.ActionBar.Subtitle" parent="TextAppearance.Material.Subhead" />
-    <style name="TextAppearance.Material.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.Material.Subhead.Inverse" />
+    <style name="TextAppearance.Material.Widget.ActionMode.Title"
+           parent="TextAppearance.Material.Title">
+        <item name="textSize">@dimen/text_size_title_material_toolbar</item>
+    </style>
+    <style name="TextAppearance.Material.Widget.ActionMode.Title.Inverse"
+           parent="TextAppearance.Material.Title.Inverse">
+        <item name="textSize">@dimen/text_size_title_material_toolbar</item>
+    </style>
+    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle"
+           parent="TextAppearance.Material.Subhead">
+        <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
+    </style>
+    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse"
+           parent="TextAppearance.Material.Subhead.Inverse">
+        <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
+    </style>
+    <style name="TextAppearance.Material.Widget.ActionBar.Title"
+           parent="TextAppearance.Material.Title">
+        <item name="textSize">@dimen/text_size_title_material_toolbar</item>
+    </style>
+    <style name="TextAppearance.Material.Widget.ActionBar.Title.Inverse"
+           parent="TextAppearance.Material.Title.Inverse">
+        <item name="textSize">@dimen/text_size_title_material_toolbar</item>
+    </style>
+    <style name="TextAppearance.Material.Widget.ActionBar.Subtitle"
+           parent="TextAppearance.Material.Subhead">
+        <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
+    </style>
+    <style name="TextAppearance.Material.Widget.ActionBar.Subtitle.Inverse"
+           parent="TextAppearance.Material.Subhead.Inverse">
+        <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
+    </style>
 
     <style name="TextAppearance.Material.Widget.ActionBar.Menu" parent="TextAppearance.Material.Menu">
         <item name="textColor">?attr/actionMenuTextColor</item>
@@ -333,6 +356,11 @@
         <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
     </style>
 
+    <style name="TextAppearance.Material.Widget.Toolbar.Title"
+           parent="TextAppearance.Material.Widget.ActionBar.Title" />
+    <style name="TextAppearance.Material.Widget.Toolbar.Subtitle"
+           parent="TextAppearance.Material.Widget.ActionBar.Subtitle" />
+
     <style name="TextAppearance.Material.WindowTitle" parent="TextAppearance.Material.Title" />
     <style name="TextAppearance.Material.DialogWindowTitle" parent="TextAppearance.Material.Title" />
 
@@ -423,12 +451,15 @@
     <style name="Widget.Material" parent="Widget" />
 
     <!-- Bordered ink button -->
-    <style name="Widget.Material.Button" parent="Widget.Button">
+    <style name="Widget.Material.Button">
         <item name="background">@drawable/btn_default_material</item>
         <item name="textAppearance">?attr/textAppearanceButton</item>
         <item name="minHeight">48dip</item>
         <item name="minWidth">88dip</item>
         <item name="stateListAnimator">@anim/button_state_list_anim_material</item>
+        <item name="focusable">true</item>
+        <item name="clickable">true</item>
+        <item name="gravity">center_vertical|center_horizontal</item>
     </style>
 
     <!-- Small bordered ink button -->
@@ -471,9 +502,6 @@
 
     <style name="Widget.Material.ButtonBar.AlertDialog">
         <item name="background">@null</item>
-        <item name="paddingStart">16dp</item>
-        <item name="paddingEnd">16dp</item>
-        <item name="paddingBottom">16dp</item>
         <item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
     </style>
 
@@ -759,6 +787,8 @@
 
     <style name="Widget.Material.Toolbar" parent="Widget.Toolbar">
         <item name="navigationButtonStyle">@style/Widget.Material.Toolbar.Button.Navigation</item>
+        <item name="titleTextAppearance">@style/TextAppearance.Material.Widget.Toolbar.Title</item>
+        <item name="subtitleTextAppearance">@style/TextAppearance.Material.Widget.Toolbar.Subtitle</item>
     </style>
 
     <style name="Widget.Material.Toolbar.Button.Navigation" parent="Widget.Toolbar.Button.Navigation">
@@ -877,6 +907,10 @@
     <style name="Widget.Material.FastScroll" parent="Widget.FastScroll">
         <item name="thumbMinWidth">0dp</item>
         <item name="thumbMinHeight">0dp</item>
+        <item name="minWidth">88dp</item>
+        <item name="minHeight">88dp</item>
+        <item name="padding">0dp</item>
+        <item name="textSize">45sp</item>
     </style>
 
     <style name="Widget.Material.PreferenceFrameLayout">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 426a82d..0b3a132 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1956,6 +1956,7 @@
   <java-symbol type="attr" name="preferenceFragmentStyle" />
   <java-symbol type="bool" name="skipHoldBeforeMerge" />
   <java-symbol type="bool" name="imsServiceAllowTurnOff" />
+  <java-symbol type="bool" name="config_mobile_allow_volte_vt" />
   <java-symbol type="bool" name="useImsAlwaysForEmergencyCall" />
   <java-symbol type="attr" name="touchscreenBlocksFocus" />
   <java-symbol type="layout" name="resolver_list_with_default" />
@@ -1982,4 +1983,8 @@
   <java-symbol type="attr" name="checkMarkGravity" />
   <java-symbol type="layout" name="select_dialog_singlechoice_material" />
   <java-symbol type="layout" name="select_dialog_multichoice_material" />
+  <java-symbol type="array" name="no_ems_support_sim_operators" />
+  <java-symbol type="color" name="battery_saver_mode_color" />
+  <java-symbol type="color" name="system_notification_accent_color" />
+  <java-symbol type="dimen" name="text_handle_min_size" />
 </resources>
diff --git a/core/res/res/values/themes_leanback.xml b/core/res/res/values/themes_leanback.xml
index 0a2c0a4..2b3b8d5 100644
--- a/core/res/res/values/themes_leanback.xml
+++ b/core/res/res/values/themes_leanback.xml
@@ -14,12 +14,33 @@
      limitations under the License.
 -->
 <resources>
+    <style name="Theme.Leanback.Dialog" parent="Theme.Material.BaseDialog">
+      <item name="colorBackground">@color/background_leanback_dark</item>
+      <item name="textColorPrimary">@color/primary_text_leanback_dark</item>
+      <item name="textColorSecondary">@color/secondary_text_leanback_dark</item>
+      <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
+      <item name="timePickerStyle">@style/Widget.Leanback.TimePicker</item>
+      <item name="datePickerStyle">@style/Widget.Leanback.DatePicker</item>
+      <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
+    </style>
+
+    <style name="Theme.Leanback.Light.Dialog" parent="Theme.Material.Light.BaseDialog">
+      <item name="colorBackground">@color/background_leanback_dark</item>
+      <item name="textColorPrimary">@color/primary_text_leanback_dark</item>
+      <item name="textColorSecondary">@color/secondary_text_leanback_dark</item>
+      <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
+      <item name="timePickerStyle">@style/Widget.Leanback.TimePicker</item>
+      <item name="datePickerStyle">@style/Widget.Leanback.DatePicker</item>
+      <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
+    </style>
+
     <style name="Theme.Leanback.Dialog.Alert" parent="Theme.Material.Dialog.BaseAlert">
       <item name="colorBackground">@color/background_leanback_dark</item>
       <item name="textColorPrimary">@color/primary_text_leanback_dark</item>
       <item name="textColorSecondary">@color/secondary_text_leanback_dark</item>
       <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
       <item name="timePickerStyle">@style/Widget.Leanback.TimePicker</item>
+      <item name="datePickerStyle">@style/Widget.Leanback.DatePicker</item>
       <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
     </style>
 
@@ -29,22 +50,13 @@
       <item name="textColorSecondary">@color/secondary_text_leanback_light</item>
       <item name="alertDialogStyle">@style/AlertDialog.Leanback.Light</item>
       <item name="timePickerStyle">@style/Widget.Leanback.TimePicker</item>
+      <item name="datePickerStyle">@style/Widget.Leanback.DatePicker</item>
       <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
     </style>
 
-    <style name="Theme.Leanback.Light.Dialog" parent="Theme.Material.Light.Dialog">
-    </style>
-
-    <style name="Theme.Leanback.Dialog" parent="Theme.Material.Dialog">
-    </style>
-
     <style name="Theme.Leanback.Dialog.AppError" parent="Theme.Leanback.Dialog">
-        <item name="windowFrame">@null</item>
-        <item name="windowBackground">@color/transparent</item>
-        <item name="windowIsFloating">true</item>
-        <item name="windowContentOverlay">@null</item>
+        <item name="windowContentTransitions">false</item>
         <item name="windowCloseOnTouchOutside">false</item>
-        <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
     </style>
 
     <!-- Setup and form wizard themes @hide @SystemApi-->
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 691ddb1..18170ac 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -364,10 +364,10 @@
 
         <!-- TODO: This belongs in a FastScroll style -->
         <item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item>
-        <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_dark</item>
-        <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_dark</item>
+        <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_material</item>
+        <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_material</item>
         <item name="fastScrollTrackDrawable">@drawable/fastscroll_track_material</item>
-        <item name="fastScrollOverlayPosition">atThumb</item>
+        <item name="fastScrollOverlayPosition">aboveThumb</item>
 
         <!-- Color palette -->
         <item name="colorPrimaryDark">@color/material_blue_grey_900</item>
@@ -706,10 +706,10 @@
         <item name="datePickerDialogTheme">?attr/dialogTheme</item>
 
         <item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item>
-        <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item>
-        <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_light</item>
+        <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_material</item>
+        <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_material</item>
         <item name="fastScrollTrackDrawable">@drawable/fastscroll_track_material</item>
-        <item name="fastScrollOverlayPosition">atThumb</item>
+        <item name="fastScrollOverlayPosition">aboveThumb</item>
 
         <!-- Color palette -->
         <item name="colorPrimaryDark">@color/material_blue_grey_100</item>
@@ -985,12 +985,7 @@
     <!-- Dialog themes for Material -->
     <eat-comment />
 
-    <!-- Material theme for dialog windows and activities, which is used by the
-         {@link android.app.Dialog} class.  This changes the window to be
-         floating (not fill the entire screen), and puts a frame around its
-         contents.  You can set this theme on an activity if you would like to
-         make an activity that looks like a Dialog. -->
-    <style name="Theme.Material.Dialog">
+    <style name="Theme.Material.BaseDialog">
         <item name="windowFrame">@null</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
         <item name="windowBackground">@drawable/dialog_background_material</item>
@@ -1019,6 +1014,13 @@
         <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
     </style>
 
+    <!-- Material theme for dialog windows and activities, which is used by the
+         {@link android.app.Dialog} class.  This changes the window to be
+         floating (not fill the entire screen), and puts a frame around its
+         contents.  You can set this theme on an activity if you would like to
+         make an activity that looks like a Dialog. -->
+    <style name="Theme.Material.Dialog" parent="Theme.Material.BaseDialog"/>
+
     <!-- Variant of Theme.Material.Dialog that has a nice minimum width for
          a regular dialog. -->
     <style name="Theme.Material.Dialog.MinWidth">
@@ -1095,12 +1097,7 @@
 
     <!-- Light material dialog themes -->
 
-    <!-- Material light theme for dialog windows and activities, which is used by the
-         {@link android.app.Dialog} class.  This changes the window to be
-         floating (not fill the entire screen), and puts a frame around its
-         contents.  You can set this theme on an activity if you would like to
-         make an activity that looks like a Dialog. -->
-    <style name="Theme.Material.Light.Dialog">
+    <style name="Theme.Material.Light.BaseDialog">
         <item name="windowFrame">@null</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
         <item name="windowBackground">@drawable/dialog_background_material</item>
@@ -1129,6 +1126,13 @@
         <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
     </style>
 
+    <!-- Material light theme for dialog windows and activities, which is used by the
+         {@link android.app.Dialog} class.  This changes the window to be
+         floating (not fill the entire screen), and puts a frame around its
+         contents.  You can set this theme on an activity if you would like to
+         make an activity that looks like a Dialog. -->
+    <style name="Theme.Material.Light.Dialog" parent="Theme.Material.Light.BaseDialog"/>
+
     <!-- Variant of Theme.Material.Light.Dialog that has a nice minimum width for
          a regular dialog. -->
     <style name="Theme.Material.Light.Dialog.MinWidth">
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 116a31e..93b16e7 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -26,8 +26,8 @@
 import android.net.IpConfiguration.IpAssignment;
 import android.net.IpConfiguration.ProxySettings;
 import android.net.LinkAddress;
-import android.net.LinkProperties;
 import android.net.RouteInfo;
+import android.net.StaticIpConfiguration;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -116,7 +116,7 @@
         boolean usercert = false;
         WifiConfiguration config = null;
         int securityType = NONE;
-        LinkProperties mLinkProperties = null;
+        StaticIpConfiguration mStaticIpConfiguration = null;
         InetAddress mInetAddr = null;
 
         @Override
@@ -153,7 +153,7 @@
                 usercert = true;
             }
             if (tagName.equalsIgnoreCase("ip")) {
-                mLinkProperties = new LinkProperties();
+                mStaticIpConfiguration = new StaticIpConfiguration();
                 ip = true;
             }
             if (tagName.equalsIgnoreCase("gateway")) {
@@ -173,15 +173,15 @@
         @Override
         public void endElement(String uri, String localName, String tagName) throws SAXException {
             if (tagName.equalsIgnoreCase("accesspoint")) {
-                if (mLinkProperties != null) {
+                if (mStaticIpConfiguration != null) {
                     config.setIpAssignment(IpAssignment.STATIC);
-                    config.setLinkProperties(mLinkProperties);
+                    config.setStaticIpConfiguration(mStaticIpConfiguration);
                 } else {
                     config.setIpAssignment(IpAssignment.DHCP);
                 }
                 config.setProxySettings(ProxySettings.NONE);
                 networks.add(config);
-                mLinkProperties = null;
+                mStaticIpConfiguration = null;
             }
         }
 
@@ -312,7 +312,7 @@
                     if (!InetAddress.isNumeric(gwAddr)) {
                         throw new SAXException();
                     }
-                    mLinkProperties.addRoute(new RouteInfo(InetAddress.getByName(gwAddr)));
+                    mStaticIpConfiguration.gateway = InetAddress.getByName(gwAddr);
                 } catch (UnknownHostException e) {
                     throw new SAXException();
                 }
@@ -324,7 +324,7 @@
                     if ((nwPrefixLength < 0) || (nwPrefixLength > 32)) {
                         throw new SAXException();
                     }
-                    mLinkProperties.addLinkAddress(new LinkAddress(mInetAddr, nwPrefixLength));
+                    mStaticIpConfiguration.ipAddress = new LinkAddress(mInetAddr, nwPrefixLength);
                 } catch (NumberFormatException e) {
                     throw new SAXException();
                 }
@@ -336,7 +336,7 @@
                     if (!InetAddress.isNumeric(dnsAddr)) {
                         throw new SAXException();
                     }
-                    mLinkProperties.addDnsServer(InetAddress.getByName(dnsAddr));
+                    mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(dnsAddr));
                 } catch (UnknownHostException e) {
                     throw new SAXException();
                 }
@@ -348,7 +348,7 @@
                     if (!InetAddress.isNumeric(dnsAddr)) {
                         throw new SAXException();
                     }
-                    mLinkProperties.addDnsServer(InetAddress.getByName(dnsAddr));
+                    mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(dnsAddr));
                 } catch (UnknownHostException e) {
                     throw new SAXException();
                 }
diff --git a/data/fonts/AndroidClock.ttf b/data/fonts/AndroidClock.ttf
index 4781ccd..a955442 100644
--- a/data/fonts/AndroidClock.ttf
+++ b/data/fonts/AndroidClock.ttf
Binary files differ
diff --git a/data/fonts/AndroidClock_Highlight.ttf b/data/fonts/AndroidClock_Highlight.ttf
index 3fa6d88..923bb30 100644
--- a/data/fonts/AndroidClock_Highlight.ttf
+++ b/data/fonts/AndroidClock_Highlight.ttf
Binary files differ
diff --git a/data/fonts/AndroidClock_Solid.ttf b/data/fonts/AndroidClock_Solid.ttf
index 3fa6d88..923bb30 100644
--- a/data/fonts/AndroidClock_Solid.ttf
+++ b/data/fonts/AndroidClock_Solid.ttf
Binary files differ
diff --git a/data/fonts/Clockopia.ttf b/data/fonts/Clockopia.ttf
index 123ea4f..3f7b6aa 100644
--- a/data/fonts/Clockopia.ttf
+++ b/data/fonts/Clockopia.ttf
Binary files differ
diff --git a/data/fonts/DroidSansFallback.ttf b/data/fonts/DroidSansFallback.ttf
index 03f49a8..96b16bb 100644
--- a/data/fonts/DroidSansFallback.ttf
+++ b/data/fonts/DroidSansFallback.ttf
Binary files differ
diff --git a/data/fonts/DroidSansFallbackFull.ttf b/data/fonts/DroidSansFallbackFull.ttf
index 1dfcc33..89959f5 100644
--- a/data/fonts/DroidSansFallbackFull.ttf
+++ b/data/fonts/DroidSansFallbackFull.ttf
Binary files differ
diff --git a/data/fonts/DroidSansMono.ttf b/data/fonts/DroidSansMono.ttf
index a007071..4085cee 100644
--- a/data/fonts/DroidSansMono.ttf
+++ b/data/fonts/DroidSansMono.ttf
Binary files differ
diff --git a/data/fonts/MTLc3m.ttf b/data/fonts/MTLc3m.ttf
index 86bdcc7..e9018f6 100644
--- a/data/fonts/MTLc3m.ttf
+++ b/data/fonts/MTLc3m.ttf
Binary files differ
diff --git a/data/fonts/MTLmr3m.ttf b/data/fonts/MTLmr3m.ttf
index 91dd47f..14f27d4 100644
--- a/data/fonts/MTLmr3m.ttf
+++ b/data/fonts/MTLmr3m.ttf
Binary files differ
diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk
index ed9bea5..f6d8ee9 100644
--- a/data/sounds/AllAudio.mk
+++ b/data/sounds/AllAudio.mk
@@ -226,6 +226,7 @@
     $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
     $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
     $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+    $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \
     $(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
     $(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
     $(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
diff --git a/data/sounds/AudioPackage10.mk b/data/sounds/AudioPackage10.mk
index ae4bc88..879e57a 100644
--- a/data/sounds/AudioPackage10.mk
+++ b/data/sounds/AudioPackage10.mk
@@ -30,6 +30,7 @@
 	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \
 	$(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
diff --git a/data/sounds/AudioPackage11.mk b/data/sounds/AudioPackage11.mk
index 3c09297..03e205b 100644
--- a/data/sounds/AudioPackage11.mk
+++ b/data/sounds/AudioPackage11.mk
@@ -30,6 +30,7 @@
 	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \
 	$(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
diff --git a/data/sounds/AudioPackage12.mk b/data/sounds/AudioPackage12.mk
index af89a82..c37c392 100644
--- a/data/sounds/AudioPackage12.mk
+++ b/data/sounds/AudioPackage12.mk
@@ -12,7 +12,8 @@
 NOTIFICATION_FILES := Ariel Ceres Carme Elara Europa Iapetus Io Rhea Salacia Titan Tethys
 RINGTONE_FILES := Callisto Dione Ganymede Luna Oberon Phobos Sedna Titania Triton Umbriel
 EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete KeypressSpacebar KeypressStandard \
-	VideoRecord camera_click camera_focus LowBattery Dock Undock Lock Unlock WirelessChargingStarted
+	VideoRecord camera_click camera_focus LowBattery Dock Undock Lock Unlock WirelessChargingStarted \
+	Trusted
 
 PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
 	$(LOCAL_PATH)/alarms/ogg/$(fn).ogg:system/media/audio/alarms/$(fn).ogg)
diff --git a/data/sounds/AudioPackage12_48.mk b/data/sounds/AudioPackage12_48.mk
index 636bb9f..2a5efb0 100644
--- a/data/sounds/AudioPackage12_48.mk
+++ b/data/sounds/AudioPackage12_48.mk
@@ -12,7 +12,7 @@
 NOTIFICATION_FILES := Ariel Ceres Carme Elara Europa Iapetus Io Rhea Salacia Titan Tethys
 RINGTONE_FILES := Callisto Dione Ganymede Luna Oberon Phobos Sedna Titania Triton Umbriel
 EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete KeypressSpacebar KeypressStandard \
-	VideoRecord camera_click Lock Unlock
+	VideoRecord camera_click Lock Unlock Trusted
 
 # Alarms not yet available in 48 kHz
 PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
@@ -33,4 +33,4 @@
     $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
     $(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
     $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
-    $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg
+    $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg
\ No newline at end of file
diff --git a/data/sounds/AudioPackage2.mk b/data/sounds/AudioPackage2.mk
index ea07acd..ba9d7e2 100644
--- a/data/sounds/AudioPackage2.mk
+++ b/data/sounds/AudioPackage2.mk
@@ -40,6 +40,7 @@
 	$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
 	$(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \
 	$(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \
 	$(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \
diff --git a/data/sounds/AudioPackage3.mk b/data/sounds/AudioPackage3.mk
index a8a3b76..5bfeb42 100644
--- a/data/sounds/AudioPackage3.mk
+++ b/data/sounds/AudioPackage3.mk
@@ -40,6 +40,7 @@
 	$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
 	$(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \
 	$(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \
 	$(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \
diff --git a/data/sounds/AudioPackage4.mk b/data/sounds/AudioPackage4.mk
index bde3ba0..43dbe20 100644
--- a/data/sounds/AudioPackage4.mk
+++ b/data/sounds/AudioPackage4.mk
@@ -45,6 +45,7 @@
 	$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
 	$(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \
 	$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
 	$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
diff --git a/data/sounds/AudioPackage5.mk b/data/sounds/AudioPackage5.mk
index 077335b..fbbb16a 100644
--- a/data/sounds/AudioPackage5.mk
+++ b/data/sounds/AudioPackage5.mk
@@ -27,6 +27,7 @@
 	$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
 	$(LOCAL_PATH)/notifications/Aldebaran.ogg:system/media/audio/notifications/Aldebaran.ogg \
 	$(LOCAL_PATH)/notifications/Altair.ogg:system/media/audio/notifications/Altair.ogg \
 	$(LOCAL_PATH)/notifications/Antares.ogg:system/media/audio/notifications/Antares.ogg \
diff --git a/data/sounds/AudioPackage6.mk b/data/sounds/AudioPackage6.mk
index 2cdd702..3205c0e 100644
--- a/data/sounds/AudioPackage6.mk
+++ b/data/sounds/AudioPackage6.mk
@@ -26,6 +26,7 @@
 	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Antimony.ogg:system/media/audio/notifications/Antimony.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Argon.ogg:system/media/audio/notifications/Argon.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Beryllium.ogg:system/media/audio/notifications/Beryllium.ogg \
diff --git a/data/sounds/AudioPackage7.mk b/data/sounds/AudioPackage7.mk
index e909235..c92c1d0 100644
--- a/data/sounds/AudioPackage7.mk
+++ b/data/sounds/AudioPackage7.mk
@@ -28,6 +28,7 @@
 	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \
diff --git a/data/sounds/AudioPackage7alt.mk b/data/sounds/AudioPackage7alt.mk
index 1132fa9..9c35a2e 100644
--- a/data/sounds/AudioPackage7alt.mk
+++ b/data/sounds/AudioPackage7alt.mk
@@ -27,6 +27,7 @@
 	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \
diff --git a/data/sounds/AudioPackage8.mk b/data/sounds/AudioPackage8.mk
index 0f4b8ad..b8be4e3e 100644
--- a/data/sounds/AudioPackage8.mk
+++ b/data/sounds/AudioPackage8.mk
@@ -30,6 +30,7 @@
 	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \
diff --git a/data/sounds/AudioPackage9.mk b/data/sounds/AudioPackage9.mk
index 36dc921..9b761bc 100644
--- a/data/sounds/AudioPackage9.mk
+++ b/data/sounds/AudioPackage9.mk
@@ -30,6 +30,7 @@
 	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
diff --git a/data/sounds/effects/ogg/Trusted.ogg b/data/sounds/effects/ogg/Trusted.ogg
new file mode 100644
index 0000000..d7f65ee
--- /dev/null
+++ b/data/sounds/effects/ogg/Trusted.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/Trusted_48k.ogg b/data/sounds/effects/ogg/Trusted_48k.ogg
new file mode 100644
index 0000000..2b63c39
--- /dev/null
+++ b/data/sounds/effects/ogg/Trusted_48k.ogg
Binary files differ
diff --git a/docs/html/google/play/billing/billing_reference.jd b/docs/html/google/play/billing/billing_reference.jd
index e168d70..4f5e65c 100644
--- a/docs/html/google/play/billing/billing_reference.jd
+++ b/docs/html/google/play/billing/billing_reference.jd
@@ -102,15 +102,28 @@
   </tr>
   <tr>
     <td>{@code type}</td>
-    <td>Value must be “inapp” for an in-app product or "subs" for 
+    <td>Value must be “inapp” for an in-app product or "subs" for
 subscriptions.</td>
   </tr>
   <tr>
     <td>{@code price}</td>
-    <td>Formatted price of the item, including its currency sign. The price 
+    <td>Formatted price of the item, including its currency sign. The price
 does not include tax.</td>
   </tr>
   <tr>
+    <td>{@code price_amount_micros}</td>
+    <td>Price in micro-units, where 1,000,000 micro-units equal one unit of the
+    currency. For example, if {@code price} is {@code "€7.99"}, {@code
+    price_amount_micros} is {@code "7990000"}.</td>
+  </tr>
+  <tr>
+    <td>{@code price_currency_code}</td>
+    <td><a href="http://en.wikipedia.org/wiki/ISO_4217#Active_codes">ISO 4217
+    currency code</a> for {@code price}. For example, if {@code price} is
+    specified in British pounds sterling, {@code price_currency_code} is {@code
+    "GBP"}.</td>
+  </tr>
+  <tr>
     <td>{@code title}</td>
     <td>Title of the product.</td>
   </tr>
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index b4813a5..3b52b0a 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -1316,7 +1316,7 @@
 <dt>{@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS MediaStore.EXTRA_MEDIA_FOCUS} (required)</dt>
 <dd>
 <p>Indicates the search mode (whether the user is looking for a particular artist, album, song,
-playlist, or radio channel). Most search modes take additional extras. For example, if the user
+or playlist). Most search modes take additional extras. For example, if the user
 is interested in listening to a particular song, the intent might have three additional extras:
 the song title, the artist, and the album. This intent supports the following search modes for
 each value of {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS}:</p>
@@ -1399,24 +1399,6 @@
       intent as an unstructured search.</li>
 </ul>
 </dd>
-<dt><p><em>Radio channel</em> - <code>"vnd.android.cursor.item/radio"</code></p></dt>
-<dd>
-<p>Play a particular radio channel or a radio channel that matches some criteria specified
-by additional extras.</p>
-<p>Additional extras:</p>
-<ul>
-  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ALBUM} - The album.</li>
-  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ARTIST} - The artist.</li>
-  <li><code>"android.intent.extra.genre"</code> - The genre.</li>
-  <li><code>"android.intent.extra.radio_channel"</code> - The radio channel.</li>
-  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_TITLE} - The song name that the radio
-      channel is based on.</li>
-  <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination
-      of: the album, the artist, the genre, the radio channel, or the title. This extra is
-      always provided for backward compatibility: existing apps that do not know about search
-      modes can process this intent as an unstructured search.</li>
-</ul>
-</dd>
 <dt><p><em>Playlist</em> - {@link android.provider.MediaStore.Audio.Playlists#ENTRY_CONTENT_TYPE Audio.Playlists.ENTRY_CONTENT_TYPE}</p></dt>
 <dd>
 <p>Play a particular playlist or a playlist that matches some criteria specified
@@ -1444,13 +1426,13 @@
 
 
 <p><b>Example intent:</b></p>
-<p>If the user wants to listen to a radio station that plays songs from a particular artist,
-a search app may generate the following intent:</p>
+<p>If the user wants to listen to music from a particular artist, a search app may generate the
+following intent:</p>
 <pre>
-public void playSearchRadioByArtist(String artist) {
+public void playSearchArtist(String artist) {
     Intent intent = new Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH);
     intent.putExtra(MediaStore.EXTRA_MEDIA_FOCUS,
-                    "vnd.android.cursor.item/radio");
+                    MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE);
     intent.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, artist);
     intent.putExtra(SearchManager.QUERY, artist);
     if (intent.resolveActivity(getPackageManager()) != null) {
@@ -1488,7 +1470,6 @@
         String artist = intent.getStringExtra(MediaStore.EXTRA_MEDIA_ARTIST);
         String genre = intent.getStringExtra("android.intent.extra.genre");
         String playlist = intent.getStringExtra("android.intent.extra.playlist");
-        String rchannel = intent.getStringExtra("android.intent.extra.radio_channel");
         String title = intent.getStringExtra(MediaStore.EXTRA_MEDIA_TITLE);
 
         // Determine the search mode and use the corresponding extras
@@ -1521,10 +1502,6 @@
             // 'Song' search mode
             playSong(album, artist, genre, title);
 
-        } else if (mediaFocus.compareTo("vnd.android.cursor.item/radio") == 0) {
-            // 'Radio channel' search mode
-            playRadioChannel(album, artist, genre, rchannel, title);
-
         } else if (mediaFocus.compareTo(MediaStore.Audio.Playlists.ENTRY_CONTENT_TYPE) == 0) {
             // 'Playlist' search mode
             playPlaylist(album, artist, genre, playlist, title);
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index e7f93bc..71d6c1c 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -251,36 +251,36 @@
     <td>Windows</td>
     <td>
   <a onclick="return onDownload(this)" id="win-studio"
-      href="http://dl.google.com/android/studio/install/0.8.0/android-studio-bundle-135.1245622-windows.exe">
-      android-studio-bundle-135.1245622-windows.exe
+      href="http://dl.google.com/android/studio/install/0.8.6/android-studio-bundle-135.1339820-windows.exe">
+      android-studio-bundle-135.1339820-windows.exe
       </a>
     </td>
-    <td>380000036 bytes</td>
-    <td>5720baef7d492f2df7398a38dae2fa92</td>
+    <td>379497130 bytes</td>
+    <td>024e002b8c8fa7dcd2ff69fd69e06e56</td>
   </tr>
 
   <tr>
     <td><nobr>Mac OS X</nobr></td>
     <td>
   <a onclick="return onDownload(this)" id="mac-studio"
-    href="http://dl.google.com/android/studio/install/0.8.0/android-studio-bundle-135.1245622-mac.dmg">
-    android-studio-bundle-135.1245622-mac.dmg
+    href="http://dl.google.com/android/studio/install/0.8.6/android-studio-bundle-135.1339820-mac.dmg">
+    android-studio-bundle-135.1339820-mac.dmg
     </a>
     </td>
-    <td>368451923 bytes</td>
-    <td>fa9da3625db44687576c5c4e8f96280e</td>
+    <td>368507143 bytes</td>
+    <td>4143f2aa556634eae91701965d88899b</td>
   </tr>
 
   <tr>
     <td>Linux</td>
     <td>
   <a onclick="return onDownload(this)" id="linux-studio"
-    href="http://dl.google.com/android/studio/install/0.8.0/android-studio-bundle-135.1245622-linux.tgz">
-    android-studio-bundle-135.1245622-linux.tgz
+    href="http://dl.google.com/android/studio/install/0.8.6/android-studio-bundle-135.1339820-linux.tgz">
+    android-studio-bundle-135.1339820-linux.tgz
     </a>
     </td>
-    <td>417756987 bytes</td>
-    <td>c70dd2e4035484b84f0ad0046a34f136</td>
+    <td>417631443 bytes</td>
+    <td>fa403762ecd0a5da87acbeff485f81cc</td>
   </tr>
   </table>
 
@@ -450,6 +450,17 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Studio v0.8.6</a> <em>(August 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+    <p>See <a href="http://tools.android.com/recent">tools.android.com</a> for a full list of changes.</p>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Studio v0.8.0</a> <em>(June 2014)</em>
   </p>
 
@@ -636,7 +647,7 @@
   if (os) {
     /* set up primary ACE download button */
     $('#download-ide-button').show();
-    $('#download-ide-button').append("Download Android Studio Beta <span class='small'>v0.8.0</span>"
+    $('#download-ide-button').append("Download Android Studio Beta <span class='small'>v0.8.6</span>"
         + "<br/> <span class='small'>with the Android SDK for " + os + "</span>");
     $('#download-ide-button').click(function() {return onDownload(this,true);}).attr('href', bundlename);
 
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 3177023..4bf0b71 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -18,15 +18,15 @@
 
 import android.annotation.NonNull;
 import android.graphics.drawable.Drawable;
-import android.view.View;
 
 /**
  * Defines a simple shape, used for bounding graphical regions.
  * <p>
- * Can be used with a View, or computed by a Drawable, to drive the shape of shadows cast by a
- * View, or to clip the contents of the View.
+ * Can be computed for a View, or computed by a Drawable, to drive the shape of
+ * shadows cast by a View, or to clip the contents of the View.
  *
- * @see View#setOutline(Outline)
+ * @see android.view.ViewOutlineProvider
+ * @see android.view.View#setOutlineProvider(android.view.ViewOutlineProvider)
  * @see Drawable#getOutline(Outline)
  */
 public final class Outline {
@@ -79,21 +79,27 @@
 
     /**
      * Returns whether the outline can be used to clip a View.
+     * <p>
+     * Currently, only Outlines that can be represented as a rectangle, circle,
+     * or round rect support clipping.
      *
-     * Currently, only outlines that can be represented as a rectangle, circle, or round rect
-     * support clipping.
-     *
-     * @see {@link View#setClipToOutline(boolean)}
+     * @see {@link android.view.View#setClipToOutline(boolean)}
      */
     public boolean canClip() {
         return !isEmpty() && mRect != null;
     }
 
     /**
-     * Sets the alpha represented by the Outline.
-     *
-     * Content producing a fully opaque (alpha = 1.0f) outline is assumed by the drawing system
-     * to fully cover content beneath it, meaning content beneath may be optimized away.
+     * Sets the alpha represented by the Outline - the degree to which the
+     * producer is guaranteed to be opaque over the Outline's shape.
+     * <p>
+     * An alpha value of <code>0.0f</code> either represents completely
+     * transparent content, or content that isn't guaranteed to fill the shape
+     * it publishes.
+     * <p>
+     * Content producing a fully opaque (alpha = <code>1.0f</code>) outline is
+     * assumed by the drawing system to fully cover content beneath it,
+     * meaning content beneath may be optimized away.
      */
     public void setAlpha(float alpha) {
         mAlpha = alpha;
@@ -130,7 +136,8 @@
     }
 
     /**
-     * Sets the Outline to the rounded rect defined by the input rect, and corner radius.
+     * Sets the Outline to the rounded rect defined by the input rect, and
+     * corner radius.
      */
     public void setRect(int left, int top, int right, int bottom) {
         setRoundRect(left, top, right, bottom, 0.0f);
@@ -145,7 +152,7 @@
 
     /**
      * Sets the Outline to the rounded rect defined by the input rect, and corner radius.
-     *
+     * <p>
      * Passing a zero radius is equivalent to calling {@link #setRect(int, int, int, int)}
      */
     public void setRoundRect(int left, int top, int right, int bottom, float radius) {
@@ -196,7 +203,8 @@
     }
 
     /**
-     * Sets the Constructs an Outline from a {@link android.graphics.Path#isConvex() convex path}.
+     * Sets the Constructs an Outline from a
+     * {@link android.graphics.Path#isConvex() convex path}.
      */
     public void setConvexPath(@NonNull Path convexPath) {
         if (convexPath.isEmpty()) {
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 1c76d9c..652fe64 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1109,9 +1109,16 @@
      * This draws a shadow layer below the main layer, with the specified
      * offset and color, and blur radius. If radius is 0, then the shadow
      * layer is removed.
+     * <p>
+     * Can be used to create a blurred shadow underneath text. Support for use
+     * with other drawing operations is constrained to the software rendering
+     * pipeline.
+     * <p>
+     * The alpha of the shadow will be the paint's alpha if the shadow color is
+     * opaque, or the alpha from the shadow color if not.
      */
-    public void setShadowLayer(float radius, float dx, float dy, int color) {
-      native_setShadowLayer(mNativePaint, radius, dx, dy, color);
+    public void setShadowLayer(float radius, float dx, float dy, int shadowColor) {
+      native_setShadowLayer(mNativePaint, radius, dx, dy, shadowColor);
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 5318fa7..d87e8e4 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -114,7 +114,9 @@
         final boolean changed = super.setVisible(visible, restart);
         if (visible) {
             if (restart || changed) {
-                setFrame(restart ? 0 : mCurFrame, true, mAnimating);
+                boolean startFromZero = restart || mCurFrame < 0 ||
+                        mCurFrame >= mAnimationState.getChildCount();
+                setFrame(startFromZero ? 0 : mCurFrame, true, mAnimating);
             }
         } else {
             unscheduleSelf(this);
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 40adf94..e52d778 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -602,9 +602,9 @@
     @Override
     public void getOutline(@NonNull Outline outline) {
         super.getOutline(outline);
-        if (mBitmapState.mBitmap.hasAlpha()) {
-            // Bitmaps with alpha can't report a non-0 alpha,
-            // since they may not fill their rectangular bounds
+        if (mBitmapState.mBitmap == null || mBitmapState.mBitmap.hasAlpha()) {
+            // Only opaque Bitmaps can report a non-0 alpha,
+            // since only they are guaranteed to fill their bounds
             outline.setAlpha(0.0f);
         }
     }
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index a383aab..29b9141 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -820,7 +820,7 @@
 
     @Override
     public int getOpacity() {
-        return (mAlpha == 255 && mGradientState.mOpaque) ?
+        return (mAlpha == 255 && mGradientState.mOpaqueOverBounds) ?
                 PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT;
     }
 
@@ -1413,7 +1413,8 @@
     public void getOutline(Outline outline) {
         final GradientState st = mGradientState;
         final Rect bounds = getBounds();
-        outline.setAlpha(mAlpha / 255.0f);
+        // only report non-zero alpha if shape being drawn is opaque
+        outline.setAlpha(st.mOpaqueOverShape ? (mAlpha / 255.0f) : 0.0f);
 
         switch (st.mShape) {
             case RECTANGLE:
@@ -1492,7 +1493,8 @@
         private int mGradientRadiusType = RADIUS_TYPE_PIXELS;
         private boolean mUseLevel;
         private boolean mUseLevelForShape;
-        private boolean mOpaque;
+        private boolean mOpaqueOverBounds;
+        private boolean mOpaqueOverShape;
 
         int[] mThemeAttrs;
         int[] mAttrSize;
@@ -1544,7 +1546,7 @@
             mGradientRadiusType = state.mGradientRadiusType;
             mUseLevel = state.mUseLevel;
             mUseLevelForShape = state.mUseLevelForShape;
-            mOpaque = state.mOpaque;
+            mOpaqueOverBounds = state.mOpaqueOverBounds;
             mThemeAttrs = state.mThemeAttrs;
             mAttrSize = state.mAttrSize;
             mAttrGradient = state.mAttrGradient;
@@ -1606,40 +1608,36 @@
         }
 
         private void computeOpacity() {
-            if (mShape != RECTANGLE) {
-                mOpaque = false;
-                return;
-            }
+            mOpaqueOverBounds = false;
+            mOpaqueOverShape = false;
 
-            if (mRadius > 0 || mRadiusArray != null) {
-                mOpaque = false;
-                return;
-            }
-
+            // First test opacity of all colors
             if (mStrokeWidth > 0) {
                 if (mStrokeColorStateList != null) {
                     if (!mStrokeColorStateList.isOpaque()) {
-                        mOpaque = false;
                         return;
                     }
                 }
             }
 
             if (mColorStateList != null && !mColorStateList.isOpaque()) {
-                mOpaque = false;
                 return;
             }
 
             if (mColors != null) {
                 for (int i = 0; i < mColors.length; i++) {
                     if (!isOpaque(mColors[i])) {
-                        mOpaque = false;
                         return;
                     }
                 }
             }
 
-            mOpaque = true;
+            // Colors are opaque, so opaqueOverShape=true,
+            mOpaqueOverShape = true;
+            // and opaqueOverBounds=true if shape fills bounds
+            mOpaqueOverBounds = mShape == RECTANGLE
+                    && mRadius <= 0
+                    && mRadiusArray == null;
         }
 
         private static boolean isOpaque(int color) {
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 588e776..dd0f06f 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -26,10 +26,13 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
-import android.graphics.*;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Insets;
+import android.graphics.Outline;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.Log;
 
 import java.io.IOException;
 
@@ -50,8 +53,6 @@
  * @attr ref android.R.styleable#InsetDrawable_insetBottom
  */
 public class InsetDrawable extends Drawable implements Drawable.Callback {
-    private static final String LOG_TAG = "InsetDrawable";
-
     private final Rect mTmpRect = new Rect();
 
     private InsetState mInsetState;
@@ -86,7 +87,6 @@
         final TypedArray a = r.obtainAttributes(attrs, R.styleable.InsetDrawable);
         super.inflateWithAttributes(r, parser, a, R.styleable.InsetDrawable_visible);
         updateStateFromTypedArray(a);
-        a.recycle();
 
         // Load inner XML elements.
         if (mInsetState.mDrawable == null) {
@@ -104,9 +104,17 @@
             dr.setCallback(this);
         }
 
-        // Verify state.
-        if (mInsetState.mDrawable == null) {
-            Log.w(LOG_TAG, "No drawable specified for <inset>");
+        verifyRequiredAttributes(a);
+        a.recycle();
+    }
+
+    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (mInsetState.mDrawable == null && (mInsetState.mThemeAttrs == null
+                || mInsetState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription() +
+                    ": <inset> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
         }
     }
 
@@ -167,6 +175,7 @@
         final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.InsetDrawable);
         try {
             updateStateFromTypedArray(a);
+            verifyRequiredAttributes(a);
         } catch (XmlPullParserException e) {
             throw new RuntimeException(e);
         } finally {
@@ -224,12 +233,8 @@
         padding.top += mInsetState.mInsetTop;
         padding.bottom += mInsetState.mInsetBottom;
 
-        if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight |
-                    mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0) {
-            return true;
-        } else {
-            return false;
-        }
+        return pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight |
+                mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0;
     }
 
     /** @hide */
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 0aa1b0d..c185a9e 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -446,19 +446,8 @@
                         ": <nine-patch> requires a valid 9-patch source image");
             }
 
-            // Hey, now might be a good time to actually load optical bounds!
             bitmap.getOpticalInsets(opticalInsets);
 
-            // Sanity check for valid padding when we have optical insets.
-            if (padding.left < opticalInsets.left) {
-                padding.left = opticalInsets.left;
-                padding.right = opticalInsets.right;
-            }
-            if (padding.top < opticalInsets.top) {
-                padding.top = opticalInsets.top;
-                padding.bottom = opticalInsets.bottom;
-            }
-
             state.mNinePatch = new NinePatch(bitmap, bitmap.getNinePatchChunk());
             state.mPadding = padding;
             state.mOpticalInsets = Insets.of(opticalInsets);
@@ -626,21 +615,6 @@
             mOpticalInsets = Insets.of(opticalInsets);
             mDither = dither;
             mAutoMirrored = autoMirror;
-
-            // Sanity check for valid padding when we have optical insets.
-            if (opticalInsets != null && !opticalInsets.isEmpty()) {
-                if (mPadding == null) {
-                    mPadding = new Rect();
-                }
-                if (mPadding.left < opticalInsets.left) {
-                    mPadding.left = opticalInsets.left;
-                    mPadding.right = opticalInsets.right;
-                }
-                if (mPadding.top < opticalInsets.top) {
-                    mPadding.top = opticalInsets.top;
-                    mPadding.bottom = opticalInsets.bottom;
-                }
-            }
         }
 
         // Copy constructor
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index c6d3db7..5f533a7 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -208,6 +208,8 @@
         // ensure that local bounds cover mapped bounds
         if (!state.mMatrix.isSimple()) return false;
 
+        if (state.mRoundRectClipState) return false;
+
         // check state/paint for transparency
         if (mPaint) {
             if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) {
@@ -999,6 +1001,8 @@
 public:
     DrawStrokableOp(float left, float top, float right, float bottom, const SkPaint* paint)
             : DrawBoundedOp(left, top, right, bottom, paint) {};
+    DrawStrokableOp(const Rect& localBounds, const SkPaint* paint)
+            : DrawBoundedOp(localBounds, paint) {};
 
     virtual bool getLocalBounds(Rect& localBounds) {
         localBounds.set(mLocalBounds);
@@ -1337,11 +1341,11 @@
     const float* mPositions;
 };
 
-class DrawTextOp : public DrawBoundedOp {
+class DrawTextOp : public DrawStrokableOp {
 public:
     DrawTextOp(const char* text, int bytesCount, int count, float x, float y,
             const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds)
-            : DrawBoundedOp(bounds, paint), mText(text), mBytesCount(bytesCount), mCount(count),
+            : DrawStrokableOp(bounds, paint), mText(text), mBytesCount(bytesCount), mCount(count),
             mX(x), mY(y), mPositions(positions), mTotalAdvance(totalAdvance) {
         mPrecacheTransform = SkMatrix::InvalidMatrix();
     }
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 94162fc..9a9c544 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -376,7 +376,7 @@
         float x, float y, const float* positions, const SkPaint* paint,
         float totalAdvance, const Rect& bounds, DrawOpMode drawOpMode) {
 
-    if (!text || count <= 0) return DrawGlInfo::kStatusDone;
+    if (!text || count <= 0 || paintWillNotDrawText(*paint)) return DrawGlInfo::kStatusDone;
 
     text = refText(text, bytesCount);
     positions = refBuffer<float>(positions, count * 2);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 721ab3d..bbf0551 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2518,8 +2518,9 @@
 
 status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
         float rx, float ry, const SkPaint* p) {
-    if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
-            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
+    if (currentSnapshot()->isIgnored()
+            || quickRejectSetupScissor(left, top, right, bottom, p)
+            || paintWillNotDraw(*p)) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2536,9 +2537,9 @@
 }
 
 status_t OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
-    if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(x - radius, y - radius,
-            x + radius, y + radius, p) ||
-            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
+    if (currentSnapshot()->isIgnored()
+            || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
+            || paintWillNotDraw(*p)) {
         return DrawGlInfo::kStatusDone;
     }
     if (p->getPathEffect() != 0) {
@@ -2558,8 +2559,9 @@
 
 status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
         const SkPaint* p) {
-    if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
-            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
+    if (currentSnapshot()->isIgnored()
+            || quickRejectSetupScissor(left, top, right, bottom, p)
+            || paintWillNotDraw(*p)) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2580,8 +2582,9 @@
 
 status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
         float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
-    if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
-            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
+    if (currentSnapshot()->isIgnored()
+            || quickRejectSetupScissor(left, top, right, bottom, p)
+            || paintWillNotDraw(*p)) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2614,8 +2617,9 @@
 
 status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
         const SkPaint* p) {
-    if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
-            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
+    if (currentSnapshot()->isIgnored()
+            || quickRejectSetupScissor(left, top, right, bottom, p)
+            || paintWillNotDraw(*p)) {
         return DrawGlInfo::kStatusDone;
     }
 
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index f5cd266..6d4bb4a 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -67,6 +67,18 @@
         return resultMode;
     }
 
+    // TODO: move to a method on android:Paint
+    static inline bool paintWillNotDraw(const SkPaint& paint) {
+        return paint.getAlpha() == 0
+                && getXfermode(paint.getXfermode()) != SkXfermode::kClear_Mode;
+    }
+
+    // TODO: move to a method on android:Paint
+    static inline bool paintWillNotDrawText(const SkPaint& paint) {
+        return paint.getAlpha() == 0
+                && paint.getLooper() == NULL
+                && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
+    }
 // ----------------------------------------------------------------------------
 // Frame state operations
 // ----------------------------------------------------------------------------
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index b33ba00..5a286ee 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -209,7 +209,9 @@
 
         // if not to popup dialog immediately, pending intent will open the dialog
         Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent();
-        PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);                
+        PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+        mNiNotification.color = mContext.getResources().getColor(
+                com.android.internal.R.color.system_notification_accent_color);
         mNiNotification.setLatestEventInfo(mContext, title, message, pi);
 
         notificationManager.notifyAsUser(null, notif.notificationId, mNiNotification,
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 6a76a71..e69c456 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2332,18 +2332,21 @@
     }
 
     /**
-     * Registers a {@link RemoteController} instance for it to receive media metadata updates
-     * and playback state information from applications using {@link RemoteControlClient}, and
-     * control their playback.
-     * <p>Registration requires the {@link OnClientUpdateListener} listener to be one of the
-     * enabled notification listeners (see
+     * Registers a {@link RemoteController} instance for it to receive media
+     * metadata updates and playback state information from applications using
+     * {@link RemoteControlClient}, and control their playback.
+     * <p>
+     * Registration requires the {@link OnClientUpdateListener} listener to be
+     * one of the enabled notification listeners (see
      * {@link android.service.notification.NotificationListenerService}).
+     *
      * @param rctlr the object to register.
-     * @return true if the {@link RemoteController} was successfully registered, false if an
-     *     error occurred, due to an internal system error, or insufficient permissions.
+     * @return true if the {@link RemoteController} was successfully registered,
+     *         false if an error occurred, due to an internal system error, or
+     *         insufficient permissions.
      * @deprecated Use
-     * {@link MediaSessionManager#addActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener, ComponentName)}
-     * and {@link MediaController} instead.
+     *             {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
+     *             and {@link MediaController} instead.
      */
     @Deprecated
     public boolean registerRemoteController(RemoteController rctlr) {
@@ -2355,12 +2358,14 @@
     }
 
     /**
-     * Unregisters a {@link RemoteController}, causing it to no longer receive media metadata and
-     * playback state information, and no longer be capable of controlling playback.
+     * Unregisters a {@link RemoteController}, causing it to no longer receive
+     * media metadata and playback state information, and no longer be capable
+     * of controlling playback.
+     *
      * @param rctlr the object to unregister.
      * @deprecated Use
-     * {@link MediaSessionManager#removeActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener)}
-     * instead.
+     *             {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
+     *             instead.
      */
     @Deprecated
     public void unregisterRemoteController(RemoteController rctlr) {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 52bcbbb..1861bd7 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -92,7 +92,7 @@
     /** Minimum value for sample rate */
     private static final int SAMPLE_RATE_HZ_MIN = 4000;
     /** Maximum value for sample rate */
-    private static final int SAMPLE_RATE_HZ_MAX = 48000;
+    private static final int SAMPLE_RATE_HZ_MAX = 96000;
 
     /** Maximum value for AudioTrack channel count */
     private static final int CHANNEL_COUNT_MAX = 8;
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 2fa0c93..7c3b4fc 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1049,8 +1049,17 @@
     private void setDataSource(String path, String[] keys, String[] values)
             throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
         final Uri uri = Uri.parse(path);
-        if ("file".equals(uri.getScheme())) {
+        final String scheme = uri.getScheme();
+        if ("file".equals(scheme)) {
             path = uri.getPath();
+        } else if (scheme != null) {
+            // handle non-file sources
+            nativeSetDataSource(
+                MediaHTTPService.createHttpServiceBinderIfNecessary(path),
+                path,
+                keys,
+                values);
+            return;
         }
 
         final File file = new File(path);
@@ -1060,20 +1069,10 @@
             setDataSource(fd);
             is.close();
         } else {
-            _setDataSource(path, keys, values);
+            throw new IOException("setDataSource failed.");
         }
     }
 
-    private void _setDataSource(
-        String path, String[] keys, String[] values)
-        throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
-        nativeSetDataSource(
-                MediaHTTPService.createHttpServiceBinderIfNecessary(path),
-                path,
-                keys,
-                values);
-    }
-
     private native void nativeSetDataSource(
         IBinder httpServiceBinder, String path, String[] keys, String[] values)
         throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index adc8391..f378cef 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -74,7 +74,7 @@
     private MetadataEditor mMetadataEditor;
 
     private MediaSessionManager mSessionManager;
-    private MediaSessionManager.SessionListener mSessionListener;
+    private MediaSessionManager.OnActiveSessionsChangedListener mSessionListener;
     private MediaController.Callback mSessionCb = new MediaControllerCallback();
 
     /**
@@ -140,7 +140,7 @@
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mSessionManager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
-        mSessionListener = new TopTransportSessionListener(context);
+        mSessionListener = new TopTransportSessionListener();
 
         if (ActivityManager.isLowRamDeviceStatic()) {
             mMaxBitmapDimension = MAX_BITMAP_DIMENSION;
@@ -710,11 +710,8 @@
      * Listens for changes to the active session stack and replaces the
      * currently tracked session if it has changed.
      */
-    private class TopTransportSessionListener extends MediaSessionManager.SessionListener {
-
-        public TopTransportSessionListener(Context context) {
-            super(context);
-        }
+    private class TopTransportSessionListener implements
+            MediaSessionManager.OnActiveSessionsChangedListener {
 
         @Override
         public void onActiveSessionsChanged(List<MediaController> controllers) {
@@ -792,7 +789,7 @@
     void startListeningToSessions() {
         final ComponentName listenerComponent = new ComponentName(mContext,
                 mOnClientUpdateListener.getClass());
-        mSessionManager.addActiveSessionsListener(mSessionListener, listenerComponent,
+        mSessionManager.addOnActiveSessionsChangedListener(mSessionListener, listenerComponent,
                 UserHandle.myUserId(), null);
         mSessionListener.onActiveSessionsChanged(mSessionManager
                 .getActiveSessions(listenerComponent));
@@ -806,7 +803,7 @@
      * @hide
      */
     void stopListeningToSessions() {
-        mSessionManager.removeActiveSessionsListener(mSessionListener);
+        mSessionManager.removeOnActiveSessionsChangedListener(mSessionListener);
         if (DEBUG) {
             Log.d(TAG, "Unregistered session listener for user "
                     + UserHandle.myUserId());
diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl
index 6ed803a..7e10c51 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -17,6 +17,9 @@
 package android.media.projection;
 
 import android.media.projection.IMediaProjection;
+import android.media.projection.IMediaProjectionCallback;
+import android.media.projection.IMediaProjectionWatcherCallback;
+import android.media.projection.MediaProjectionInfo;
 import android.os.IBinder;
 
 /** {@hide} */
@@ -25,4 +28,8 @@
     IMediaProjection createProjection(int uid, String packageName, int type,
             boolean permanentGrant);
     boolean isValidMediaProjection(IMediaProjection projection);
+    MediaProjectionInfo getActiveProjectionInfo();
+    void stopActiveProjection();
+    void addCallback(IMediaProjectionWatcherCallback callback);
+    void removeCallback(IMediaProjectionWatcherCallback callback);
 }
diff --git a/media/java/android/media/routing/IMediaRouterStateCallback.aidl b/media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl
similarity index 64%
rename from media/java/android/media/routing/IMediaRouterStateCallback.aidl
rename to media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl
index 0299904..2231ce1 100644
--- a/media/java/android/media/routing/IMediaRouterStateCallback.aidl
+++ b/media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl
@@ -1,4 +1,5 @@
-/* Copyright (C) 2014 The Android Open Source Project
+/*
+ * 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.
@@ -13,10 +14,12 @@
  * limitations under the License.
  */
 
-package android.media.routing;
+package android.media.projection;
 
-/** @hide */
-interface IMediaRouterStateCallback {
+import android.media.projection.MediaProjectionInfo;
 
+/** {@hide} */
+oneway interface IMediaProjectionWatcherCallback {
+    void onStart(in MediaProjectionInfo info);
+    void onStop(in MediaProjectionInfo info);
 }
-
diff --git a/media/java/android/media/routing/IMediaRouter.aidl b/media/java/android/media/projection/MediaProjectionInfo.aidl
similarity index 73%
rename from media/java/android/media/routing/IMediaRouter.aidl
rename to media/java/android/media/projection/MediaProjectionInfo.aidl
index 0abb258..3c8f9b6 100644
--- a/media/java/android/media/routing/IMediaRouter.aidl
+++ b/media/java/android/media/projection/MediaProjectionInfo.aidl
@@ -1,10 +1,11 @@
-/* Copyright (C) 2014 The Android Open Source Project
+/**
+ * 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
+ *     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,
@@ -13,10 +14,6 @@
  * limitations under the License.
  */
 
-package android.media.routing;
+package android.media.projection;
 
-/** @hide */
-interface IMediaRouter {
-
-}
-
+parcelable MediaProjectionInfo;
diff --git a/media/java/android/media/projection/MediaProjectionInfo.java b/media/java/android/media/projection/MediaProjectionInfo.java
new file mode 100644
index 0000000..7ebc31f
--- /dev/null
+++ b/media/java/android/media/projection/MediaProjectionInfo.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.projection;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+/** @hide */
+public final class MediaProjectionInfo implements Parcelable {
+    private final String mPackageName;
+    private final UserHandle mUserHandle;
+
+    public MediaProjectionInfo(String packageName, UserHandle handle) {
+        mPackageName = packageName;
+        mUserHandle = handle;
+    }
+
+    public MediaProjectionInfo(Parcel in) {
+        mPackageName = in.readString();
+        mUserHandle = UserHandle.readFromParcel(in);
+    }
+
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    public UserHandle getUserHandle() {
+        return mUserHandle;
+    }
+
+    @Override
+    public String toString() {
+        return "MediaProjectionInfo{mPackageName="
+            + mPackageName + ", mUserHandle="
+            + mUserHandle + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mPackageName);
+        UserHandle.writeToParcel(mUserHandle, out);
+    }
+
+    public static final Parcelable.Creator<MediaProjectionInfo> CREATOR =
+            new Parcelable.Creator<MediaProjectionInfo>() {
+        @Override
+        public MediaProjectionInfo createFromParcel(Parcel in) {
+            return new MediaProjectionInfo (in);
+        }
+
+        @Override
+        public MediaProjectionInfo[] newArray(int size) {
+            return new MediaProjectionInfo[size];
+        }
+    };
+}
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index aac8cf9..50d66c6 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -17,12 +17,20 @@
 package android.media.projection;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.media.projection.IMediaProjection;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.util.Map;
 
 /**
  * Manages the retrieval of certain types of {@link MediaProjection} tokens.
@@ -35,6 +43,7 @@
  * </p>
  */
 public final class MediaProjectionManager {
+    private static final String TAG = "MediaProjectionManager";
     /** @hide */
     public static final String EXTRA_APP_TOKEN = "android.media.projection.extra.EXTRA_APP_TOKEN";
     /** @hide */
@@ -49,10 +58,15 @@
     public static final int TYPE_PRESENTATION = 2;
 
     private Context mContext;
+    private Map<Callback, CallbackDelegate> mCallbacks;
+    private IMediaProjectionManager mService;
 
     /** @hide */
     public MediaProjectionManager(Context context) {
         mContext = context;
+        IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
+        mService = IMediaProjectionManager.Stub.asInterface(b);
+        mCallbacks = new ArrayMap<>();
     }
 
     /**
@@ -88,4 +102,105 @@
         }
         return new MediaProjection(mContext, IMediaProjection.Stub.asInterface(projection));
     }
+
+    /**
+     * Get the {@link MediaProjectionInfo} for the active {@link MediaProjection}.
+     * @hide
+     */
+    public MediaProjectionInfo getActiveProjectionInfo() {
+        try {
+            return mService.getActiveProjectionInfo();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to get the active projection info", e);
+        }
+        return null;
+    }
+
+    /**
+     * Stop the current projection if there is one.
+     * @hide
+     */
+    public void stopActiveProjection() {
+        try {
+            mService.stopActiveProjection();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to stop the currently active media projection", e);
+        }
+    }
+
+    /**
+     * Add a callback to monitor all of the {@link MediaProjection}s activity.
+     * Not for use by regular applications, must have the MANAGE_MEDIA_PROJECTION permission.
+     * @hide
+     */
+    public void addCallback(@NonNull Callback callback, @Nullable Handler handler) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback must not be null");
+        }
+        CallbackDelegate delegate = new CallbackDelegate(callback, handler);
+        mCallbacks.put(callback, delegate);
+        try {
+            mService.addCallback(delegate);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to add callbacks to MediaProjection service", e);
+        }
+    }
+
+    /**
+     * Remove a MediaProjection monitoring callback.
+     * @hide
+     */
+    public void removeCallback(@NonNull Callback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback must not be null");
+        }
+        CallbackDelegate delegate = mCallbacks.remove(callback);
+        try {
+            if (delegate != null) {
+                mService.removeCallback(delegate);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to add callbacks to MediaProjection service", e);
+        }
+    }
+
+    /** @hide */
+    public static abstract class Callback {
+        public abstract void onStart(MediaProjectionInfo info);
+        public abstract void onStop(MediaProjectionInfo info);
+    }
+
+    /** @hide */
+    private final static class CallbackDelegate extends IMediaProjectionWatcherCallback.Stub {
+        private Callback mCallback;
+        private Handler mHandler;
+
+        public CallbackDelegate(Callback callback, Handler handler) {
+            mCallback = callback;
+            if (handler == null) {
+                handler = new Handler();
+            }
+            mHandler = handler;
+        }
+
+        @Override
+        public void onStart(final MediaProjectionInfo info) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onStart(info);
+                }
+            });
+        }
+
+        @Override
+        public void onStop(final MediaProjectionInfo info) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onStop(info);
+                }
+            });
+        }
+    }
 }
diff --git a/media/java/android/media/routing/IMediaRouteClientCallback.aidl b/media/java/android/media/routing/IMediaRouteClientCallback.aidl
deleted file mode 100644
index d90ea3b..0000000
--- a/media/java/android/media/routing/IMediaRouteClientCallback.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.routing;
-
-import android.media.routing.MediaRouteSelector;
-import android.media.routing.ParcelableConnectionInfo;
-import android.media.routing.ParcelableDestinationInfo;
-import android.media.routing.ParcelableRouteInfo;
-import android.os.IBinder;
-import android.os.Bundle;
-
-/**
- * @hide
- */
-oneway interface IMediaRouteClientCallback {
-    void onDestinationFound(int seq, in ParcelableDestinationInfo destination,
-            in ParcelableRouteInfo[] routes);
-
-    void onDestinationLost(int seq, String id);
-
-    void onDiscoveryFailed(int seq, int error, in CharSequence message, in Bundle extras);
-
-    void onConnected(int seq, in ParcelableConnectionInfo connection);
-
-    void onDisconnected(int seq);
-
-    void onConnectionFailed(int seq, int error, in CharSequence message, in Bundle extras);
-}
diff --git a/media/java/android/media/routing/IMediaRouteService.aidl b/media/java/android/media/routing/IMediaRouteService.aidl
deleted file mode 100644
index 493ab6d..0000000
--- a/media/java/android/media/routing/IMediaRouteService.aidl
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.routing;
-
-import android.media.routing.IMediaRouteClientCallback;
-import android.media.routing.MediaRouteSelector;
-import android.os.Bundle;
-
-/**
- * Interface to an app's MediaRouteService.
- * @hide
- */
-oneway interface IMediaRouteService {
-    void registerClient(int clientUid, String clientPackageName,
-            in IMediaRouteClientCallback callback);
-
-    void unregisterClient(in IMediaRouteClientCallback callback);
-
-    void startDiscovery(in IMediaRouteClientCallback callback, int seq,
-            in List<MediaRouteSelector> selectors, int flags);
-
-    void stopDiscovery(in IMediaRouteClientCallback callback);
-
-    void connect(in IMediaRouteClientCallback callback, int seq,
-            String destinationId, String routeId, int flags, in Bundle extras);
-
-    void disconnect(in IMediaRouteClientCallback callback);
-
-    void pauseStream(in IMediaRouteClientCallback callback);
-
-    void resumeStream(in IMediaRouteClientCallback callback);
-}
-
diff --git a/media/java/android/media/routing/IMediaRouterDelegate.aidl b/media/java/android/media/routing/IMediaRouterDelegate.aidl
deleted file mode 100644
index 35f84c8..0000000
--- a/media/java/android/media/routing/IMediaRouterDelegate.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/* Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.routing;
-
-/** @hide */
-interface IMediaRouterDelegate {
-
-}
-
diff --git a/media/java/android/media/routing/IMediaRouterRoutingCallback.aidl b/media/java/android/media/routing/IMediaRouterRoutingCallback.aidl
deleted file mode 100644
index 173ae55..0000000
--- a/media/java/android/media/routing/IMediaRouterRoutingCallback.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/* Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.routing;
-
-/** @hide */
-interface IMediaRouterRoutingCallback {
-
-}
-
diff --git a/media/java/android/media/routing/MediaRouteSelector.aidl b/media/java/android/media/routing/MediaRouteSelector.aidl
deleted file mode 100644
index 37bfa4a..0000000
--- a/media/java/android/media/routing/MediaRouteSelector.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.media.routing;
-
-parcelable MediaRouteSelector;
diff --git a/media/java/android/media/routing/MediaRouteSelector.java b/media/java/android/media/routing/MediaRouteSelector.java
deleted file mode 100644
index 26a9b1c..0000000
--- a/media/java/android/media/routing/MediaRouteSelector.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.routing;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.media.routing.MediaRouter.RouteFeatures;
-import android.os.Bundle;
-import android.os.IInterface;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A media route selector consists of a set of constraints that are used to select
- * the routes to which an application would like to connect.  The constraints consist
- * of a set of required or optional features and protocols.  The constraints may also
- * require the use of a specific media route service package or additional characteristics
- * that are described by a bundle of extra parameters.
- * <p>
- * The application will typically create several different selectors that express
- * various combinations of characteristics that it would like to use together when
- * it connects to a destination media device.  For each destination that is discovered,
- * media route services will publish some number of routes and include information
- * about which selector each route matches.  The application will then choose among
- * these routes to determine which best satisfies its desired purpose and connect to it.
- * </p>
- */
-public final class MediaRouteSelector implements Parcelable {
-    private final int mRequiredFeatures;
-    private final int mOptionalFeatures;
-    private final List<String> mRequiredProtocols;
-    private final List<String> mOptionalProtocols;
-    private final String mServicePackageName;
-    private final Bundle mExtras;
-
-    MediaRouteSelector(int requiredFeatures, int optionalFeatures,
-            List<String> requiredProtocols, List<String> optionalProtocols,
-            String servicePackageName, Bundle extras) {
-        mRequiredFeatures = requiredFeatures;
-        mOptionalFeatures = optionalFeatures;
-        mRequiredProtocols = requiredProtocols;
-        mOptionalProtocols = optionalProtocols;
-        mServicePackageName = servicePackageName;
-        mExtras = extras;
-    }
-
-    /**
-     * Gets the set of required route features.
-     *
-     * @return A set of required route feature flags.
-     */
-    public @RouteFeatures int getRequiredFeatures() {
-        return mRequiredFeatures;
-    }
-
-    /**
-     * Gets the set of optional route features.
-     *
-     * @return A set of optional route feature flags.
-     */
-    public @RouteFeatures int getOptionalFeatures() {
-        return mOptionalFeatures;
-    }
-
-    /**
-     * Gets the list of route protocols that a route must support in order to be selected.
-     * <p>
-     * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-     * for more information.
-     * </p>
-     *
-     * @return The list of fully qualified route protocol names.
-     */
-    public @NonNull List<String> getRequiredProtocols() {
-        return mRequiredProtocols;
-    }
-
-    /**
-     * Gets the list of optional route protocols that a client may use if they are available.
-     * <p>
-     * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-     * for more information.
-     * </p>
-     *
-     * @return The list of optional fully qualified route protocol names.
-     */
-    public @NonNull List<String> getOptionalProtocols() {
-        return mOptionalProtocols;
-    }
-
-    /**
-     * Returns true if the selector includes a required or optional request for
-     * the specified protocol using its fully qualified class name.
-     * <p>
-     * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-     * for more information.
-     * </p>
-     *
-     * @param clazz The protocol class.
-     * @return True if the protocol was requested.
-     */
-    public boolean containsProtocol(@NonNull Class<?> clazz) {
-        return containsProtocol(clazz.getName());
-    }
-
-    /**
-     * Returns true if the selector includes a required or optional request for
-     * the specified protocol.
-     * <p>
-     * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-     * for more information.
-     * </p>
-     *
-     * @param name The name of the protocol.
-     * @return True if the protocol was requested.
-     */
-    public boolean containsProtocol(@NonNull String name) {
-        return mRequiredProtocols.contains(name)
-                || mOptionalProtocols.contains(name);
-    }
-
-    /**
-     * Gets the package name of a specific media route service that this route selector
-     * requires.
-     *
-     * @return The required media route service package name, or null if none.
-     */
-    public @Nullable String getServicePackageName() {
-        return mServicePackageName;
-    }
-
-    /**
-     * Gets optional extras that may be used to select or configure routes for a
-     * particular purpose.  Some extras may be used by media route services to apply
-     * additional constraints or parameters for the routes to be discovered.
-     *
-     * @return The optional extras, or null if none.
-     */
-    public @Nullable Bundle getExtras() {
-        return mExtras;
-    }
-
-    @Override
-    public String toString() {
-        return "MediaRouteSelector{ "
-                + ", requiredFeatures=0x" + Integer.toHexString(mRequiredFeatures)
-                + ", optionalFeatures=0x" + Integer.toHexString(mOptionalFeatures)
-                + ", requiredProtocols=" + mRequiredProtocols
-                + ", optionalProtocols=" + mOptionalProtocols
-                + ", servicePackageName=" + mServicePackageName
-                + ", extras=" + mExtras + " }";
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mRequiredFeatures);
-        dest.writeInt(mOptionalFeatures);
-        dest.writeStringList(mRequiredProtocols);
-        dest.writeStringList(mOptionalProtocols);
-        dest.writeString(mServicePackageName);
-        dest.writeBundle(mExtras);
-    }
-
-    public static final Parcelable.Creator<MediaRouteSelector> CREATOR =
-            new Parcelable.Creator<MediaRouteSelector>() {
-        @Override
-        public MediaRouteSelector createFromParcel(Parcel source) {
-            int requiredFeatures = source.readInt();
-            int optionalFeatures = source.readInt();
-            ArrayList<String> requiredProtocols = new ArrayList<String>();
-            ArrayList<String> optionalProtocols = new ArrayList<String>();
-            source.readStringList(requiredProtocols);
-            source.readStringList(optionalProtocols);
-            return new MediaRouteSelector(requiredFeatures, optionalFeatures,
-                    requiredProtocols, optionalProtocols,
-                    source.readString(), source.readBundle());
-        }
-
-        @Override
-        public MediaRouteSelector[] newArray(int size) {
-            return new MediaRouteSelector[size];
-        }
-    };
-
-    /**
-     * Builder for {@link MediaRouteSelector} objects.
-     */
-    public static final class Builder {
-        private int mRequiredFeatures;
-        private int mOptionalFeatures;
-        private final ArrayList<String> mRequiredProtocols = new ArrayList<String>();
-        private final ArrayList<String> mOptionalProtocols = new ArrayList<String>();
-        private String mServicePackageName;
-        private Bundle mExtras;
-
-        /**
-         * Creates an initially empty selector builder.
-         */
-        public Builder() {
-        }
-
-        /**
-         * Sets the set of required route features.
-         *
-         * @param features A set of required route feature flags.
-         */
-        public @NonNull Builder setRequiredFeatures(@RouteFeatures int features) {
-            mRequiredFeatures = features;
-            return this;
-        }
-
-        /**
-         * Sets the set of optional route features.
-         *
-         * @param features A set of optional route feature flags.
-         */
-        public @NonNull Builder setOptionalFeatures(@RouteFeatures int features) {
-            mOptionalFeatures = features;
-            return this;
-        }
-
-        /**
-         * Adds a route protocol that a route must support in order to be selected
-         * using its fully qualified class name.
-         * <p>
-         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-         * for more information.
-         * </p>
-         *
-         * @param clazz The protocol class.
-         * @return this
-         */
-        public @NonNull Builder addRequiredProtocol(@NonNull Class<?> clazz) {
-            if (clazz == null) {
-                throw new IllegalArgumentException("clazz must not be null");
-            }
-            return addRequiredProtocol(clazz.getName());
-        }
-
-        /**
-         * Adds a route protocol that a route must support in order to be selected.
-         * <p>
-         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-         * for more information.
-         * </p>
-         *
-         * @param name The fully qualified name of the required protocol.
-         * @return this
-         */
-        public @NonNull Builder addRequiredProtocol(@NonNull String name) {
-            if (TextUtils.isEmpty(name)) {
-                throw new IllegalArgumentException("name must not be null or empty");
-            }
-            mRequiredProtocols.add(name);
-            return this;
-        }
-
-        /**
-         * Adds an optional route protocol that a client may use if available
-         * using its fully qualified class name.
-         * <p>
-         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-         * for more information.
-         * </p>
-         *
-         * @param clazz The protocol class.
-         * @return this
-         */
-        public @NonNull Builder addOptionalProtocol(@NonNull Class<?> clazz) {
-            if (clazz == null) {
-                throw new IllegalArgumentException("clazz must not be null");
-            }
-            return addOptionalProtocol(clazz.getName());
-        }
-
-        /**
-         * Adds an optional route protocol that a client may use if available.
-         * <p>
-         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-         * for more information.
-         * </p>
-         *
-         * @param name The fully qualified name of the optional protocol.
-         * @return this
-         */
-        public @NonNull Builder addOptionalProtocol(@NonNull String name) {
-            if (TextUtils.isEmpty(name)) {
-                throw new IllegalArgumentException("name must not be null or empty");
-            }
-            mOptionalProtocols.add(name);
-            return this;
-        }
-
-        /**
-         * Sets the package name of the media route service to which this selector
-         * appertains.
-         * <p>
-         * If a package name is specified here then this selector will only be
-         * passed to media route services from that package.  This has the effect
-         * of restricting the set of matching routes to just those that are offered
-         * by that package.
-         * </p>
-         *
-         * @param packageName The required service package name, or null if none.
-         * @return this
-         */
-        public @NonNull Builder setServicePackageName(@Nullable String packageName) {
-            mServicePackageName = packageName;
-            return this;
-        }
-
-        /**
-         * Sets optional extras that may be used to select or configure routes for a
-         * particular purpose.  Some extras may be used by route services to specify
-         * additional constraints or parameters for the routes to be discovered.
-         *
-         * @param extras The optional extras, or null if none.
-         * @return this
-         */
-        public @NonNull Builder setExtras(@Nullable Bundle extras) {
-            mExtras = extras;
-            return this;
-        }
-
-        /**
-         * Builds the {@link MediaRouteSelector} object.
-         *
-         * @return The new media route selector instance.
-         */
-        public @NonNull MediaRouteSelector build() {
-            return new MediaRouteSelector(mRequiredFeatures, mOptionalFeatures,
-                    mRequiredProtocols, mOptionalProtocols, mServicePackageName, mExtras);
-        }
-    }
-}
diff --git a/media/java/android/media/routing/MediaRouteService.java b/media/java/android/media/routing/MediaRouteService.java
deleted file mode 100644
index 4d5a8a9..0000000
--- a/media/java/android/media/routing/MediaRouteService.java
+++ /dev/null
@@ -1,1023 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.routing;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SdkConstant;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.media.routing.MediaRouter.ConnectionError;
-import android.media.routing.MediaRouter.ConnectionInfo;
-import android.media.routing.MediaRouter.ConnectionRequest;
-import android.media.routing.MediaRouter.DestinationInfo;
-import android.media.routing.MediaRouter.DiscoveryError;
-import android.media.routing.MediaRouter.DiscoveryRequest;
-import android.media.routing.MediaRouter.RouteInfo;
-import android.media.routing.MediaRouter.ServiceMetadata;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Media route services implement strategies for discovering
- * and establishing connections to media devices and their routes.  These services
- * are also known as media route providers.
- * <p>
- * Each media route service subclass is responsible for enabling applications
- * and the system to interact with media devices of some kind.
- * For example, one particular media route service implementation might
- * offer support for discovering nearby wireless display devices and streaming
- * video contents to them; another media route service implementation might
- * offer support for discovering nearby speakers and streaming media appliances
- * and sending commands to play content on request.
- * </p><p>
- * Subclasses must override the {@link #onCreateClientSession} method to return
- * a {@link ClientSession} object that implements the {@link ClientSession#onStartDiscovery},
- * {@link ClientSession#onStopDiscovery}, and {@link ClientSession#onConnect} methods
- * to allow clients to discover and connect to media devices.
- * </p><p>
- * This object is not thread-safe.  All callbacks are invoked on the main looper.
- * </p>
- *
- * <h3>Clients</h3>
- * <p>
- * The clients of this API are media applications that would like to discover
- * and connect to media devices.  The client may also be the system, such as
- * when the user initiates display mirroring via the Cast Screen function.
- * </p><p>
- * There may be multiple client sessions active at the same time.  Each client
- * session can request discovery and connect to routes independently of any
- * other client.  It is the responsibility of the media route service to maintain
- * separate state for each client session and to ensure that clients cannot interfere
- * with one another in harmful ways.
- * </p><p>
- * Notwithstanding the requirement to support any number of concurrent client
- * sessions, the media route service may impose constraints on how many clients
- * can connect to the same media device in a particular mode at the same time.
- * In some cases, media devices may support connections from an arbitrary number
- * of clients simultaneously but often it may be necessary to ensure that only
- * one client is in control.  When this happens, the media route service should
- * report a connection error unless the connection request specifies that the
- * client should take control of the media device (and forcibly disconnect other
- * clients that may be using it).
- * </p>
- *
- * <h3>Destinations</h3>
- * <p>
- * The media devices to which an application may send media content are referred
- * to in the API as destinations.  Each destination therefore represents a single
- * independent device such as a speaker or TV set.  Destinations are given meaningful
- * names and descriptions to help the user associate them with devices in their
- * environment.
- * </p><p>
- * Destinations may be local or remote and may be accessed through various means,
- * often wirelessly.  The user may install media route services to enable
- * media applications to connect to a variety of destinations with different
- * capabilities.
- * </p>
- *
- * <h3>Routes</h3>
- * <p>
- * Routes represent possible usages or means of reaching and interacting with
- * a destination.  Since destinations may support many different features, they may
- * each offer multiple routes for applications to choose from based on their needs.
- * For example, one route might express the ability to stream locally rendered audio
- * and video to the device; another route might express the ability to send a URL for
- * the destination to download from the network and play all by itself.
- * </p><p>
- * Routes are discovered according to the set of capabilities that
- * an application or the system is seeking to use at a particular time.  For example,
- * if an application wants to stream music to a destination then it will ask the
- * {@link MediaRouter} to find routes to destinations can stream music and ignore
- * all other destinations that cannot.
- * </p><p>
- * In general, the application will inspect the set of routes that have been
- * offered then connect to the most appropriate route for its desired purpose.
- * </p>
- *
- * <h3>Discovery</h3>
- * <p>
- * Discovery is the process of finding destinations based on a description of the
- * kinds of routes that an application or the system would like to use.
- * </p><p>
- * Discovery begins when {@link ClientSession#onStartDiscovery} is called and ends when
- * {@link ClientSession#onStopDiscovery} is called.  There may be multiple simultaneous
- * discovery requests in progress at the same time from different clients.  It is up to
- * the media route service to perform these requests in parallel or multiplex them
- * as required.
- * </p><p>
- * Media route services are <em>strongly encouraged</em> to use the information
- * in the discovery request to optimize discovery and avoid redundant work.
- * In the case where no media device supported by the media route service
- * could possibly offer the requested capabilities, the
- * {@link ClientSession#onStartDiscovery} method should return <code>false</code> to
- * let the system know that it can unbind from the media route service and
- * release its resources.
- * </p>
- *
- * <h3>Settings</h3>
- * <p>
- * Many kinds of devices can be discovered on demand simply by scanning the local network
- * or using wireless protocols such as Bluetooth to find them.  However, in some cases
- * it may be necessary for the user to manually configure destinations before they
- * can be used (or to adjust settings later).  Actual user configuration of destinations
- * is beyond the scope of this API but media route services may specify an activity
- * in their manifest that the user can launch to perform these tasks.
- * </p><p>
- * Note that media route services that are installed from the store must be enabled
- * by the user before they become available for applications to use.
- * The {@link android.provider.Settings#ACTION_CAST_SETTINGS Settings.ACTION_CAST_SETTINGS}
- * settings activity provides the ability for the user to configure media route services.
- * </p>
- *
- * <h3>Manifest Declaration</h3>
- * <p>
- * Media route services must be declared in the manifest along with meta-data
- * about the kinds of routes that they are capable of discovering.  The system
- * uses this information to optimize the set of services to which it binds in
- * order to satisfy a particular discovery request.
- * </p><p>
- * To extend this class, you must declare the service in your manifest file with
- * the {@link android.Manifest.permission#BIND_MEDIA_ROUTE_SERVICE} permission
- * and include an intent filter with the {@link #SERVICE_INTERFACE} action.  You must
- * also add meta-data to describe the kinds of routes that your service is capable
- * of discovering.
- * </p><p>
- * For example:
- * </p><pre>
- * &lt;service android:name=".MediaRouteProvider"
- *          android:label="&#64;string/service_name"
- *          android:permission="android.permission.BIND_MEDIA_ROUTE_SERVICE">
- *     &lt;intent-filter>
- *         &lt;action android:name="android.media.routing.MediaRouteService" />
- *     &lt;/intent-filter>
- *
- *     TODO: INSERT METADATA DECLARATIONS HERE
- *
- * &lt;/service>
- * </pre>
- */
-public abstract class MediaRouteService extends Service {
-    private static final String TAG = "MediaRouteService";
-
-    private static final boolean DEBUG = true;
-
-    private final Handler mHandler;
-    private final BinderService mService;
-    private final ArrayMap<IBinder, ClientRecord> mClientRecords =
-            new ArrayMap<IBinder, ClientRecord>();
-
-    private ServiceMetadata mMetadata;
-
-    /**
-     * The {@link Intent} that must be declared as handled by the service.
-     */
-    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
-    public static final String SERVICE_INTERFACE =
-            "android.media.routing.MediaRouteService";
-
-    /**
-     * Creates a media route service.
-     */
-    public MediaRouteService() {
-        mHandler = new Handler(true);
-        mService = new BinderService();
-    }
-
-    @Override
-    public @Nullable IBinder onBind(Intent intent) {
-        if (SERVICE_INTERFACE.equals(intent.getAction())) {
-            return mService;
-        }
-        return null;
-    }
-
-    /**
-     * Creates a new client session on behalf of a client.
-     * <p>
-     * The implementation should return a {@link ClientSession} for the client
-     * to use.  The media route service must take care to manage the state of
-     * each client session independently from any others that might also be
-     * in use at the same time.
-     * </p>
-     *
-     * @param client Information about the client.
-     * @return The client session object, or null if the client is not allowed
-     * to interact with this media route service.
-     */
-    public abstract @Nullable ClientSession onCreateClientSession(@NonNull ClientInfo client);
-
-    /**
-     * Gets metadata about this service.
-     * <p>
-     * Use this method to obtain a {@link ServiceMetadata} object to provide when creating
-     * a {@link android.media.routing.MediaRouter.DestinationInfo.Builder}.
-     * </p>
-     *
-     * @return Metadata about this service.
-     */
-    public @NonNull ServiceMetadata getServiceMetadata() {
-        if (mMetadata == null) {
-            try {
-                mMetadata = new ServiceMetadata(this);
-            } catch (NameNotFoundException ex) {
-                Log.wtf(TAG, "Could not retrieve own service metadata!");
-            }
-        }
-        return mMetadata;
-    }
-
-    /**
-     * Enables a single client to access the functionality of the media route service.
-     */
-    public static abstract class ClientSession {
-        /**
-         * Starts discovery.
-         * <p>
-         * If the media route service is capable of discovering routes that satisfy
-         * the request then this method should start discovery and return true.
-         * Otherwise, this method should return false.  If false is returned,
-         * then the framework will not call {@link #onStopDiscovery} since discovery
-         * was never actually started.
-         * </p><p>
-         * There may already be other discovery requests in progress at the same time
-         * for other clients; the media route service must keep track of them all.
-         * </p>
-         *
-         * @param req The discovery request to start.
-         * @param callback A callback to receive discovery events related to this
-         * particular request.  The events that the service sends to this callback
-         * will be sent to the client that initiated the discovery request.
-         * @return True if discovery has started.  False if the media route service
-         * is unable to discover routes that satisfy the request.
-         */
-        public abstract boolean onStartDiscovery(@NonNull DiscoveryRequest req,
-                @NonNull DiscoveryCallback callback);
-
-        /**
-         * Stops discovery.
-         * <p>
-         * If {@link #onStartDiscovery} returned true, then this method will eventually
-         * be called when the framework no longer requires this discovery request
-         * to be performed.
-         * </p><p>
-         * There may still be other discovery requests in progress for other clients;
-         * they must keep working until they have each been stopped by their client.
-         * </p>
-         */
-        public abstract void onStopDiscovery();
-
-        /**
-         * Starts connecting to a route.
-         *
-         * @param req The connection request.
-         * @param callback A callback to receive events connection events related
-         * to this particular request.  The events that the service sends to this callback
-         * will be sent to the client that initiated the discovery request.
-         * @return True if the connection is in progress, or false if the client
-         * unable to connect to the requested route.
-         */
-        public abstract boolean onConnect(@NonNull ConnectionRequest req,
-                @NonNull ConnectionCallback callback);
-
-        /**
-         * Called when the client requests to disconnect from the route
-         * or abort a connection attempt in progress.
-         */
-        public abstract void onDisconnect();
-
-        /**
-         * Called when the client requests to pause streaming of content to
-         * live audio/video routes such as when it goes into the background.
-         * <p>
-         * The default implementation does nothing.
-         * </p>
-         */
-        public void onPauseStream() { }
-
-        /**
-         * Called when the application requests to resume streaming of content to
-         * live audio/video routes such as when it returns to the foreground.
-         * <p>
-         * The default implementation does nothing.
-         * </p>
-         */
-        public void onResumeStream() { }
-
-        /**
-         * Called when the client is releasing the session.
-         * <p>
-         * The framework automatically takes care of stopping discovery and
-         * terminating the connection politely before calling this method to release
-         * the session.
-         * </p><p>
-         * The default implementation does nothing.
-         * </p>
-         */
-        public void onRelease() { }
-    }
-
-    /**
-     * Provides events in response to a discovery request.
-     */
-    public final class DiscoveryCallback {
-        private final ClientRecord mRecord;
-
-        DiscoveryCallback(ClientRecord record) {
-            mRecord = record;
-        }
-
-        /**
-         * Called by the service when a destination is found that
-         * offers one or more routes that satisfy the discovery request.
-         * <p>
-         * This method should be called whenever the list of available routes
-         * at a destination changes or whenever the properties of the destination
-         * itself change.
-         * </p>
-         *
-         * @param destination The destination that was found.
-         * @param routes The list of that destination's routes that satisfy the
-         * discovery request.
-         */
-        public void onDestinationFound(final @NonNull DestinationInfo destination,
-                final @NonNull List<RouteInfo> routes) {
-            if (destination == null) {
-                throw new IllegalArgumentException("destination must not be null");
-            }
-            if (routes == null) {
-                throw new IllegalArgumentException("routes must not be null");
-            }
-            for (int i = 0; i < routes.size(); i++) {
-                if (routes.get(i).getDestination() != destination) {
-                    throw new IllegalArgumentException("routes must refer to the "
-                            + "destination");
-                }
-            }
-
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mRecord.dispatchDestinationFound(DiscoveryCallback.this,
-                            destination, routes);
-                }
-            });
-        }
-
-        /**
-         * Called by the service when a destination is no longer
-         * reachable or is no longer offering any routes that satisfy
-         * the discovery request.
-         *
-         * @param destination The destination that went away.
-         */
-        public void onDestinationLost(final @NonNull DestinationInfo destination) {
-            if (destination == null) {
-                throw new IllegalArgumentException("destination must not be null");
-            }
-
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mRecord.dispatchDestinationLost(DiscoveryCallback.this, destination);
-                }
-            });
-        }
-
-        /**
-         * Called by the service when a discovery has failed in a non-recoverable manner.
-         *
-         * @param error The error code: one of
-         * {@link MediaRouter#DISCOVERY_ERROR_UNKNOWN},
-         * {@link MediaRouter#DISCOVERY_ERROR_ABORTED},
-         * or {@link MediaRouter#DISCOVERY_ERROR_NO_CONNECTIVITY}.
-         * @param message The localized error message, or null if none.  This message
-         * may be shown to the user.
-         * @param extras Additional information about the error which a client
-         * may use, or null if none.
-         */
-        public void onDiscoveryFailed(final @DiscoveryError int error,
-                final @Nullable CharSequence message, final @Nullable Bundle extras) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mRecord.dispatchDiscoveryFailed(DiscoveryCallback.this,
-                            error, message, extras);
-                }
-            });
-        }
-    }
-
-    /**
-     * Provides events in response to a connection request.
-     */
-    public final class ConnectionCallback {
-        private final ClientRecord mRecord;
-
-        ConnectionCallback(ClientRecord record) {
-            mRecord = record;
-        }
-
-        /**
-         * Called by the service when the connection succeeds.
-         *
-         * @param connection Immutable information about the connection.
-         */
-        public void onConnected(final @NonNull ConnectionInfo connection) {
-            if (connection == null) {
-                throw new IllegalArgumentException("connection must not be null");
-            }
-
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mRecord.dispatchConnected(ConnectionCallback.this, connection);
-                }
-            });
-        }
-
-        /**
-         * Called by the service when the connection is terminated normally.
-         * <p>
-         * Abnormal termination is reported via {@link #onConnectionFailed}.
-         * </p>
-         */
-        public void onDisconnected() {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mRecord.dispatchDisconnected(ConnectionCallback.this);
-                }
-            });
-        }
-
-        /**
-         * Called by the service when a connection attempt or connection in
-         * progress has failed in a non-recoverable manner.
-         *
-         * @param error The error code: one of
-         * {@link MediaRouter#CONNECTION_ERROR_ABORTED},
-         * {@link MediaRouter#CONNECTION_ERROR_UNAUTHORIZED},
-         * {@link MediaRouter#CONNECTION_ERROR_UNREACHABLE},
-         * {@link MediaRouter#CONNECTION_ERROR_BUSY},
-         * {@link MediaRouter#CONNECTION_ERROR_TIMEOUT},
-         * {@link MediaRouter#CONNECTION_ERROR_BROKEN},
-         * or {@link MediaRouter#CONNECTION_ERROR_BARGED}.
-         * @param message The localized error message, or null if none.  This message
-         * may be shown to the user.
-         * @param extras Additional information about the error which a client
-         * may use, or null if none.
-         */
-        public void onConnectionFailed(final @ConnectionError int error,
-                final @Nullable CharSequence message, final @Nullable Bundle extras) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mRecord.dispatchConnectionFailed(ConnectionCallback.this,
-                            error, message, extras);
-                }
-            });
-        }
-    }
-
-    /**
-     * Identifies a client of the media route service.
-     */
-    public static final class ClientInfo {
-        private final int mUid;
-        private final String mPackageName;
-
-        ClientInfo(int uid, String packageName) {
-            mUid = uid;
-            mPackageName = packageName;
-        }
-
-        /**
-         * Gets the UID of the client application.
-         */
-        public int getUid() {
-            return mUid;
-        }
-
-        /**
-         * Gets the package name of the client application.
-         */
-        public @NonNull String getPackageName() {
-            return mPackageName;
-        }
-
-        @Override
-        public @NonNull String toString() {
-            return "ClientInfo{ uid=" + mUid + ", package=" + mPackageName + " }";
-        }
-    }
-
-    private final class BinderService extends IMediaRouteService.Stub {
-        @Override
-        public void registerClient(final int clientUid, final String clientPackageName,
-                final IMediaRouteClientCallback callback) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    ClientInfo client = new ClientInfo(clientUid, clientPackageName);
-                    if (DEBUG) {
-                        Log.d(TAG, "registerClient: client=" + client);
-                    }
-
-                    ClientSession session = onCreateClientSession(client);
-                    if (session == null) {
-                        // request refused by service
-                        Log.w(TAG, "Media route service refused to create session for client: "
-                                + "client=" + client);
-                        return;
-                    }
-
-                    ClientRecord record = new ClientRecord(callback, client, session);
-                    try {
-                        callback.asBinder().linkToDeath(record, 0);
-                    } catch (RemoteException ex) {
-                        // client died prematurely
-                        Log.w(TAG, "Client died prematurely while creating session: "
-                                + "client=" + client);
-                        record.release();
-                        return;
-                    }
-
-                    mClientRecords.put(callback.asBinder(), record);
-                }
-            });
-        }
-
-        @Override
-        public void unregisterClient(IMediaRouteClientCallback callback) {
-            unregisterClient(callback, false);
-        }
-
-        void unregisterClient(final IMediaRouteClientCallback callback,
-                final boolean died) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    ClientRecord record = mClientRecords.remove(callback.asBinder());
-                    if (record == null) {
-                        return; // spurious
-                    }
-
-                    if (DEBUG) {
-                        Log.d(TAG, "unregisterClient: client=" + record.getClientInfo()
-                                + ", died=" + died);
-                    }
-
-                    record.release();
-                    callback.asBinder().unlinkToDeath(record, 0);
-                }
-            });
-        }
-
-        @Override
-        public void startDiscovery(final IMediaRouteClientCallback callback,
-                final int seq, final List<MediaRouteSelector> selectors,
-                final int flags) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    ClientRecord record = mClientRecords.get(callback.asBinder());
-                    if (record == null) {
-                        return; // spurious
-                    }
-
-                    if (DEBUG) {
-                        Log.d(TAG, "startDiscovery: client=" + record.getClientInfo()
-                                + ", seq=" + seq + ", selectors=" + selectors
-                                + ", flags=0x" + Integer.toHexString(flags));
-                    }
-                    record.startDiscovery(seq, selectors, flags);
-                }
-            });
-        }
-
-        @Override
-        public void stopDiscovery(final IMediaRouteClientCallback callback) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    ClientRecord record = mClientRecords.get(callback.asBinder());
-                    if (record == null) {
-                        return; // spurious
-                    }
-
-                    if (DEBUG) {
-                        Log.d(TAG, "stopDiscovery: client=" + record.getClientInfo());
-                    }
-                    record.stopDiscovery();
-                }
-            });
-        }
-
-        @Override
-        public void connect(final IMediaRouteClientCallback callback,
-                final int seq, final String destinationId, final String routeId,
-                final int flags, final Bundle extras) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    ClientRecord record = mClientRecords.get(callback.asBinder());
-                    if (record == null) {
-                        return; // spurious
-                    }
-
-                    if (DEBUG) {
-                        Log.d(TAG, "connect: client=" + record.getClientInfo()
-                                + ", seq=" + seq + ", destinationId=" + destinationId
-                                + ", routeId=" + routeId
-                                + ", flags=0x" + Integer.toHexString(flags)
-                                + ", extras=" + extras);
-                    }
-                    record.connect(seq, destinationId, routeId, flags, extras);
-                }
-            });
-        }
-
-        @Override
-        public void disconnect(final IMediaRouteClientCallback callback) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    ClientRecord record = mClientRecords.get(callback.asBinder());
-                    if (record == null) {
-                        return; // spurious
-                    }
-
-                    if (DEBUG) {
-                        Log.d(TAG, "disconnect: client=" + record.getClientInfo());
-                    }
-                    record.disconnect();
-                }
-            });
-        }
-
-        @Override
-        public void pauseStream(final IMediaRouteClientCallback callback) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    ClientRecord record = mClientRecords.get(callback.asBinder());
-                    if (record == null) {
-                        return; // spurious
-                    }
-
-                    if (DEBUG) {
-                        Log.d(TAG, "pauseStream: client=" + record.getClientInfo());
-                    }
-                    record.pauseStream();
-                }
-            });
-        }
-
-        @Override
-        public void resumeStream(final IMediaRouteClientCallback callback) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    ClientRecord record = mClientRecords.get(callback.asBinder());
-                    if (record == null) {
-                        return; // spurious
-                    }
-
-                    if (DEBUG) {
-                        Log.d(TAG, "resumeStream: client=" + record.getClientInfo());
-                    }
-                    record.resumeStream();
-                }
-            });
-        }
-    }
-
-    // Must be accessed on handler
-    private final class ClientRecord implements IBinder.DeathRecipient {
-        private final IMediaRouteClientCallback mClientCallback;
-        private final ClientInfo mClient;
-        private final ClientSession mSession;
-
-        private int mDiscoverySeq;
-        private DiscoveryRequest mDiscoveryRequest;
-        private DiscoveryCallback mDiscoveryCallback;
-        private final ArrayMap<String, DestinationRecord> mDestinations =
-                new ArrayMap<String, DestinationRecord>();
-
-        private int mConnectionSeq;
-        private ConnectionRequest mConnectionRequest;
-        private ConnectionCallback mConnectionCallback;
-        private ConnectionInfo mConnection;
-        private boolean mConnectionPaused;
-
-        public ClientRecord(IMediaRouteClientCallback callback,
-                ClientInfo client, ClientSession session) {
-            mClientCallback = callback;
-            mClient = client;
-            mSession = session;
-        }
-
-        // Invoked on binder thread unlike all other methods in this class.
-        @Override
-        public void binderDied() {
-            mService.unregisterClient(mClientCallback, true);
-        }
-
-        public ClientInfo getClientInfo() {
-            return mClient;
-        }
-
-        public void release() {
-            stopDiscovery();
-            disconnect();
-        }
-
-        public void startDiscovery(int seq, List<MediaRouteSelector> selectors,
-                int flags) {
-            stopDiscovery();
-
-            mDiscoverySeq = seq;
-            mDiscoveryRequest = new DiscoveryRequest(selectors);
-            mDiscoveryRequest.setFlags(flags);
-            mDiscoveryCallback = new DiscoveryCallback(this);
-            boolean started = mSession.onStartDiscovery(mDiscoveryRequest, mDiscoveryCallback);
-            if (!started) {
-                dispatchDiscoveryFailed(mDiscoveryCallback,
-                        MediaRouter.DISCOVERY_ERROR_ABORTED, null, null);
-                clearDiscovery();
-            }
-        }
-
-        public void stopDiscovery() {
-            if (mDiscoveryRequest != null) {
-                mSession.onStopDiscovery();
-                clearDiscovery();
-            }
-        }
-
-        private void clearDiscovery() {
-            mDestinations.clear();
-            mDiscoveryRequest = null;
-            mDiscoveryCallback = null;
-        }
-
-        public void connect(int seq, String destinationId, String routeId,
-                int flags, Bundle extras) {
-            disconnect();
-
-            mConnectionSeq = seq;
-            mConnectionCallback = new ConnectionCallback(this);
-
-            DestinationRecord destinationRecord = mDestinations.get(destinationId);
-            if (destinationRecord == null) {
-                Log.w(TAG, "Aborting connection to route since no matching destination "
-                        + "was found in the list of known destinations: "
-                        + "destinationId=" + destinationId);
-                dispatchConnectionFailed(mConnectionCallback,
-                        MediaRouter.CONNECTION_ERROR_ABORTED, null, null);
-                clearConnection();
-                return;
-            }
-
-            RouteInfo route = destinationRecord.getRoute(routeId);
-            if (route == null) {
-                Log.w(TAG, "Aborting connection to route since no matching route "
-                        + "was found in the list of known routes: "
-                        + "destination=" + destinationRecord.destination
-                        + ", routeId=" + routeId);
-                dispatchConnectionFailed(mConnectionCallback,
-                        MediaRouter.CONNECTION_ERROR_ABORTED, null, null);
-                clearConnection();
-                return;
-            }
-
-            mConnectionRequest = new ConnectionRequest(route);
-            mConnectionRequest.setFlags(flags);
-            mConnectionRequest.setExtras(extras);
-            boolean started = mSession.onConnect(mConnectionRequest, mConnectionCallback);
-            if (!started) {
-                dispatchConnectionFailed(mConnectionCallback,
-                        MediaRouter.CONNECTION_ERROR_ABORTED, null, null);
-                clearConnection();
-            }
-        }
-
-        public void disconnect() {
-            if (mConnectionRequest != null) {
-                mSession.onDisconnect();
-                clearConnection();
-            }
-        }
-
-        private void clearConnection() {
-            mConnectionRequest = null;
-            mConnectionCallback = null;
-            if (mConnection != null) {
-                mConnection.close();
-                mConnection = null;
-            }
-            mConnectionPaused = false;
-        }
-
-        public void pauseStream() {
-            if (mConnectionRequest != null && !mConnectionPaused) {
-                mConnectionPaused = true;
-                mSession.onPauseStream();
-            }
-        }
-
-        public void resumeStream() {
-            if (mConnectionRequest != null && mConnectionPaused) {
-                mConnectionPaused = false;
-                mSession.onResumeStream();
-            }
-        }
-
-        public void dispatchDestinationFound(DiscoveryCallback callback,
-                DestinationInfo destination, List<RouteInfo> routes) {
-            if (callback == mDiscoveryCallback) {
-                if (DEBUG) {
-                    Log.d(TAG, "destinationFound: destination=" + destination
-                            + ", routes=" + routes);
-                }
-                mDestinations.put(destination.getId(),
-                        new DestinationRecord(destination, routes));
-
-                ParcelableDestinationInfo pdi = new ParcelableDestinationInfo();
-                pdi.id = destination.getId();
-                pdi.name = destination.getName();
-                pdi.description = destination.getDescription();
-                pdi.iconResourceId = destination.getIconResourceId();
-                pdi.extras = destination.getExtras();
-                ArrayList<ParcelableRouteInfo> pris = new ArrayList<ParcelableRouteInfo>();
-                for (RouteInfo route : routes) {
-                    int selectorIndex = mDiscoveryRequest.getSelectors().indexOf(
-                            route.getSelector());
-                    if (selectorIndex < 0) {
-                        Log.w(TAG, "Ignoring route because the selector does not match "
-                                + "any of those that were originally supplied by the "
-                                + "client's discovery request: destination=" + destination
-                                + ", route=" + route);
-                        continue;
-                    }
-
-                    ParcelableRouteInfo pri = new ParcelableRouteInfo();
-                    pri.id = route.getId();
-                    pri.selectorIndex = selectorIndex;
-                    pri.features = route.getFeatures();
-                    pri.protocols = route.getProtocols().toArray(
-                            new String[route.getProtocols().size()]);
-                    pri.extras = route.getExtras();
-                    pris.add(pri);
-                }
-                try {
-                    mClientCallback.onDestinationFound(mDiscoverySeq, pdi,
-                            pris.toArray(new ParcelableRouteInfo[pris.size()]));
-                } catch (RemoteException ex) {
-                    // binder death handled elsewhere
-                }
-            }
-        }
-
-        public void dispatchDestinationLost(DiscoveryCallback callback,
-                DestinationInfo destination) {
-            if (callback == mDiscoveryCallback) {
-                if (DEBUG) {
-                    Log.d(TAG, "destinationLost: destination=" + destination);
-                }
-
-                if (mDestinations.get(destination.getId()).destination == destination) {
-                    mDestinations.remove(destination.getId());
-                    try {
-                        mClientCallback.onDestinationLost(mDiscoverySeq, destination.getId());
-                    } catch (RemoteException ex) {
-                        // binder death handled elsewhere
-                    }
-                }
-            }
-        }
-
-        public void dispatchDiscoveryFailed(DiscoveryCallback callback,
-                int error, CharSequence message, Bundle extras) {
-            if (callback == mDiscoveryCallback) {
-                if (DEBUG) {
-                    Log.d(TAG, "discoveryFailed: error=" + error + ", message=" + message
-                            + ", extras=" + extras);
-                }
-
-                try {
-                    mClientCallback.onDiscoveryFailed(mDiscoverySeq, error, message, extras);
-                } catch (RemoteException ex) {
-                    // binder death handled elsewhere
-                }
-            }
-        }
-
-        public void dispatchConnected(ConnectionCallback callback, ConnectionInfo connection) {
-            if (callback == mConnectionCallback) {
-                if (DEBUG) {
-                    Log.d(TAG, "connected: connection=" + connection);
-                }
-                if (mConnection == null) {
-                    mConnection = connection;
-
-                    ParcelableConnectionInfo pci = new ParcelableConnectionInfo();
-                    pci.audioAttributes = connection.getAudioAttributes();
-                    pci.presentationDisplayId = connection.getPresentationDisplay() != null ?
-                            connection.getPresentationDisplay().getDisplayId() : -1;
-                    pci.protocolBinders = new IBinder[connection.getProtocols().size()];
-                    for (int i = 0; i < pci.protocolBinders.length; i++) {
-                        pci.protocolBinders[i] = connection.getProtocolBinder(i);
-                    }
-                    pci.extras = connection.getExtras();
-                    try {
-                        mClientCallback.onConnected(mConnectionSeq, pci);
-                    } catch (RemoteException ex) {
-                        // binder death handled elsewhere
-                    }
-                } else {
-                    Log.w(TAG, "Media route service called onConnected() while already "
-                            + "connected.");
-                }
-            }
-        }
-
-        public void dispatchDisconnected(ConnectionCallback callback) {
-            if (callback == mConnectionCallback) {
-                if (DEBUG) {
-                    Log.d(TAG, "disconnected");
-                }
-
-                if (mConnection != null) {
-                    mConnection.close();
-                    mConnection = null;
-
-                    try {
-                        mClientCallback.onDisconnected(mConnectionSeq);
-                    } catch (RemoteException ex) {
-                        // binder death handled elsewhere
-                    }
-                }
-            }
-        }
-
-        public void dispatchConnectionFailed(ConnectionCallback callback,
-                int error, CharSequence message, Bundle extras) {
-            if (callback == mConnectionCallback) {
-                if (DEBUG) {
-                    Log.d(TAG, "connectionFailed: error=" + error + ", message=" + message
-                            + ", extras=" + extras);
-                }
-
-                try {
-                    mClientCallback.onConnectionFailed(mConnectionSeq, error, message, extras);
-                } catch (RemoteException ex) {
-                    // binder death handled elsewhere
-                }
-            }
-        }
-    }
-
-    private static final class DestinationRecord {
-        public final DestinationInfo destination;
-        public final List<RouteInfo> routes;
-
-        public DestinationRecord(DestinationInfo destination, List<RouteInfo> routes) {
-            this.destination = destination;
-            this.routes = routes;
-        }
-
-        public RouteInfo getRoute(String routeId) {
-            final int count = routes.size();
-            for (int i = 0; i < count; i++) {
-                RouteInfo route = routes.get(i);
-                if (route.getId().equals(routeId)) {
-                    return route;
-                }
-            }
-            return null;
-        }
-    }
-}
diff --git a/media/java/android/media/routing/MediaRouter.java b/media/java/android/media/routing/MediaRouter.java
deleted file mode 100644
index 4f6d324..0000000
--- a/media/java/android/media/routing/MediaRouter.java
+++ /dev/null
@@ -1,1886 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.routing;
-
-import android.annotation.DrawableRes;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Presentation;
-import android.app.Service;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ServiceInfo;
-import android.graphics.drawable.Drawable;
-import android.hardware.display.DisplayManager;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.AudioTrack;
-import android.media.VolumeProvider;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.view.Display;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Media router allows applications to discover, connect to, control,
- * and send content to nearby media devices known as destinations.
- * <p>
- * There are generally two participants involved in media routing: an
- * application that wants to send media content to a destination and a
- * {@link MediaRouteService media route service} that provides the
- * service of transporting that content where it needs to go on behalf of the
- * application.
- * </p><p>
- * To send media content to a destination, the application must ask the system
- * to discover available routes to destinations that provide certain capabilities,
- * establish a connection to a route, then send messages through the connection to
- * control the routing of audio and video streams, launch remote applications,
- * and invoke other functions of the destination.
- * </p><p>
- * Media router objects are thread-safe.
- * </p>
- *
- * <h3>Destinations</h3>
- * <p>
- * The media devices to which an application may send media content are referred
- * to in the API as destinations.  Each destination therefore represents a single
- * independent device such as a speaker or TV set.  Destinations are given meaningful
- * names and descriptions to help the user associate them with devices in their
- * environment.
- * </p><p>
- * Destinations may be local or remote and may be accessed through various means,
- * often wirelessly.  The user may install media route services to enable
- * media applications to connect to a variety of destinations with different
- * capabilities.
- * </p>
- *
- * <h3>Routes</h3>
- * <p>
- * Routes represent possible usages or means of reaching and interacting with
- * a destination.  Since destinations may support many different features, they may
- * each offer multiple routes for applications to choose from based on their needs.
- * For example, one route might express the ability to stream locally rendered audio
- * and video to the device; another route might express the ability to send a URL for
- * the destination to download from the network and play all by itself.
- * </p><p>
- * Routes are discovered according to the set of capabilities that
- * an application or the system is seeking to use at a particular time.  For example,
- * if an application wants to stream music to a destination then it will ask the
- * {@link MediaRouter} to find routes to destinations can stream music and ignore
- * all other destinations that cannot.
- * </p><p>
- * In general, the application will inspect the set of routes that have been
- * offered then connect to the most appropriate route for its desired purpose.
- * </p>
- *
- * <h3>Route Selection</h3>
- * <p>
- * When the user open the media route chooser activity, the system will display
- * a list of nearby media destinations which have been discovered.  After the
- * choice is made the application may connect to one of the routes offered by
- * this destination and begin communicating with the destination.
- * </p><p>
- * Destinations are located through a process called discovery.  During discovery,
- * the system will start installed {@link MediaRouteService media route services}
- * to scan the network for nearby devices that offer the kinds of capabilities that the
- * application is seeking to use.  The application specifies the capabilities it requires by
- * adding {@link MediaRouteSelector media route selectors} to the media router
- * using the {@link #addSelector} method.  Only destinations that provide routes
- * which satisfy at least one of these media route selectors will be discovered.
- * </p><p>
- * Once the user has selected a destination, the application will be given a chance
- * to choose one of the routes to which it would like to connect.  The application
- * may switch to a different route from the same destination at a later time but
- * in order to connect to a new destination, the application must once again launch
- * the media route chooser activity to ask the user to choose a destination.
- * </p>
- *
- * <h3>Route Protocols</h3>
- * <p>
- * Route protocols express capabilities offered by routes.  Each media route selector
- * must specify at least one required protocol by which the routes will be selected.
- * </p><p>
- * The framework provides several predefined <code>MediaRouteProtocols</code> which are
- * defined in the <code>android-support-media-protocols.jar</code> support library.
- * Applications must statically link this library to make use of these protocols.
- * </p><p>
- * The static library approach is used to enable ongoing extension and refinement
- * of protocols in the SDK and interoperability with the media router implementation
- * for older platform versions which is offered by the framework support library.
- * </p><p>
- * Media route services may also define custom media route protocols of their own
- * to enable applications to access specialized capabilities of certain destinations
- * assuming they have linked in the required protocol code.
- * </p><p>
- * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code> for more information.
- * </p>
- *
- * <h3>Connections</h3>
- * <p>
- * After connecting to a media route, the application can send commands to
- * the route using any of the protocols that it requested.  If the route supports live
- * audio or video streaming then the application can create an {@link AudioTrack} or
- * {@link Presentation} to route locally generated content to the destination.
- * </p>
- *
- * <h3>Delegation</h3>
- * <p>
- * The creator of the media router is responsible for establishing the policy for
- * discovering and connecting to destinations.  UI components may observe the state
- * of the media router by {@link #createDelegate creating} a {@link Delegate}.
- * </p><p>
- * The media router should also be attached to the {@link MediaSession media session}
- * that is handling media playback lifecycle.  This will allow
- * authorized {@link MediaController media controllers}, possibly running in other
- * processes, to provide UI to examine and change the media destination by
- * {@link MediaController#createMediaRouterDelegate creating} a {@link Delegate}
- * for the media router associated with the session.
- * </p>
- */
-public final class MediaRouter {
-    private final DisplayManager mDisplayManager;
-
-    private final Object mLock = new Object();
-
-    private RoutingCallback mRoutingCallback;
-    private Handler mRoutingCallbackHandler;
-
-    private boolean mReleased;
-    private int mDiscoveryState;
-    private int mConnectionState;
-    private final ArrayList<MediaRouteSelector> mSelectors =
-            new ArrayList<MediaRouteSelector>();
-    private final ArrayMap<DestinationInfo, List<RouteInfo>> mDiscoveredDestinations =
-            new ArrayMap<DestinationInfo, List<RouteInfo>>();
-    private RouteInfo mSelectedRoute;
-    private ConnectionInfo mConnection;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = { DISCOVERY_STATE_STOPPED, DISCOVERY_STATE_STARTED })
-    public @interface DiscoveryState { }
-
-    /**
-     * Discovery state: Discovery is not currently in progress.
-     */
-    public static final int DISCOVERY_STATE_STOPPED = 0;
-
-    /**
-     * Discovery state: Discovery is being performed.
-     */
-    public static final int DISCOVERY_STATE_STARTED = 1;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, value = { DISCOVERY_FLAG_BACKGROUND })
-    public @interface DiscoveryFlags { }
-
-    /**
-     * Discovery flag: Indicates that the client has requested passive discovery in
-     * the background.  The media route service should try to use less power and rely
-     * more on its internal caches to minimize its impact.
-     */
-    public static final int DISCOVERY_FLAG_BACKGROUND = 1 << 0;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = { DISCOVERY_ERROR_UNKNOWN, DISCOVERY_ERROR_ABORTED,
-            DISCOVERY_ERROR_NO_CONNECTIVITY })
-    public @interface DiscoveryError { }
-
-    /**
-     * Discovery error: Unknown error; refer to the error message for details.
-     */
-    public static final int DISCOVERY_ERROR_UNKNOWN = 0;
-
-    /**
-     * Discovery error: The media router or media route service has decided not to
-     * handle the discovery request for some reason.
-     */
-    public static final int DISCOVERY_ERROR_ABORTED = 1;
-
-    /**
-     * Discovery error: The media route service is unable to perform discovery
-     * due to a lack of connectivity such as because the radio is disabled.
-     */
-    public static final int DISCOVERY_ERROR_NO_CONNECTIVITY = 2;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = { CONNECTION_STATE_DISCONNECTED, CONNECTION_STATE_CONNECTING,
-            CONNECTION_STATE_CONNECTED })
-    public @interface ConnectionState { }
-
-    /**
-     * Connection state: No destination has been selected.  Media content should
-     * be sent to the default output.
-     */
-    public static final int CONNECTION_STATE_DISCONNECTED = 0;
-
-    /**
-     * Connection state: The application is in the process of connecting to
-     * a route offered by the selected destination.
-     */
-    public static final int CONNECTION_STATE_CONNECTING = 1;
-
-    /**
-     * Connection state: The application has connected to a route offered by
-     * the selected destination.
-     */
-    public static final int CONNECTION_STATE_CONNECTED = 2;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, value = { CONNECTION_FLAG_BARGE })
-    public @interface ConnectionFlags { }
-
-    /**
-     * Connection flag: Indicates that the client has requested to barge in and evict
-     * other clients that might have already connected to the destination and that
-     * would otherwise prevent this client from connecting.  When this flag is not
-     * set, the media route service should be polite and report
-     * {@link MediaRouter#CONNECTION_ERROR_BUSY} in case the destination is
-     * already occupied and cannot accept additional connections.
-     */
-    public static final int CONNECTION_FLAG_BARGE = 1 << 0;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = { CONNECTION_ERROR_UNKNOWN, CONNECTION_ERROR_ABORTED,
-            CONNECTION_ERROR_UNAUTHORIZED, CONNECTION_ERROR_UNAUTHORIZED,
-            CONNECTION_ERROR_BUSY, CONNECTION_ERROR_TIMEOUT, CONNECTION_ERROR_BROKEN })
-    public @interface ConnectionError { }
-
-    /**
-     * Connection error: Unknown error; refer to the error message for details.
-     */
-    public static final int CONNECTION_ERROR_UNKNOWN = 0;
-
-    /**
-     * Connection error: The media router or media route service has decided not to
-     * handle the connection request for some reason.
-     */
-    public static final int CONNECTION_ERROR_ABORTED = 1;
-
-    /**
-     * Connection error: The device has refused the connection from this client.
-     * This error should be avoided because the media route service should attempt
-     * to filter out devices that the client cannot access as it performs discovery
-     * on behalf of that client.
-     */
-    public static final int CONNECTION_ERROR_UNAUTHORIZED = 2;
-
-    /**
-     * Connection error: The device is unreachable over the network.
-     */
-    public static final int CONNECTION_ERROR_UNREACHABLE = 3;
-
-    /**
-     * Connection error: The device is already busy serving another client and
-     * the connection request did not ask to barge in.
-     */
-    public static final int CONNECTION_ERROR_BUSY = 4;
-
-    /**
-     * Connection error: A timeout occurred during connection.
-     */
-    public static final int CONNECTION_ERROR_TIMEOUT = 5;
-
-    /**
-     * Connection error: The connection to the device was severed unexpectedly.
-     */
-    public static final int CONNECTION_ERROR_BROKEN = 6;
-
-    /**
-     * Connection error: The connection was terminated because a different client barged
-     * in and took control of the destination.
-     */
-    public static final int CONNECTION_ERROR_BARGED = 7;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = { DISCONNECTION_REASON_APPLICATION_REQUEST,
-            DISCONNECTION_REASON_USER_REQUEST, DISCONNECTION_REASON_ERROR })
-    public @interface DisconnectionReason { }
-
-    /**
-     * Disconnection reason: The application requested disconnection itself.
-     */
-    public static final int DISCONNECTION_REASON_APPLICATION_REQUEST = 0;
-
-    /**
-     * Disconnection reason: The user requested disconnection.
-     */
-    public static final int DISCONNECTION_REASON_USER_REQUEST = 1;
-
-    /**
-     * Disconnection reason: An error occurred.
-     */
-    public static final int DISCONNECTION_REASON_ERROR = 2;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, value = { ROUTE_FEATURE_LIVE_AUDIO, ROUTE_FEATURE_LIVE_VIDEO })
-    public @interface RouteFeatures { }
-
-    /**
-     * Route feature: Live audio.
-     * <p>
-     * A route that supports live audio streams audio rendered by the application
-     * to the destination.
-     * </p><p>
-     * To take advantage of live audio routing, the application must render its
-     * media using the audio attributes specified by {@link #getPreferredAudioAttributes}.
-     * </p>
-     *
-     * @see #getPreferredAudioAttributes
-     * @see android.media.AudioAttributes
-     */
-    public static final int ROUTE_FEATURE_LIVE_AUDIO = 1 << 0;
-
-    /**
-     * Route feature: Live video.
-     * <p>
-     * A route that supports live video streams video rendered by the application
-     * to the destination.
-     * </p><p>
-     * To take advantage of live video routing, the application must render its
-     * media to a {@link android.app.Presentation presentation window} on the
-     * display specified by {@link #getPreferredPresentationDisplay}.
-     * </p>
-     *
-     * @see #getPreferredPresentationDisplay
-     * @see android.app.Presentation
-     */
-    public static final int ROUTE_FEATURE_LIVE_VIDEO = 1 << 1;
-
-    /**
-     * Creates a media router.
-     *
-     * @param context The context with which the router is associated.
-     */
-    public MediaRouter(@NonNull Context context) {
-        if (context == null) {
-            throw new IllegalArgumentException("context must not be null");
-        }
-
-        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
-    }
-
-    /** @hide */
-    public IMediaRouter getBinder() {
-        // todo
-        return null;
-    }
-
-    /**
-     * Disconnects from the selected destination and releases the media router.
-     * <p>
-     * This method should be called by the application when it no longer requires
-     * the media router to ensure that all bound resources may be cleaned up.
-     * </p>
-     */
-    public void release() {
-        synchronized (mLock) {
-            mReleased = true;
-            // todo
-        }
-    }
-
-    /**
-     * Returns true if the media router has been released.
-     */
-    public boolean isReleased() {
-        synchronized (mLock) {
-            return mReleased;
-        }
-    }
-
-    /**
-     * Gets the current route discovery state.
-     *
-     * @return The current discovery state: one of {@link #DISCOVERY_STATE_STOPPED},
-     * {@link #DISCOVERY_STATE_STARTED}.
-     */
-    public @DiscoveryState int getDiscoveryState() {
-        synchronized (mLock) {
-            return mDiscoveryState;
-        }
-    }
-
-    /**
-     * Gets the current route connection state.
-     *
-     * @return The current state: one of {@link #CONNECTION_STATE_DISCONNECTED},
-     * {@link #CONNECTION_STATE_CONNECTING} or {@link #CONNECTION_STATE_CONNECTED}.
-     */
-    public @ConnectionState int getConnectionState() {
-        synchronized (mLock) {
-            return mConnectionState;
-        }
-    }
-
-    /**
-     * Creates a media router delegate through which the destination of the media
-     * router may be controlled.
-     * <p>
-     * This is the point of entry for UI code that initiates discovery and
-     * connection to routes.
-     * </p>
-     */
-    public @NonNull Delegate createDelegate() {
-        return null; // todo
-    }
-
-    /**
-     * Sets a callback to participate in route discovery, filtering, and connection
-     * establishment.
-     *
-     * @param callback The callback to set, or null if none.
-     * @param handler The handler to receive callbacks, or null to use the current thread.
-     */
-    public void setRoutingCallback(@Nullable RoutingCallback callback,
-            @Nullable Handler handler) {
-        synchronized (mLock) {
-            if (callback == null) {
-                mRoutingCallback = null;
-                mRoutingCallbackHandler = null;
-            } else {
-                mRoutingCallback = callback;
-                mRoutingCallbackHandler = handler != null ? handler : new Handler();
-            }
-        }
-    }
-
-    /**
-     * Adds a media route selector to use to find destinations that have
-     * routes with the specified capabilities during route discovery.
-     */
-    public void addSelector(@NonNull MediaRouteSelector selector) {
-        if (selector == null) {
-            throw new IllegalArgumentException("selector must not be null");
-        }
-
-        synchronized (mLock) {
-            if (!mSelectors.contains(selector)) {
-                mSelectors.add(selector);
-                // todo
-            }
-        }
-    }
-
-    /**
-     * Removes a media route selector.
-     */
-    public void removeSelector(@NonNull MediaRouteSelector selector) {
-        if (selector == null) {
-            throw new IllegalArgumentException("selector must not be null");
-        }
-
-        synchronized (mLock) {
-            if (mSelectors.remove(selector)) {
-                // todo
-            }
-        }
-    }
-
-    /**
-     * Removes all media route selectors.
-     * <p>
-     * Note that at least one selector must be added in order to perform discovery.
-     * </p>
-     */
-    public void clearSelectors() {
-        synchronized (mLock) {
-            if (!mSelectors.isEmpty()) {
-                mSelectors.clear();
-                // todo
-            }
-        }
-    }
-
-    /**
-     * Gets a list of all media route selectors to consider during discovery.
-     */
-    public @NonNull List<MediaRouteSelector> getSelectors() {
-        synchronized (mLock) {
-            return new ArrayList<MediaRouteSelector>(mSelectors);
-        }
-    }
-
-    /**
-     * Gets the connection to the currently selected route.
-     *
-     * @return The connection to the currently selected route, or null if not connected.
-     */
-    public @NonNull ConnectionInfo getConnection() {
-        synchronized (mLock) {
-            return mConnection;
-        }
-    }
-
-    /**
-     * Gets the list of discovered destinations.
-     * <p>
-     * This list is only valid while discovery is running and is null otherwise.
-     * </p>
-     *
-     * @return The list of discovered destinations, or null if discovery is not running.
-     */
-    public @NonNull List<DestinationInfo> getDiscoveredDestinations() {
-        synchronized (mLock) {
-            if (mDiscoveryState == DISCOVERY_STATE_STARTED) {
-                return new ArrayList<DestinationInfo>(mDiscoveredDestinations.keySet());
-            }
-            return null;
-        }
-    }
-
-    /**
-     * Gets the list of discovered routes for a particular destination.
-     * <p>
-     * This list is only valid while discovery is running and is null otherwise.
-     * </p>
-     *
-     * @param destination The destination for which to get the list of discovered routes.
-     * @return The list of discovered routes for the destination, or null if discovery
-     * is not running.
-     */
-    public @NonNull List<RouteInfo> getDiscoveredRoutes(@NonNull DestinationInfo destination) {
-        if (destination == null) {
-            throw new IllegalArgumentException("destination must not be null");
-        }
-        synchronized (mLock) {
-            if (mDiscoveryState == DISCOVERY_STATE_STARTED) {
-                List<RouteInfo> routes = mDiscoveredDestinations.get(destination);
-                if (routes != null) {
-                    return new ArrayList<RouteInfo>(routes);
-                }
-            }
-            return null;
-        }
-    }
-
-    /**
-     * Gets the destination that has been selected.
-     *
-     * @return The selected destination, or null if disconnected.
-     */
-    public @Nullable DestinationInfo getSelectedDestination() {
-        synchronized (mLock) {
-            return mSelectedRoute != null ? mSelectedRoute.getDestination() : null;
-        }
-    }
-
-    /**
-     * Gets the route that has been selected.
-     *
-     * @return The selected destination, or null if disconnected.
-     */
-    public @Nullable RouteInfo getSelectedRoute() {
-        synchronized (mLock) {
-            return mSelectedRoute;
-        }
-    }
-
-    /**
-     * Gets the preferred audio attributes that should be used to stream live audio content
-     * based on the connected route.
-     * <p>
-     * Use an {@link AudioTrack} to send audio content to the destination with these
-     * audio attributes.
-     * </p><p>
-     * The preferred audio attributes may change when a connection is established but it
-     * will remain constant until disconnected.
-     * </p>
-     *
-     * @return The preferred audio attributes to use.  When connected, returns the
-     * route's audio attributes or null if it does not support live audio streaming.
-     * Otherwise returns audio attributes associated with {@link AudioAttributes#USAGE_MEDIA}.
-     */
-    public @Nullable AudioAttributes getPreferredAudioAttributes() {
-        synchronized (mLock) {
-            if (mConnection != null) {
-                return mConnection.getAudioAttributes();
-            }
-            return new AudioAttributes.Builder()
-                    .setLegacyStreamType(AudioManager.STREAM_MUSIC)
-                    .build();
-        }
-    }
-
-    /**
-     * Gets the preferred presentation display that should be used to stream live video content
-     * based on the connected route.
-     * <p>
-     * Use a {@link Presentation} to send video content to the destination with this display.
-     * </p><p>
-     * The preferred presentation display may change when a connection is established but it
-     * will remain constant until disconnected.
-     * </p>
-     *
-     * @return The preferred presentation display to use.  When connected, returns
-     * the route's presentation display or null if it does not support live video
-     * streaming.  Otherwise returns the first available
-     * {@link DisplayManager#DISPLAY_CATEGORY_PRESENTATION presentation display},
-     * such as a mirrored wireless or HDMI display or null if none.
-     */
-    public @Nullable Display getPreferredPresentationDisplay() {
-        synchronized (mLock) {
-            if (mConnection != null) {
-                return mConnection.getPresentationDisplay();
-            }
-            Display[] displays = mDisplayManager.getDisplays(
-                    DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
-            return displays.length != 0 ? displays[0] : null;
-        }
-    }
-
-    /**
-     * Gets the preferred volume provider that should be used to control the volume
-     * of content rendered on the currently selected route.
-     * <p>
-     * The preferred volume provider may change when a connection is established but it
-     * will remain the same until disconnected.
-     * </p>
-     *
-     * @return The preferred volume provider to use, or null if the currently
-     * selected route does not support remote volume adjustment or if the connection
-     * is not yet established.  If no route is selected, returns null to indicate
-     * that system volume control should be used.
-     */
-    public @Nullable VolumeProvider getPreferredVolumeProvider() {
-        synchronized (mLock) {
-            if (mConnection != null) {
-                return mConnection.getVolumeProvider();
-            }
-            return null;
-        }
-    }
-
-    /**
-     * Requests to pause streaming of live audio or video routes.
-     * Should be called when the application is going into the background and is
-     * no longer rendering content locally.
-     * <p>
-     * This method does nothing unless a connection has been established.
-     * </p>
-     */
-    public void pauseStream() {
-        // todo
-    }
-
-    /**
-     * Requests to resume streaming of live audio or video routes.
-     * May be called when the application is returning to the foreground and is
-     * about to resume rendering content locally.
-     * <p>
-     * This method does nothing unless a connection has been established.
-     * </p>
-     */
-    public void resumeStream() {
-        // todo
-    }
-
-    /**
-     * This class is used by UI components to let the user discover and
-     * select a destination to which the media router should connect.
-     * <p>
-     * This API has somewhat more limited functionality than the {@link MediaRouter}
-     * itself because it is designed to allow applications to control
-     * the destination of media router instances that belong to other processes.
-     * </p><p>
-     * To control the destination of your own media router, call
-     * {@link #createDelegate} to obtain a local delegate object.
-     * </p><p>
-     * To control the destination of a media router that belongs to another process,
-     * first obtain a {@link MediaController} that is associated with the media playback
-     * that is occurring in that process, then call
-     * {@link MediaController#createMediaRouterDelegate} to obtain an instance of
-     * its destination controls.  Note that special permissions may be required to
-     * obtain the {@link MediaController} instance in the first place.
-     * </p>
-     */
-    public static final class Delegate {
-        /**
-         * Returns true if the media router has been released.
-         */
-        public boolean isReleased() {
-            // todo
-            return false;
-        }
-
-        /**
-         * Gets the current route discovery state.
-         *
-         * @return The current discovery state: one of {@link #DISCOVERY_STATE_STOPPED},
-         * {@link #DISCOVERY_STATE_STARTED}.
-         */
-        public @DiscoveryState int getDiscoveryState() {
-            // todo
-            return -1;
-        }
-
-        /**
-         * Gets the current route connection state.
-         *
-         * @return The current state: one of {@link #CONNECTION_STATE_DISCONNECTED},
-         * {@link #CONNECTION_STATE_CONNECTING} or {@link #CONNECTION_STATE_CONNECTED}.
-         */
-        public @ConnectionState int getConnectionState() {
-            // todo
-            return -1;
-        }
-
-        /**
-         * Gets the currently selected destination.
-         *
-         * @return The destination information, or null if none.
-         */
-        public @Nullable DestinationInfo getSelectedDestination() {
-            return null;
-        }
-
-        /**
-         * Gets the list of discovered destinations.
-         * <p>
-         * This list is only valid while discovery is running and is null otherwise.
-         * </p>
-         *
-         * @return The list of discovered destinations, or null if discovery is not running.
-         */
-        public @NonNull List<DestinationInfo> getDiscoveredDestinations() {
-            return null;
-        }
-
-        /**
-         * Adds a callback to receive state changes.
-         *
-         * @param callback The callback to set, or null if none.
-         * @param handler The handler to receive callbacks, or null to use the current thread.
-         */
-        public void addStateCallback(@Nullable StateCallback callback,
-                @Nullable Handler handler) {
-            if (callback == null) {
-                throw new IllegalArgumentException("callback must not be null");
-            }
-            if (handler == null) {
-                handler = new Handler();
-            }
-            // todo
-        }
-
-        /**
-         * Removes a callback for state changes.
-         *
-         * @param callback The callback to set, or null if none.
-         */
-        public void removeStateCallback(@Nullable StateCallback callback) {
-            // todo
-        }
-
-        /**
-         * Starts performing discovery.
-         * <p>
-         * Performing discovery is expensive.  Make sure to call {@link #stopDiscovery}
-         * as soon as possible once a new destination has been selected to allow the system
-         * to stop services associated with discovery.
-         * </p>
-         *
-         * @param flags The discovery flags, such as {@link MediaRouter#DISCOVERY_FLAG_BACKGROUND}.
-         */
-        public void startDiscovery(@DiscoveryFlags int flags) {
-            // todo
-        }
-
-        /**
-         * Stops performing discovery.
-         */
-        public void stopDiscovery() {
-            // todo
-        }
-
-        /**
-         * Connects to a destination during route discovery.
-         * <p>
-         * This method may only be called while route discovery is active and the
-         * destination appears in the
-         * {@link #getDiscoveredDestinations list of discovered destinations}.
-         * If the media router is already connected to a route then it will first disconnect
-         * from the current route then connect to the new route.
-         * </p>
-         *
-         * @param destination The destination to which the media router should connect.
-         * @param flags The connection flags, such as {@link MediaRouter#CONNECTION_FLAG_BARGE}.
-         */
-        public void connect(@NonNull DestinationInfo destination, @DiscoveryFlags int flags) {
-            // todo
-        }
-
-        /**
-         * Disconnects from the currently selected destination.
-         * <p>
-         * Does nothing if not currently connected.
-         * </p>
-         *
-         * @param reason The reason for the disconnection: one of
-         * {@link #DISCONNECTION_REASON_APPLICATION_REQUEST},
-         * {@link #DISCONNECTION_REASON_USER_REQUEST}, or {@link #DISCONNECTION_REASON_ERROR}.
-         */
-        public void disconnect(@DisconnectionReason int reason) {
-            // todo
-        }
-    }
-
-    /**
-     * Describes immutable properties of a connection to a route.
-     */
-    public static final class ConnectionInfo {
-        private final RouteInfo mRoute;
-        private final AudioAttributes mAudioAttributes;
-        private final Display mPresentationDisplay;
-        private final VolumeProvider mVolumeProvider;
-        private final IBinder[] mProtocolBinders;
-        private final Object[] mProtocolInstances;
-        private final Bundle mExtras;
-        private final ArrayList<Closeable> mCloseables;
-
-        private static final Class<?>[] MEDIA_ROUTE_PROTOCOL_CTOR_PARAMETERS =
-                new Class<?>[] { IBinder.class };
-
-        ConnectionInfo(RouteInfo route,
-                AudioAttributes audioAttributes, Display display,
-                VolumeProvider volumeProvider, IBinder[] protocolBinders,
-                Bundle extras, ArrayList<Closeable> closeables) {
-            mRoute = route;
-            mAudioAttributes = audioAttributes;
-            mPresentationDisplay = display;
-            mVolumeProvider = volumeProvider;
-            mProtocolBinders = protocolBinders;
-            mProtocolInstances = new Object[mProtocolBinders.length];
-            mExtras = extras;
-            mCloseables = closeables;
-        }
-
-        /**
-         * Gets the route that is connected.
-         */
-        public @NonNull RouteInfo getRoute() {
-            return mRoute;
-        }
-
-        /**
-         * Gets the audio attributes which the client should use to stream audio
-         * to the destination, or null if the route does not support live audio streaming.
-         */
-        public @Nullable AudioAttributes getAudioAttributes() {
-            return mAudioAttributes;
-        }
-
-        /**
-         * Gets the display which the client should use to stream video to the
-         * destination using a {@link Presentation}, or null if the route does not
-         * support live video streaming.
-         */
-        public @Nullable Display getPresentationDisplay() {
-            return mPresentationDisplay;
-        }
-
-        /**
-         * Gets the route's volume provider, or null if none.
-         */
-        public @Nullable VolumeProvider getVolumeProvider() {
-            return mVolumeProvider;
-        }
-
-        /**
-         * Gets the set of supported route features.
-         */
-        public @RouteFeatures int getFeatures() {
-            return mRoute.getFeatures();
-        }
-
-        /**
-         * Gets the list of supported route protocols.
-         * <p>
-         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-         * for more information.
-         * </p>
-         */
-        public @NonNull List<String> getProtocols() {
-            return mRoute.getProtocols();
-        }
-
-        /**
-         * Gets an instance of a route protocol object that wraps the protocol binder
-         * and provides easy access to the protocol's functionality.
-         * <p>
-         * This is a convenience method which invokes {@link #getProtocolBinder(String)}
-         * using the name of the provided class then passes the resulting {@link IBinder}
-         * to a single-argument constructor of that class.
-         * </p><p>
-         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-         * for more information.
-         * </p>
-         */
-        @SuppressWarnings("unchecked")
-        public @Nullable <T> T getProtocolObject(Class<T> clazz) {
-            int index = getProtocols().indexOf(clazz.getName());
-            if (index < 0) {
-                return null;
-            }
-            if (mProtocolInstances[index] == null && mProtocolBinders[index] != null) {
-                final Constructor<T> ctor;
-                try {
-                    ctor = clazz.getConstructor(MEDIA_ROUTE_PROTOCOL_CTOR_PARAMETERS);
-                } catch (NoSuchMethodException ex) {
-                    throw new RuntimeException("Could not find public constructor "
-                            + "with IBinder argument in protocol class: " + clazz.getName(), ex);
-                }
-                try {
-                    mProtocolInstances[index] = ctor.newInstance(mProtocolBinders[index]);
-                } catch (InstantiationException | IllegalAccessException
-                        | InvocationTargetException ex) {
-                    throw new RuntimeException("Could create instance of protocol class: "
-                            + clazz.getName(), ex);
-                }
-            }
-            return (T)mProtocolInstances[index];
-        }
-
-        /**
-         * Gets the {@link IBinder} that provides access to the specified route protocol
-         * or null if the protocol is not supported.
-         * <p>
-         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-         * for more information.
-         * </p>
-         */
-        public @Nullable IBinder getProtocolBinder(@NonNull String name) {
-            int index = getProtocols().indexOf(name);
-            return index >= 0 ? mProtocolBinders[index] : null;
-        }
-
-        /**
-         * Gets the {@link IBinder} that provides access to the specified route protocol
-         * at the given index in the protocol list or null if the protocol is not supported.
-         * <p>
-         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-         * for more information.
-         * </p>
-         */
-        public @Nullable IBinder getProtocolBinder(int index) {
-            return mProtocolBinders[index];
-        }
-
-        /**
-         * Gets optional extra media route service or protocol specific information about
-         * the connection.  Use the service or protocol name as the prefix for
-         * any extras to avoid namespace collisions.
-         */
-        public @Nullable Bundle getExtras() {
-            return mExtras;
-        }
-
-        /**
-         * Closes all closeables associated with the connection when the connection
-         * is being torn down.
-         */
-        void close() {
-            final int count = mCloseables.size();
-            for (int i = 0; i < count; i++) {
-                try {
-                    mCloseables.get(i).close();
-                } catch (IOException ex) {
-                }
-            }
-        }
-
-        @Override
-        public @NonNull String toString() {
-            return "ConnectionInfo{ route=" + mRoute
-                    + ", audioAttributes=" + mAudioAttributes
-                    + ", presentationDisplay=" + mPresentationDisplay
-                    + ", volumeProvider=" + mVolumeProvider
-                    + ", protocolBinders=" + mProtocolBinders + " }";
-        }
-
-        /**
-         * Builds {@link ConnectionInfo} objects.
-         */
-        public static final class Builder {
-            private final RouteInfo mRoute;
-            private AudioAttributes mAudioAttributes;
-            private Display mPresentationDisplay;
-            private VolumeProvider mVolumeProvider;
-            private final IBinder[] mProtocols;
-            private Bundle mExtras;
-            private final ArrayList<Closeable> mCloseables = new ArrayList<Closeable>();
-
-            /**
-             * Creates a builder for connection information.
-             *
-             * @param route The route that is connected.
-             */
-            public Builder(@NonNull RouteInfo route) {
-                if (route == null) {
-                    throw new IllegalArgumentException("route");
-                }
-                mRoute = route;
-                mProtocols = new IBinder[route.getProtocols().size()];
-            }
-
-            /**
-             * Sets the audio attributes which the client should use to stream audio
-             * to the destination, or null if the route does not support live audio streaming.
-             */
-            public @NonNull Builder setAudioAttributes(
-                    @Nullable AudioAttributes audioAttributes) {
-                mAudioAttributes = audioAttributes;
-                return this;
-            }
-
-            /**
-             * Sets the display which the client should use to stream video to the
-             * destination using a {@link Presentation}, or null if the route does not
-             * support live video streaming.
-             */
-            public @NonNull Builder setPresentationDisplay(@Nullable Display display) {
-                mPresentationDisplay = display;
-                return this;
-            }
-
-            /**
-             * Sets the route's volume provider, or null if none.
-             */
-            public @NonNull Builder setVolumeProvider(@Nullable VolumeProvider provider) {
-                mVolumeProvider = provider;
-                return this;
-            }
-
-            /**
-             * Sets the binder stub of a supported route protocol using
-             * the protocol's fully qualified class name.  The protocol must be one
-             * of those that was indicated as being supported by the route.
-             * <p>
-             * If the stub implements {@link Closeable} then it will automatically
-             * be closed when the client disconnects from the route.
-             * </p><p>
-             * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-             * for more information.
-             * </p>
-             */
-            public @NonNull Builder setProtocolStub(@NonNull Class<?> clazz,
-                    @NonNull IInterface stub) {
-                if (clazz == null) {
-                    throw new IllegalArgumentException("clazz must not be null");
-                }
-                if (stub == null) {
-                    throw new IllegalArgumentException("stub must not be null");
-                }
-                if (stub instanceof Closeable) {
-                    mCloseables.add((Closeable)stub);
-                }
-                return setProtocolBinder(clazz.getName(), stub.asBinder());
-            }
-
-            /**
-             * Sets the binder interface of a supported route protocol by name.
-             * The protocol must be one of those that was indicated as being supported
-             * by the route.
-             * <p>
-             * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-             * for more information.
-             * </p>
-             */
-            public @NonNull Builder setProtocolBinder(@NonNull String name,
-                    @NonNull IBinder binder) {
-                if (TextUtils.isEmpty(name)) {
-                    throw new IllegalArgumentException("name must not be null or empty");
-                }
-                if (binder == null) {
-                    throw new IllegalArgumentException("binder must not be null");
-                }
-                int index = mRoute.getProtocols().indexOf(name);
-                if (index < 0) {
-                    throw new IllegalArgumentException("name must specify a protocol that "
-                            + "the route actually declared that it supports: "
-                            + "name=" + name + ", protocols=" + mRoute.getProtocols());
-                }
-                mProtocols[index] = binder;
-                return this;
-            }
-
-            /**
-             * Sets optional extra media route service or protocol specific information about
-             * the connection.  Use the service or protocol name as the prefix for
-             * any extras to avoid namespace collisions.
-             */
-            public @NonNull Builder setExtras(@Nullable Bundle extras) {
-                mExtras = extras;
-                return this;
-            }
-
-            /**
-             * Builds the {@link ConnectionInfo} object.
-             */
-            public @NonNull ConnectionInfo build() {
-                return new ConnectionInfo(mRoute,
-                        mAudioAttributes, mPresentationDisplay,
-                        mVolumeProvider, mProtocols, mExtras, mCloseables);
-            }
-        }
-    }
-
-    /**
-     * Describes one particular way of routing media content to a destination
-     * according to the capabilities specified by a media route selector on behalf
-     * of an application.
-     */
-    public static final class RouteInfo {
-        private final String mId;
-        private final DestinationInfo mDestination;
-        private final MediaRouteSelector mSelector;
-        private final int mFeatures;
-        private final ArrayList<String> mProtocols;
-        private final Bundle mExtras;
-
-        RouteInfo(String id, DestinationInfo destination, MediaRouteSelector selector,
-                int features, ArrayList<String> protocols, Bundle extras) {
-            mId = id;
-            mDestination = destination;
-            mSelector = selector;
-            mFeatures = features;
-            mProtocols = protocols;
-            mExtras = extras;
-        }
-
-        /**
-         * Gets the route's stable identifier.
-         * <p>
-         * The id is intended to uniquely identify the route among all routes that
-         * are offered by a particular destination in such a way that the client can
-         * refer to it at a later time.
-         * </p>
-         */
-        public @NonNull String getId() {
-            return mId;
-        }
-
-        /**
-         * Gets the destination that is offering this route.
-         */
-        public @NonNull DestinationInfo getDestination() {
-            return mDestination;
-        }
-
-        /**
-         * Gets the media route selector provided by the client for which this
-         * route was created.
-         * <p>
-         * It is implied that this route supports all of the required capabilities
-         * that were expressed in the selector.
-         * </p>
-         */
-        public @NonNull MediaRouteSelector getSelector() {
-            return mSelector;
-        }
-
-        /**
-         * Gets the set of supported route features.
-         */
-        public @RouteFeatures int getFeatures() {
-            return mFeatures;
-        }
-
-        /**
-         * Gets the list of supported route protocols.
-         * <p>
-         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
-         * for more information.
-         * </p>
-         */
-        public @NonNull List<String> getProtocols() {
-            return mProtocols;
-        }
-
-        /**
-         * Gets optional extra information about the route, or null if none.
-         */
-        public @Nullable Bundle getExtras() {
-            return mExtras;
-        }
-
-        @Override
-        public @NonNull String toString() {
-            return "RouteInfo{ id=" + mId + ", destination=" + mDestination
-                    + ", features=0x" + Integer.toHexString(mFeatures)
-                    + ", selector=" + mSelector + ", protocols=" + mProtocols
-                    + ", extras=" + mExtras + " }";
-        }
-
-        /**
-         * Builds {@link RouteInfo} objects.
-         */
-        public static final class Builder {
-            private final DestinationInfo mDestination;
-            private final String mId;
-            private final MediaRouteSelector mSelector;
-            private int mFeatures;
-            private final ArrayList<String> mProtocols = new ArrayList<String>();
-            private Bundle mExtras;
-
-            /**
-             * Creates a builder for route information.
-             *
-             * @param id The route's stable identifier.
-             * @param destination The destination of this route.
-             * @param selector The media route selector provided by the client for which
-             * this route was created.  This must be one of the selectors that was
-             * included in the discovery request.
-             */
-            public Builder(@NonNull String id, @NonNull DestinationInfo destination,
-                    @NonNull MediaRouteSelector selector) {
-                if (TextUtils.isEmpty(id)) {
-                    throw new IllegalArgumentException("id must not be null or empty");
-                }
-                if (destination == null) {
-                    throw new IllegalArgumentException("destination must not be null");
-                }
-                if (selector == null) {
-                    throw new IllegalArgumentException("selector must not be null");
-                }
-                mDestination = destination;
-                mId = id;
-                mSelector = selector;
-            }
-
-            /**
-             * Sets the set of supported route features.
-             */
-            public @NonNull Builder setFeatures(@RouteFeatures int features) {
-                mFeatures = features;
-                return this;
-            }
-
-            /**
-             * Adds a supported route protocol using its fully qualified class name.
-             * <p>
-             * If the protocol was not requested by the client in its selector
-             * then it will be silently discarded.
-             * </p>
-             */
-            public @NonNull <T extends IInterface> Builder addProtocol(@NonNull Class<T> clazz) {
-                if (clazz == null) {
-                    throw new IllegalArgumentException("clazz must not be null");
-                }
-                return addProtocol(clazz.getName());
-            }
-
-            /**
-             * Adds a supported route protocol by name.
-             * <p>
-             * If the protocol was not requested by the client in its selector
-             * then it will be silently discarded.
-             * </p>
-             */
-            public @NonNull Builder addProtocol(@NonNull String name) {
-                if (TextUtils.isEmpty(name)) {
-                    throw new IllegalArgumentException("name must not be null");
-                }
-                if (mSelector.containsProtocol(name)) {
-                    mProtocols.add(name);
-                }
-                return this;
-            }
-
-            /**
-             * Sets optional extra information about the route, or null if none.
-             */
-            public @NonNull Builder setExtras(@Nullable Bundle extras) {
-                mExtras = extras;
-                return this;
-            }
-
-            /**
-             * Builds the {@link RouteInfo} object.
-             * <p>
-             * Ensures that all required protocols have been supplied.
-             * </p>
-             */
-            public @NonNull RouteInfo build() {
-                int missingFeatures = mSelector.getRequiredFeatures() & ~mFeatures;
-                if (missingFeatures != 0) {
-                    throw new IllegalStateException("The media route selector "
-                            + "specified required features which this route does "
-                            + "not appear to support so it should not have been published: "
-                            + "missing 0x" + Integer.toHexString(missingFeatures));
-                }
-                for (String protocol : mSelector.getRequiredProtocols()) {
-                    if (!mProtocols.contains(protocol)) {
-                        throw new IllegalStateException("The media route selector "
-                                + "specified required protocols which this route "
-                                + "does not appear to support so it should not have "
-                                + "been published: missing " + protocol);
-                    }
-                }
-                return new RouteInfo(mId, mDestination, mSelector,
-                        mFeatures, mProtocols, mExtras);
-            }
-        }
-    }
-
-    /**
-     * Describes a destination for media content such as a device,
-     * an individual port on a device, or a group of devices.
-     */
-    public static final class DestinationInfo {
-        private final String mId;
-        private final ServiceMetadata mService;
-        private final CharSequence mName;
-        private final CharSequence mDescription;
-        private final int mIconResourceId;
-        private final Bundle mExtras;
-
-        DestinationInfo(String id, ServiceMetadata service,
-                CharSequence name, CharSequence description,
-                int iconResourceId, Bundle extras) {
-            mId = id;
-            mService = service;
-            mName = name;
-            mDescription = description;
-            mIconResourceId = iconResourceId;
-            mExtras = extras;
-        }
-
-        /**
-         * Gets the destination's stable identifier.
-         * <p>
-         * The id is intended to uniquely identify the destination among all destinations
-         * provided by the media route service in such a way that the client can
-         * refer to it at a later time.  Ideally, the id should be resilient to
-         * user-initiated actions such as changes to the name or description
-         * of the destination.
-         * </p>
-         */
-        public @NonNull String getId() {
-            return mId;
-        }
-
-        /**
-         * Gets metadata about the service that is providing access to this destination.
-         */
-        public @NonNull ServiceMetadata getServiceMetadata() {
-            return mService;
-        }
-
-        /**
-         * Gets the destination's name for display to the user.
-         */
-        public @NonNull CharSequence getName() {
-            return mName;
-        }
-
-        /**
-         * Gets the destination's description for display to the user, or null if none.
-         */
-        public @Nullable CharSequence getDescription() {
-            return mDescription;
-        }
-
-        /**
-         * Gets an icon resource from the service's package which is used
-         * to identify the destination, or -1 if none.
-         */
-        public @DrawableRes int getIconResourceId() {
-            return mIconResourceId;
-        }
-
-        /**
-         * Loads the icon drawable, or null if none.
-         */
-        public @Nullable Drawable loadIcon(@NonNull PackageManager pm) {
-            return mIconResourceId >= 0 ? mService.getDrawable(pm, mIconResourceId) : null;
-        }
-
-        /**
-         * Gets optional extra information about the destination, or null if none.
-         */
-        public @Nullable Bundle getExtras() {
-            return mExtras;
-        }
-
-        @Override
-        public @NonNull String toString() {
-            return "DestinationInfo{ id=" + mId + ", service=" + mService + ", name=" + mName
-                    + ", description=" + mDescription + ", iconResourceId=" + mIconResourceId
-                    + ", extras=" + mExtras + " }";
-        }
-
-        /**
-         * Builds {@link DestinationInfo} objects.
-         */
-        public static final class Builder {
-            private final String mId;
-            private final ServiceMetadata mService;
-            private final CharSequence mName;
-            private CharSequence mDescription;
-            private int mIconResourceId = -1;
-            private Bundle mExtras;
-
-            /**
-             * Creates a builder for destination information.
-             *
-             * @param id The destination's stable identifier.
-             * @param service Metatada about the service that is providing access to
-             * this destination.
-             * @param name The destination's name for display to the user.
-             */
-            public Builder(@NonNull String id, @NonNull ServiceMetadata service,
-                    @NonNull CharSequence name) {
-                if (TextUtils.isEmpty(id)) {
-                    throw new IllegalArgumentException("id must not be null or empty");
-                }
-                if (service == null) {
-                    throw new IllegalArgumentException("service must not be null");
-                }
-                if (TextUtils.isEmpty(name)) {
-                    throw new IllegalArgumentException("name must not be null or empty");
-                }
-                mId = id;
-                mService = service;
-                mName = name;
-            }
-
-            /**
-             * Sets the destination's description for display to the user, or null if none.
-             */
-            public @NonNull Builder setDescription(@Nullable CharSequence description) {
-                mDescription = description;
-                return this;
-            }
-
-            /**
-             * Sets an icon resource from this package used to identify the destination,
-             * or -1 if none.
-             */
-            public @NonNull Builder setIconResourceId(@DrawableRes int resid) {
-                mIconResourceId = resid;
-                return this;
-            }
-
-            /**
-             * Gets optional extra information about the destination, or null if none.
-             */
-            public @NonNull Builder setExtras(@Nullable Bundle extras) {
-                mExtras = extras;
-                return this;
-            }
-
-            /**
-             * Builds the {@link DestinationInfo} object.
-             */
-            public @NonNull DestinationInfo build() {
-                return new DestinationInfo(mId, mService, mName, mDescription,
-                        mIconResourceId, mExtras);
-            }
-        }
-    }
-
-    /**
-     * Describes metadata about a {@link MediaRouteService} which is providing
-     * access to certain kinds of destinations.
-     */
-    public static final class ServiceMetadata {
-        private final ServiceInfo mService;
-        private CharSequence mLabel;
-        private Drawable mIcon;
-
-        ServiceMetadata(Service service) throws NameNotFoundException {
-            mService = service.getPackageManager().getServiceInfo(
-                    new ComponentName(service, service.getClass()),
-                    PackageManager.GET_META_DATA);
-        }
-
-        ServiceMetadata(ServiceInfo service) {
-            mService = service;
-        }
-
-        /**
-         * Gets the service's component information including it name, label and icon.
-         */
-        public @NonNull ServiceInfo getService() {
-            return mService;
-        }
-
-        /**
-         * Gets the service's component name.
-         */
-        public @NonNull ComponentName getComponentName() {
-            return new ComponentName(mService.packageName, mService.name);
-        }
-
-        /**
-         * Gets the service's package name.
-         */
-        public @NonNull String getPackageName() {
-            return mService.packageName;
-        }
-
-        /**
-         * Gets the service's name for display to the user, or null if none.
-         */
-        public @NonNull CharSequence getLabel(@NonNull PackageManager pm) {
-            if (mLabel == null) {
-                mLabel = mService.loadLabel(pm);
-            }
-            return mLabel;
-        }
-
-        /**
-         * Gets the icon drawable, or null if none.
-         */
-        public @Nullable Drawable getIcon(@NonNull PackageManager pm) {
-            if (mIcon == null) {
-                mIcon = mService.loadIcon(pm);
-            }
-            return mIcon;
-        }
-
-        // TODO: add service metadata
-
-        Drawable getDrawable(PackageManager pm, int resid) {
-            return pm.getDrawable(getPackageName(), resid, mService.applicationInfo);
-        }
-
-        @Override
-        public @NonNull String toString() {
-            return "ServiceInfo{ service=" + getComponentName().toShortString() + " }";
-        }
-    }
-
-    /**
-     * Describes a request to discover routes on behalf of an application.
-     */
-    public static final class DiscoveryRequest {
-        private final ArrayList<MediaRouteSelector> mSelectors =
-                new ArrayList<MediaRouteSelector>();
-        private int mFlags;
-
-        DiscoveryRequest(@NonNull List<MediaRouteSelector> selectors) {
-            setSelectors(selectors);
-        }
-
-        /**
-         * Sets the list of media route selectors to consider during discovery.
-         */
-        public void setSelectors(@NonNull List<MediaRouteSelector> selectors) {
-            if (selectors == null) {
-                throw new IllegalArgumentException("selectors");
-            }
-            mSelectors.clear();
-            mSelectors.addAll(selectors);
-        }
-
-        /**
-         * Gets the list of media route selectors to consider during discovery.
-         */
-        public @NonNull List<MediaRouteSelector> getSelectors() {
-            return mSelectors;
-        }
-
-        /**
-         * Gets discovery flags, such as {@link MediaRouter#DISCOVERY_FLAG_BACKGROUND}.
-         */
-        public @DiscoveryFlags int getFlags() {
-            return mFlags;
-        }
-
-        /**
-         * Sets discovery flags, such as {@link MediaRouter#DISCOVERY_FLAG_BACKGROUND}.
-         */
-        public void setFlags(@DiscoveryFlags int flags) {
-            mFlags = flags;
-        }
-
-        @Override
-        public @NonNull String toString() {
-            return "DiscoveryRequest{ selectors=" + mSelectors
-                    + ", flags=0x" + Integer.toHexString(mFlags)
-                    + " }";
-        }
-    }
-
-    /**
-     * Describes a request to connect to a previously discovered route on
-     * behalf of an application.
-     */
-    public static final class ConnectionRequest {
-        private RouteInfo mRoute;
-        private int mFlags;
-        private Bundle mExtras;
-
-        ConnectionRequest(@NonNull RouteInfo route) {
-            setRoute(route);
-        }
-
-        /**
-         * Gets the route to which to connect.
-         */
-        public @NonNull RouteInfo getRoute() {
-            return mRoute;
-        }
-
-        /**
-         * Sets the route to which to connect.
-         */
-        public void setRoute(@NonNull RouteInfo route) {
-            if (route == null) {
-                throw new IllegalArgumentException("route must not be null");
-            }
-            mRoute = route;
-        }
-
-        /**
-         * Gets connection flags, such as {@link MediaRouter#CONNECTION_FLAG_BARGE}.
-         */
-        public @ConnectionFlags int getFlags() {
-            return mFlags;
-        }
-
-        /**
-         * Sets connection flags, such as {@link MediaRouter#CONNECTION_FLAG_BARGE}.
-         */
-        public void setFlags(@ConnectionFlags int flags) {
-            mFlags = flags;
-        }
-
-        /**
-         * Gets optional extras supplied by the application as part of the call to
-         * connect, or null if none.  The media route service may use this
-         * information to configure the route during connection.
-         */
-        public @Nullable Bundle getExtras() {
-            return mExtras;
-        }
-
-        /**
-         * Sets optional extras supplied by the application as part of the call to
-         * connect, or null if none.  The media route service may use this
-         * information to configure the route during connection.
-         */
-        public void setExtras(@Nullable Bundle extras) {
-            mExtras = extras;
-        }
-
-        @Override
-        public @NonNull String toString() {
-            return "ConnectionRequest{ route=" + mRoute
-                    + ", flags=0x" + Integer.toHexString(mFlags)
-                    + ", extras=" + mExtras + " }";
-        }
-    }
-
-    /**
-     * Callback interface to specify policy for route discovery, filtering,
-     * and connection establishment as well as observe media router state changes.
-     */
-    public static abstract class RoutingCallback extends StateCallback {
-        /**
-         * Called to prepare a discovery request object to specify the desired
-         * media route selectors when the media router has been asked to start discovery.
-         * <p>
-         * By default, the discovery request contains all of the selectors which
-         * have been added to the media router.  Subclasses may override the list of
-         * selectors by modifying the discovery request object before returning.
-         * </p>
-         *
-         * @param request The discovery request object which may be modified by
-         * this method to alter how discovery will be performed.
-         * @param selectors The immutable list of media route selectors which were
-         * added to the media router.
-         * @return True to allow discovery to proceed or false to abort it.
-         * By default, this methods returns true.
-         */
-        public boolean onPrepareDiscoveryRequest(@NonNull DiscoveryRequest request,
-                @NonNull List<MediaRouteSelector> selectors) {
-            return true;
-        }
-
-        /**
-         * Called to prepare a connection request object to specify the desired
-         * route and connection parameters when the media router has been asked to
-         * connect to a particular destination.
-         * <p>
-         * By default, the connection request specifies the first available route
-         * to the destination.  Subclasses may override the route and destination
-         * or set additional connection parameters by modifying the connection request
-         * object before returning.
-         * </p>
-         *
-         * @param request The connection request object which may be modified by
-         * this method to alter how the connection will be established.
-         * @param destination The destination to which the media router was asked
-         * to connect.
-         * @param routes The list of routes that belong to that destination sorted
-         * in the same order as their matching media route selectors which were
-         * used during discovery.
-         * @return True to allow the connection to proceed or false to abort it.
-         * By default, this methods returns true.
-         */
-        public boolean onPrepareConnectionRequest(
-                @NonNull ConnectionRequest request,
-                @NonNull DestinationInfo destination, @NonNull List<RouteInfo> routes) {
-            return true;
-        }
-    }
-
-    /**
-     * Callback class to receive events from a {@link MediaRouter.Delegate}.
-     */
-    public static abstract class StateCallback {
-        /**
-         * Called when the media router has been released.
-         */
-        public void onReleased() { }
-
-        /**
-         * Called when the discovery state has changed.
-         *
-         * @param state The new discovery state: one of
-         * {@link #DISCOVERY_STATE_STOPPED} or {@link #DISCOVERY_STATE_STARTED}.
-         */
-        public void onDiscoveryStateChanged(@DiscoveryState int state) { }
-
-        /**
-         * Called when the connection state has changed.
-         *
-         * @param state The new connection state: one of
-         * {@link #CONNECTION_STATE_DISCONNECTED}, {@link #CONNECTION_STATE_CONNECTING}
-         * or {@link #CONNECTION_STATE_CONNECTED}.
-         */
-        public void onConnectionStateChanged(@ConnectionState int state) { }
-
-        /**
-         * Called when the selected destination has changed.
-         *
-         * @param destination The new selected destination, or null if none.
-         */
-        public void onSelectedDestinationChanged(@Nullable DestinationInfo destination) { }
-
-        /**
-         * Called when route discovery has started.
-         */
-        public void onDiscoveryStarted() { }
-
-        /**
-         * Called when route discovery has stopped normally.
-         * <p>
-         * Abnormal termination is reported via {@link #onDiscoveryFailed}.
-         * </p>
-         */
-        public void onDiscoveryStopped() { }
-
-        /**
-         * Called when discovery has failed in a non-recoverable manner.
-         *
-         * @param error The error code: one of
-         * {@link MediaRouter#DISCOVERY_ERROR_UNKNOWN},
-         * {@link MediaRouter#DISCOVERY_ERROR_ABORTED},
-         * or {@link MediaRouter#DISCOVERY_ERROR_NO_CONNECTIVITY}.
-         * @param message The localized error message, or null if none.  This message
-         * may be shown to the user.
-         * @param extras Additional information about the error which a client
-         * may use, or null if none.
-         */
-        public void onDiscoveryFailed(@DiscoveryError int error, @Nullable CharSequence message,
-                @Nullable Bundle extras) { }
-
-        /**
-         * Called when a new destination is found or has changed during discovery.
-         * <p>
-         * Certain destinations may be omitted because they have been filtered
-         * out by the media router's routing callback.
-         * </p>
-         *
-         * @param destination The destination that was found.
-         */
-        public void onDestinationFound(@NonNull DestinationInfo destination) { }
-
-        /**
-         * Called when a destination is no longer reachable or is no longer
-         * offering any routes that satisfy the discovery request.
-         *
-         * @param destination The destination that went away.
-         */
-        public void onDestinationLost(@NonNull DestinationInfo destination) { }
-
-        /**
-         * Called when a connection attempt begins.
-         */
-        public void onConnecting() { }
-
-        /**
-         * Called when the connection succeeds.
-         */
-        public void onConnected() { }
-
-        /**
-         * Called when the connection is terminated normally.
-         * <p>
-         * Abnormal termination is reported via {@link #onConnectionFailed}.
-         * </p>
-         */
-        public void onDisconnected() { }
-
-        /**
-         * Called when a connection attempt or connection in
-         * progress has failed in a non-recoverable manner.
-         *
-         * @param error The error code: one of
-         * {@link MediaRouter#CONNECTION_ERROR_ABORTED},
-         * {@link MediaRouter#CONNECTION_ERROR_UNAUTHORIZED},
-         * {@link MediaRouter#CONNECTION_ERROR_UNREACHABLE},
-         * {@link MediaRouter#CONNECTION_ERROR_BUSY},
-         * {@link MediaRouter#CONNECTION_ERROR_TIMEOUT},
-         * {@link MediaRouter#CONNECTION_ERROR_BROKEN},
-         * or {@link MediaRouter#CONNECTION_ERROR_BARGED}.
-         * @param message The localized error message, or null if none.  This message
-         * may be shown to the user.
-         * @param extras Additional information about the error which a client
-         * may use, or null if none.
-         */
-        public void onConnectionFailed(@ConnectionError int error,
-                @Nullable CharSequence message, @Nullable Bundle extras) { }
-    }
-}
diff --git a/media/java/android/media/routing/ParcelableConnectionInfo.aidl b/media/java/android/media/routing/ParcelableConnectionInfo.aidl
deleted file mode 100644
index 4a9ec94..0000000
--- a/media/java/android/media/routing/ParcelableConnectionInfo.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.media.routing;
-
-parcelable ParcelableConnectionInfo;
diff --git a/media/java/android/media/routing/ParcelableConnectionInfo.java b/media/java/android/media/routing/ParcelableConnectionInfo.java
deleted file mode 100644
index 45cfe9f..0000000
--- a/media/java/android/media/routing/ParcelableConnectionInfo.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.routing;
-
-import android.media.AudioAttributes;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Internal parcelable representation of a media route connection.
- */
-class ParcelableConnectionInfo implements Parcelable {
-    public AudioAttributes audioAttributes;
-    public int presentationDisplayId = -1;
-    // todo: volume
-    public IBinder[] protocolBinders;
-    public Bundle extras;
-
-    public static final Parcelable.Creator<ParcelableConnectionInfo> CREATOR =
-            new Parcelable.Creator<ParcelableConnectionInfo>() {
-        @Override
-        public ParcelableConnectionInfo createFromParcel(Parcel source) {
-            ParcelableConnectionInfo info = new ParcelableConnectionInfo();
-            if (source.readInt() != 0) {
-                info.audioAttributes = AudioAttributes.CREATOR.createFromParcel(source);
-            }
-            info.presentationDisplayId = source.readInt();
-            info.protocolBinders = source.createBinderArray();
-            info.extras = source.readBundle();
-            return info;
-        }
-
-        @Override
-        public ParcelableConnectionInfo[] newArray(int size) {
-            return new ParcelableConnectionInfo[size];
-        }
-    };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        if (audioAttributes != null) {
-            dest.writeInt(1);
-            audioAttributes.writeToParcel(dest, flags);
-        } else {
-            dest.writeInt(0);
-        }
-        dest.writeInt(presentationDisplayId);
-        dest.writeBinderArray(protocolBinders);
-        dest.writeBundle(extras);
-    }
-}
diff --git a/media/java/android/media/routing/ParcelableDestinationInfo.aidl b/media/java/android/media/routing/ParcelableDestinationInfo.aidl
deleted file mode 100644
index bf1c198..0000000
--- a/media/java/android/media/routing/ParcelableDestinationInfo.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.media.routing;
-
-parcelable ParcelableDestinationInfo;
diff --git a/media/java/android/media/routing/ParcelableDestinationInfo.java b/media/java/android/media/routing/ParcelableDestinationInfo.java
deleted file mode 100644
index eca5eec..0000000
--- a/media/java/android/media/routing/ParcelableDestinationInfo.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.routing;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-/**
- * Internal parcelable representation of a media destination.
- */
-class ParcelableDestinationInfo implements Parcelable {
-    public String id;
-    public CharSequence name;
-    public CharSequence description;
-    public int iconResourceId;
-    public Bundle extras;
-
-    public static final Parcelable.Creator<ParcelableDestinationInfo> CREATOR =
-            new Parcelable.Creator<ParcelableDestinationInfo>() {
-        @Override
-        public ParcelableDestinationInfo createFromParcel(Parcel source) {
-            ParcelableDestinationInfo info = new ParcelableDestinationInfo();
-            info.id = source.readString();
-            info.name = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-            info.description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-            info.iconResourceId = source.readInt();
-            info.extras = source.readBundle();
-            return info;
-        }
-
-        @Override
-        public ParcelableDestinationInfo[] newArray(int size) {
-            return new ParcelableDestinationInfo[size];
-        }
-    };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(id);
-        TextUtils.writeToParcel(name, dest, flags);
-        TextUtils.writeToParcel(description, dest, flags);
-        dest.writeInt(iconResourceId);
-        dest.writeBundle(extras);
-    }
-}
diff --git a/media/java/android/media/routing/ParcelableRouteInfo.aidl b/media/java/android/media/routing/ParcelableRouteInfo.aidl
deleted file mode 100644
index 126afaa..0000000
--- a/media/java/android/media/routing/ParcelableRouteInfo.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.media.routing;
-
-parcelable ParcelableRouteInfo;
diff --git a/media/java/android/media/routing/ParcelableRouteInfo.java b/media/java/android/media/routing/ParcelableRouteInfo.java
deleted file mode 100644
index fb1a547..0000000
--- a/media/java/android/media/routing/ParcelableRouteInfo.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.routing;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Internal parcelable representation of a media route.
- */
-class ParcelableRouteInfo implements Parcelable {
-    public String id;
-    public int selectorIndex; // index of selector within list used for discovery
-    public int features;
-    public String[] protocols;
-    public Bundle extras;
-
-    public static final Parcelable.Creator<ParcelableRouteInfo> CREATOR =
-            new Parcelable.Creator<ParcelableRouteInfo>() {
-        @Override
-        public ParcelableRouteInfo createFromParcel(Parcel source) {
-            ParcelableRouteInfo info = new ParcelableRouteInfo();
-            info.id = source.readString();
-            info.selectorIndex = source.readInt();
-            info.features = source.readInt();
-            info.protocols = source.createStringArray();
-            info.extras = source.readBundle();
-            return info;
-        }
-
-        @Override
-        public ParcelableRouteInfo[] newArray(int size) {
-            return new ParcelableRouteInfo[size];
-        }
-    };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(id);
-        dest.writeInt(selectorIndex);
-        dest.writeInt(features);
-        dest.writeStringArray(protocols);
-        dest.writeBundle(extras);
-    }
-}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index af3b72e..bd0019f 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -19,7 +19,6 @@
 import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.MediaMetadata;
-import android.media.routing.IMediaRouter;
 import android.media.session.ISessionController;
 import android.media.session.PlaybackState;
 import android.media.session.MediaSession;
@@ -35,7 +34,6 @@
     ISessionController getController();
     void setFlags(int flags);
     void setActive(boolean active);
-    void setMediaRouter(in IMediaRouter router);
     void setMediaButtonReceiver(in PendingIntent mbr);
     void setLaunchPendingIntent(in PendingIntent pi);
     void destroy();
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 5764bd1..6b80477 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -20,8 +20,6 @@
 import android.content.pm.ParceledListSlice;
 import android.media.MediaMetadata;
 import android.media.Rating;
-import android.media.routing.IMediaRouterDelegate;
-import android.media.routing.IMediaRouterStateCallback;
 import android.media.session.ISessionControllerCallback;
 import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
@@ -51,8 +49,6 @@
     void adjustVolume(int direction, int flags, String packageName);
     void setVolumeTo(int value, int flags, String packageName);
 
-    IMediaRouterDelegate createMediaRouterDelegate(IMediaRouterStateCallback callback);
-
     // These commands are for the TransportControls
     void play();
     void playUri(in Uri uri, in Bundle extras);
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 63c85f8..2ec0293 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -26,7 +26,6 @@
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
-import android.media.routing.MediaRouter;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -119,17 +118,6 @@
     }
 
     /**
-     * Creates a media router delegate through which the destination of the media
-     * router may be observed and controlled.
-     *
-     * @return The media router delegate, or null if the media session does
-     * not support media routing.
-     */
-    public @Nullable MediaRouter.Delegate createMediaRouterDelegate() {
-        return new MediaRouter.Delegate();
-    }
-
-    /**
      * Send the specified media button event to the session. Only media keys can
      * be sent by this method, other keys will be ignored.
      *
@@ -185,7 +173,7 @@
      *
      * @return The current play queue or null.
      */
-    public @Nullable List<MediaSession.Track> getQueue() {
+    public @Nullable List<MediaSession.Item> getQueue() {
         try {
             ParceledListSlice queue = mSessionBinder.getQueue();
             if (queue != null) {
@@ -259,18 +247,18 @@
     }
 
     /**
-     * Get the current volume info for this session.
+     * Get the current audio info for this session.
      *
-     * @return The current volume info or null.
+     * @return The current audio info or null.
      */
-    public @Nullable VolumeInfo getVolumeInfo() {
+    public @Nullable AudioInfo getAudioInfo() {
         try {
             ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes();
-            return new VolumeInfo(result.volumeType, result.audioAttrs, result.controlType,
+            return new AudioInfo(result.volumeType, result.audioAttrs, result.controlType,
                     result.maxVolume, result.currentVolume);
 
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getVolumeInfo.", e);
+            Log.wtf(TAG, "Error calling getAudioInfo.", e);
         }
         return null;
     }
@@ -305,7 +293,7 @@
      * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
      * {@link AudioManager} may be used to affect the handling.
      *
-     * @see #getVolumeInfo()
+     * @see #getAudioInfo()
      * @param value The value to set it to, between 0 and the reported max.
      * @param flags Any flags to pass with the command.
      */
@@ -326,7 +314,7 @@
      * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
      * {@link AudioManager} may be used to affect the handling.
      *
-     * @see #getVolumeInfo()
+     * @see #getAudioInfo()
      * @param direction The direction to adjust the volume in.
      * @param flags Any flags to pass with the command.
      */
@@ -544,13 +532,14 @@
         }
 
         /**
-         * Override to handle changes to tracks in the queue.
+         * Override to handle changes to items in the queue.
          *
-         * @param queue A list of tracks in the current play queue. It should include the currently
-         *              playing track as well as previous and upcoming tracks if applicable.
-         * @see MediaSession.Track
+         * @param queue A list of items in the current play queue. It should
+         *            include the currently playing item as well as previous and
+         *            upcoming items if applicable.
+         * @see MediaSession.Item
          */
-        public void onQueueChanged(@Nullable List<MediaSession.Track> queue) {
+        public void onQueueChanged(@Nullable List<MediaSession.Item> queue) {
         }
 
         /**
@@ -572,11 +561,11 @@
         }
 
         /**
-         * Override to handle changes to the volume info.
+         * Override to handle changes to the audio info.
          *
-         * @param info The current volume info for this session.
+         * @param info The current audio info for this session.
          */
-        public void onVolumeInfoChanged(VolumeInfo info) {
+        public void onAudioInfoChanged(AudioInfo info) {
         }
     }
 
@@ -638,14 +627,14 @@
         }
 
         /**
-         * Play a track with a specific id in the play queue.
-         * If you specify an id that is not in the play queue, the behavior is undefined.
+         * Play an item with a specific id in the play queue. If you specify an
+         * id that is not in the play queue, the behavior is undefined.
          */
-        public void skipToTrack(long id) {
+        public void skipToItem(long id) {
             try {
                 mSessionBinder.skipToTrack(id);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling skipToTrack(" + id + ").", e);
+                Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
             }
         }
 
@@ -784,9 +773,9 @@
     }
 
     /**
-     * Holds information about the way volume is handled for this session.
+     * Holds information about the way audio is handled for this session.
      */
-    public static final class VolumeInfo {
+    public static final class AudioInfo {
         private final int mVolumeType;
         private final int mVolumeControl;
         private final int mMaxVolume;
@@ -796,7 +785,7 @@
         /**
          * @hide
          */
-        public VolumeInfo(int type, AudioAttributes attrs, int control, int max, int current) {
+        public AudioInfo(int type, AudioAttributes attrs, int control, int max, int current) {
             mVolumeType = type;
             mAudioAttrs = attrs;
             mVolumeControl = control;
@@ -904,7 +893,7 @@
 
         @Override
         public void onQueueChanged(ParceledListSlice parceledQueue) {
-            List<MediaSession.Track> queue = parceledQueue.getList();
+            List<MediaSession.Item> queue = parceledQueue.getList();
             MediaController controller = mController.get();
             if (controller != null) {
                 controller.postMessage(MSG_UPDATE_QUEUE, queue, null);
@@ -931,7 +920,7 @@
         public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) {
             MediaController controller = mController.get();
             if (controller != null) {
-                VolumeInfo info = new VolumeInfo(pvi.volumeType, pvi.audioAttrs, pvi.controlType,
+                AudioInfo info = new AudioInfo(pvi.volumeType, pvi.audioAttrs, pvi.controlType,
                         pvi.maxVolume, pvi.currentVolume);
                 controller.postMessage(MSG_UPDATE_VOLUME, info, null);
             }
@@ -960,7 +949,7 @@
                     mCallback.onMetadataChanged((MediaMetadata) msg.obj);
                     break;
                 case MSG_UPDATE_QUEUE:
-                    mCallback.onQueueChanged((List<MediaSession.Track>) msg.obj);
+                    mCallback.onQueueChanged((List<MediaSession.Item>) msg.obj);
                     break;
                 case MSG_UPDATE_QUEUE_TITLE:
                     mCallback.onQueueTitleChanged((CharSequence) msg.obj);
@@ -969,7 +958,7 @@
                     mCallback.onExtrasChanged((Bundle) msg.obj);
                     break;
                 case MSG_UPDATE_VOLUME:
-                    mCallback.onVolumeInfoChanged((VolumeInfo) msg.obj);
+                    mCallback.onAudioInfoChanged((AudioInfo) msg.obj);
                     break;
                 case MSG_DESTROYED:
                     mCallback.onSessionDestroyed();
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index cf73c2a..de725fc 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -28,7 +28,6 @@
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
-import android.media.routing.MediaRouter;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -225,23 +224,6 @@
     }
 
     /**
-     * Associates a {@link MediaRouter} with this session to control the destination
-     * of media content.
-     * <p>
-     * A media router may only be associated with at most one session at a time.
-     * </p>
-     *
-     * @param router The media router, or null to remove the current association.
-     */
-    public void setMediaRouter(@Nullable MediaRouter router) {
-        try {
-            mBinder.setMediaRouter(router != null ? router.getBinder() : null);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
-        }
-    }
-
-    /**
      * Set a pending intent for your media button receiver to allow restarting
      * playback after the session has been stopped. If your app is started in
      * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
@@ -435,18 +417,19 @@
     }
 
     /**
-     * Update the list of tracks in the play queue. It is an ordered list and should contain the
-     * current track, and previous or upcoming tracks if they exist.
-     * Specify null if there is no current play queue.
+     * Update the list of items in the play queue. It is an ordered list and
+     * should contain the current item, and previous or upcoming items if they
+     * exist. Specify null if there is no current play queue.
      * <p>
-     * The queue should be of reasonable size. If the play queue is unbounded within your
-     * app, it is better to send a reasonable amount in a sliding window instead.
+     * The queue should be of reasonable size. If the play queue is unbounded
+     * within your app, it is better to send a reasonable amount in a sliding
+     * window instead.
      *
-     * @param queue A list of tracks in the play queue.
+     * @param queue A list of items in the play queue.
      */
-    public void setQueue(@Nullable List<Track> queue) {
+    public void setQueue(@Nullable List<Item> queue) {
         try {
-            mBinder.setQueue(new ParceledListSlice<Track>(queue));
+            mBinder.setQueue(new ParceledListSlice<Item>(queue));
         } catch (RemoteException e) {
             Log.wtf("Dead object in setQueue.", e);
         }
@@ -512,8 +495,8 @@
         postToCallback(CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
     }
 
-    private void dispatchSkipToTrack(long id) {
-        postToCallback(CallbackMessageHandler.MSG_SKIP_TO_TRACK, id);
+    private void dispatchSkipToItem(long id) {
+        postToCallback(CallbackMessageHandler.MSG_SKIP_TO_ITEM, id);
     }
 
     private void dispatchPause() {
@@ -782,9 +765,10 @@
         }
 
         /**
-         * Override to handle requests to play a track with a given id from the play queue.
+         * Override to handle requests to play an item with a given id from the
+         * play queue.
          */
-        public void onSkipToTrack(long id) {
+        public void onSkipToItem(long id) {
         }
 
         /**
@@ -916,7 +900,7 @@
         public void onSkipToTrack(long id) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchSkipToTrack(id);
+                session.dispatchSkipToItem(id);
             }
         }
 
@@ -1015,12 +999,12 @@
     }
 
     /**
-     * A single track that is part of the play queue. It contains information necessary to display
-     * a single track in the queue.
+     * A single item that is part of the play queue. It contains information
+     * necessary to display a single item in the queue.
      */
-    public static final class Track implements Parcelable {
+    public static final class Item implements Parcelable {
         /**
-         * This id is reserved. No tracks can be explicitly asigned this id.
+         * This id is reserved. No items can be explicitly asigned this id.
          */
         public static final int UNKNOWN_ID = -1;
 
@@ -1030,22 +1014,23 @@
         private final Bundle mExtras;
 
         /**
-         * Create a new {@link MediaSession.Track}.
+         * Create a new {@link MediaSession.Item}.
          *
-         * @param metadata The metadata for this track.
-         * @param id An identifier for this track. It must be unique within the play queue.
-         * @param uri The uri for this track.
-         * @param extras A bundle of extras that can be used to add extra information about the
-         *               track.
+         * @param metadata The metadata for this item.
+         * @param id An identifier for this item. It must be unique within the
+         *            play queue.
+         * @param uri The uri for this item.
+         * @param extras A bundle of extras that can be used to add extra
+         *            information about this item.
          */
-        private Track(MediaMetadata metadata, long id, Uri uri, Bundle extras) {
+        private Item(MediaMetadata metadata, long id, Uri uri, Bundle extras) {
             mMetadata = metadata;
             mId = id;
             mUri = uri;
             mExtras = extras;
         }
 
-        private Track(Parcel in) {
+        private Item(Parcel in) {
             mMetadata = MediaMetadata.CREATOR.createFromParcel(in);
             mId = in.readLong();
             mUri = Uri.CREATOR.createFromParcel(in);
@@ -1053,35 +1038,35 @@
         }
 
         /**
-         * Get the metadata for this track.
+         * Get the metadata for this item.
          */
         public MediaMetadata getMetadata() {
             return mMetadata;
         }
 
         /**
-         * Get the id for this track.
+         * Get the id for this item.
          */
         public long getId() {
             return mId;
         }
 
         /**
-         * Get the Uri for this track.
+         * Get the Uri for this item.
          */
         public Uri getUri() {
             return mUri;
         }
 
         /**
-         * Get the extras for this track.
+         * Get the extras for this item.
          */
         public Bundle getExtras() {
             return mExtras;
         }
 
         /**
-         * Builder for {@link MediaSession.Track} objects.
+         * Builder for {@link MediaSession.Item} objects.
          */
         public static final class Builder {
             private final MediaMetadata mMetadata;
@@ -1096,15 +1081,15 @@
             public Builder(MediaMetadata metadata, long id, Uri uri) {
                 if (metadata == null) {
                     throw new IllegalArgumentException(
-                            "You must specify a non-null MediaMetadata to build a Track.");
+                            "You must specify a non-null MediaMetadata to build an Item.");
                 }
                 if (uri == null) {
                     throw new IllegalArgumentException(
-                            "You must specify a non-null Uri to build a Track.");
+                            "You must specify a non-null Uri to build an Item.");
                 }
                 if (id == UNKNOWN_ID) {
                     throw new IllegalArgumentException(
-                            "You must specify an id other than UNKNOWN_ID to build a Track.");
+                            "You must specify an id other than UNKNOWN_ID to build an Item.");
                 }
                 mMetadata = metadata;
                 mId = id;
@@ -1112,18 +1097,18 @@
             }
 
             /**
-             * Set optional extras for the track.
+             * Set optional extras for the item.
              */
-            public MediaSession.Track.Builder setExtras(Bundle extras) {
+            public MediaSession.Item.Builder setExtras(Bundle extras) {
                 mExtras = extras;
                 return this;
             }
 
             /**
-             * Create the {@link Track}.
+             * Create the {@link Item}.
              */
-            public MediaSession.Track build() {
-                return new MediaSession.Track(mMetadata, mId, mUri, mExtras);
+            public MediaSession.Item build() {
+                return new MediaSession.Item(mMetadata, mId, mUri, mExtras);
             }
         }
 
@@ -1140,23 +1125,23 @@
             return 0;
         }
 
-        public static final Creator<MediaSession.Track> CREATOR
-                = new Creator<MediaSession.Track>() {
+        public static final Creator<MediaSession.Item> CREATOR
+                = new Creator<MediaSession.Item>() {
 
             @Override
-            public MediaSession.Track createFromParcel(Parcel p) {
-                return new MediaSession.Track(p);
+            public MediaSession.Item createFromParcel(Parcel p) {
+                return new MediaSession.Item(p);
             }
 
             @Override
-            public MediaSession.Track[] newArray(int size) {
-                return new MediaSession.Track[size];
+            public MediaSession.Item[] newArray(int size) {
+                return new MediaSession.Item[size];
             }
         };
 
         @Override
         public String toString() {
-            return "MediaSession.Track {" +
+            return "MediaSession.Item {" +
                     "Metadata=" + mMetadata +
                     ", Id=" + mId +
                     ", Uri=" + mUri +
@@ -1182,7 +1167,7 @@
         private static final int MSG_PLAY = 1;
         private static final int MSG_PLAY_URI = 2;
         private static final int MSG_PLAY_SEARCH = 3;
-        private static final int MSG_SKIP_TO_TRACK = 4;
+        private static final int MSG_SKIP_TO_ITEM = 4;
         private static final int MSG_PAUSE = 5;
         private static final int MSG_STOP = 6;
         private static final int MSG_NEXT = 7;
@@ -1232,8 +1217,8 @@
                 case MSG_PLAY_SEARCH:
                     mCallback.onPlayFromSearch((String) msg.obj, msg.getData());
                     break;
-                case MSG_SKIP_TO_TRACK:
-                    mCallback.onSkipToTrack((Long) msg.obj);
+                case MSG_SKIP_TO_ITEM:
+                    mCallback.onSkipToItem((Long) msg.obj);
                 case MSG_PAUSE:
                     mCallback.onPause();
                     break;
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index c2fb5a3..8a1e076 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -30,6 +30,7 @@
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.view.KeyEvent;
 
@@ -50,6 +51,9 @@
 public final class MediaSessionManager {
     private static final String TAG = "SessionManager";
 
+    private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners
+            = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>();
+    private final Object mLock = new Object();
     private final ISessionManager mService;
 
     private Context mContext;
@@ -141,10 +145,11 @@
      * @param notificationListener The enabled notification listener component.
      *            May be null.
      */
-    public void addActiveSessionsListener(@NonNull SessionListener sessionListener,
+    public void addOnActiveSessionsChangedListener(
+            @NonNull OnActiveSessionsChangedListener sessionListener,
             @Nullable ComponentName notificationListener) {
-        addActiveSessionsListener(sessionListener, notificationListener, UserHandle.myUserId(),
-                null);
+        addOnActiveSessionsChangedListener(sessionListener, notificationListener,
+                UserHandle.myUserId(), null);
     }
 
     /**
@@ -163,7 +168,8 @@
      * @param handler The handler to post updates on.
      * @hide
      */
-    public void addActiveSessionsListener(@NonNull SessionListener sessionListener,
+    public void addOnActiveSessionsChangedListener(
+            @NonNull OnActiveSessionsChangedListener sessionListener,
             @Nullable ComponentName notificationListener, int userId, @Nullable Handler handler) {
         if (sessionListener == null) {
             throw new IllegalArgumentException("listener may not be null");
@@ -171,11 +177,18 @@
         if (handler == null) {
             handler = new Handler();
         }
-        sessionListener.setHandler(handler);
-        try {
-            mService.addSessionsListener(sessionListener.mStub, notificationListener, userId);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error in addActiveSessionsListener.", e);
+        synchronized (mLock) {
+            if (mListeners.get(sessionListener) != null) {
+                Log.w(TAG, "Attempted to add session listener twice, ignoring.");
+                return;
+            }
+            SessionsChangedWrapper wrapper = new SessionsChangedWrapper(sessionListener, handler);
+            try {
+                mService.addSessionsListener(wrapper.mStub, notificationListener, userId);
+                mListeners.put(sessionListener, wrapper);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in addOnActiveSessionsChangedListener.", e);
+            }
         }
     }
 
@@ -184,14 +197,20 @@
      *
      * @param listener The listener to remove.
      */
-    public void removeActiveSessionsListener(@NonNull SessionListener listener) {
+    public void removeOnActiveSessionsChangedListener(
+            @NonNull OnActiveSessionsChangedListener listener) {
         if (listener == null) {
             throw new IllegalArgumentException("listener may not be null");
         }
-        try {
-            mService.removeSessionsListener(listener.mStub);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error in removeActiveSessionsListener.", e);
+        synchronized (mLock) {
+            SessionsChangedWrapper wrapper = mListeners.remove(listener);
+            if (wrapper != null) {
+                try {
+                    mService.removeSessionsListener(wrapper.mStub);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error in removeOnActiveSessionsChangedListener.", e);
+                }
+            }
         }
     }
 
@@ -257,28 +276,18 @@
 
     /**
      * Listens for changes to the list of active sessions. This can be added
-     * using {@link #addActiveSessionsListener}.
+     * using {@link #addOnActiveSessionsChangedListener}.
      */
-    public static abstract class SessionListener {
-        private final Context mContext;
-        private Handler mHandler;
+    public interface OnActiveSessionsChangedListener {
+        public void onActiveSessionsChanged(@Nullable List<MediaController> controllers);
+    }
 
-        public SessionListener(Context context) {
-            mContext = context;
-        }
-        /**
-         * Called when the list of active sessions has changed. This can be due
-         * to a session being added or removed or the order of sessions
-         * changing. The controllers will be provided in priority order with the
-         * most important controller at index 0.
-         *
-         * @param controllers The updated list of controllers for the user that
-         *            changed.
-         */
-        public abstract void onActiveSessionsChanged(
-                @Nullable List<MediaController> controllers);
+    private final class SessionsChangedWrapper {
+        private final OnActiveSessionsChangedListener mListener;
+        private final Handler mHandler;
 
-        private final void setHandler(Handler handler) {
+        public SessionsChangedWrapper(OnActiveSessionsChangedListener listener, Handler handler) {
+            mListener = listener;
             mHandler = handler;
         }
 
@@ -295,7 +304,7 @@
                             for (int i = 0; i < size; i++) {
                                 controllers.add(new MediaController(mContext, tokens.get(i)));
                             }
-                            SessionListener.this.onActiveSessionsChanged(controllers);
+                            mListener.onActiveSessionsChanged(controllers);
                         }
                     });
                 }
diff --git a/media/java/android/media/session/ParcelableVolumeInfo.java b/media/java/android/media/session/ParcelableVolumeInfo.java
index e71b539..96a45d9b 100644
--- a/media/java/android/media/session/ParcelableVolumeInfo.java
+++ b/media/java/android/media/session/ParcelableVolumeInfo.java
@@ -21,7 +21,7 @@
 
 /**
  * Convenience class for passing information about the audio configuration of a
- * session. The public implementation is {@link MediaController.VolumeInfo}.
+ * session. The public implementation is {@link MediaController.AudioInfo}.
  *
  * @hide
  */
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 2ad8eae..566e218 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -120,11 +120,11 @@
     public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11;
 
     /**
-     * Indicates this performer supports the skip to track command.
+     * Indicates this performer supports the skip to item command.
      *
      * @see Builder#setActions(long)
      */
-    public static final long ACTION_SKIP_TO_TRACK = 1 << 12;
+    public static final long ACTION_SKIP_TO_ITEM = 1 << 12;
 
     /**
      * This is the default playback state and indicates that no media has been
@@ -223,11 +223,11 @@
     private List<PlaybackState.CustomAction> mCustomActions;
     private final CharSequence mErrorMessage;
     private final long mUpdateTime;
-    private final long mActiveTrackId;
+    private final long mActiveItemId;
 
     private PlaybackState(int state, long position, long updateTime, float speed,
             long bufferPosition, long transportControls,
-            List<PlaybackState.CustomAction> customActions, long activeTrackId,
+            List<PlaybackState.CustomAction> customActions, long activeItemId,
             CharSequence error) {
         mState = state;
         mPosition = position;
@@ -236,7 +236,7 @@
         mBufferPosition = bufferPosition;
         mActions = transportControls;
         mCustomActions = new ArrayList<>(customActions);
-        mActiveTrackId = activeTrackId;
+        mActiveItemId = activeItemId;
         mErrorMessage = error;
     }
 
@@ -248,7 +248,7 @@
         mBufferPosition = in.readLong();
         mActions = in.readLong();
         mCustomActions = in.createTypedArrayList(CustomAction.CREATOR);
-        mActiveTrackId = in.readLong();
+        mActiveItemId = in.readLong();
         mErrorMessage = in.readCharSequence();
 
     }
@@ -263,7 +263,7 @@
         bob.append(", updated=").append(mUpdateTime);
         bob.append(", actions=").append(mActions);
         bob.append(", custom actions=").append(mCustomActions);
-        bob.append(", active track id=").append(mActiveTrackId);
+        bob.append(", active item id=").append(mActiveItemId);
         bob.append(", error=").append(mErrorMessage);
         bob.append("}");
         return bob.toString();
@@ -283,7 +283,7 @@
         dest.writeLong(mBufferPosition);
         dest.writeLong(mActions);
         dest.writeTypedList(mCustomActions);
-        dest.writeLong(mActiveTrackId);
+        dest.writeLong(mActiveItemId);
         dest.writeCharSequence(mErrorMessage);
     }
 
@@ -716,7 +716,7 @@
         private long mActions;
         private CharSequence mErrorMessage;
         private long mUpdateTime;
-        private long mActiveTrackId = MediaSession.Track.UNKNOWN_ID;
+        private long mActiveItemId = MediaSession.Item.UNKNOWN_ID;
 
         /**
          * Creates an initially empty state builder.
@@ -744,14 +744,14 @@
             }
             mErrorMessage = from.mErrorMessage;
             mUpdateTime = from.mUpdateTime;
-            mActiveTrackId = from.mActiveTrackId;
+            mActiveItemId = from.mActiveItemId;
         }
 
         /**
          * Set the current state of playback.
          * <p>
          * The position must be in ms and indicates the current playback
-         * position within the track. If the position is unknown use
+         * position within the item. If the position is unknown use
          * {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown
          * position the time at which the position was updated must be provided.
          * It is okay to use {@link SystemClock#elapsedRealtime()} if the
@@ -773,7 +773,7 @@
          * </ul>
          *
          * @param state The current state of playback.
-         * @param position The position in the current track in ms.
+         * @param position The position in the current item in ms.
          * @param playbackSpeed The current speed of playback as a multiple of
          *            normal playback.
          * @param updateTime The time in the {@link SystemClock#elapsedRealtime}
@@ -792,7 +792,7 @@
          * Set the current state of playback.
          * <p>
          * The position must be in ms and indicates the current playback
-         * position within the track. If the position is unknown use
+         * position within the item. If the position is unknown use
          * {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to
          * the current {@link SystemClock#elapsedRealtime()}.
          * <p>
@@ -812,7 +812,7 @@
          * </ul>
          *
          * @param state The current state of playback.
-         * @param position The position in the current track in ms.
+         * @param position The position in the current item in ms.
          * @param playbackSpeed The current speed of playback as a multiple of
          *            normal playback.
          * @return this
@@ -902,14 +902,14 @@
         }
 
         /**
-         * Set the active track in the play queue by specifying its id.
-         * The default value is {@link MediaSession.Track#UNKNOWN_ID}
+         * Set the active item in the play queue by specifying its id. The
+         * default value is {@link MediaSession.Item#UNKNOWN_ID}
          *
-         * @param id The id of the active track.
+         * @param id The id of the active item.
          * @return this
          */
-        public Builder setActiveTrack(long id) {
-            mActiveTrackId = id;
+        public Builder setActiveItem(long id) {
+            mActiveItemId = id;
             return this;
         }
 
@@ -932,7 +932,7 @@
          */
         public PlaybackState build() {
             return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferPosition,
-                    mActions, mCustomActions, mActiveTrackId, mErrorMessage);
+                    mActions, mCustomActions, mActiveItemId, mErrorMessage);
         }
     }
 }
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 99fb911..1aad2fa 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -29,7 +29,7 @@
 oneway interface ITvInputSession {
     void release();
 
-    void setMainSession(boolean isMainSession);
+    void setMain(boolean isMain);
     void setSurface(in Surface surface);
     void dispatchSurfaceChanged(int format, int width, int height);
     // TODO: Remove this once it becomes irrelevant for applications to handle audio focus. The plan
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index 5022cc1..58e46f0 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -42,7 +42,7 @@
     private static final String TAG = "TvInputSessionWrapper";
 
     private static final int DO_RELEASE = 1;
-    private static final int DO_SET_MAIN_SESSION = 2;
+    private static final int DO_SET_MAIN = 2;
     private static final int DO_SET_SURFACE = 3;
     private static final int DO_DISPATCH_SURFACE_CHANGED = 4;
     private static final int DO_SET_STREAM_VOLUME = 5;
@@ -91,8 +91,8 @@
                 }
                 return;
             }
-            case DO_SET_MAIN_SESSION: {
-                mTvInputSessionImpl.setMainSession((Boolean) msg.obj);
+            case DO_SET_MAIN: {
+                mTvInputSessionImpl.setMain((Boolean) msg.obj);
                 return;
             }
             case DO_SET_SURFACE: {
@@ -162,8 +162,8 @@
     }
 
     @Override
-    public void setMainSession(boolean isMain) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_MAIN_SESSION, isMain));
+    public void setMain(boolean isMain) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_MAIN, isMain));
     }
 
     @Override
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 6a7433d..3f5697f 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -158,17 +158,17 @@
     }
 
     /**
-     * Create a new instance of the TvInputInfo class,
-     * instantiating it from the given Context, ResolveInfo, and HdmiDeviceInfo.
+     * Create a new instance of the TvInputInfo class, instantiating it from the given Context,
+     * ResolveInfo, and HdmiDeviceInfo.
      *
      * @param service The ResolveInfo returned from the package manager about this TV input service.
      * @param deviceInfo The HdmiDeviceInfo for a HDMI CEC logical device.
      * @param parentId The ID of this TV input's parent input. {@code null} if none exists.
-     * @param iconUri The {@link android.net.Uri} to load the icon image.
-     *        {@see android.content.ContentResolver#openInputStream}. If it is null, the application
-     *        icon of {@code service} will be loaded.
-     * @param label The label of this TvInputInfo. If it is null or empty, {@code service} label
-     *        will be loaded.
+     * @param iconUri The {@link android.net.Uri} to load the icon image. See
+     *            {@link android.content.ContentResolver#openInputStream}. If it is {@code null},
+     *            the application icon of {@code service} will be loaded.
+     * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
+     *            label will be loaded.
      * @hide
      */
     @SystemApi
@@ -182,16 +182,16 @@
     }
 
     /**
-     * Create a new instance of the TvInputInfo class,
-     * instantiating it from the given Context, ResolveInfo, and TvInputHardwareInfo.
+     * Create a new instance of the TvInputInfo class, instantiating it from the given Context,
+     * ResolveInfo, and TvInputHardwareInfo.
      *
      * @param service The ResolveInfo returned from the package manager about this TV input service.
      * @param hardwareInfo The TvInputHardwareInfo for a TV input hardware device.
-     * @param iconUri The {@link android.net.Uri} to load the icon image.
-     *        {@see android.content.ContentResolver#openInputStream}. If it is null, the application
-     *        icon of {@code service} will be loaded.
-     * @param label The label of this TvInputInfo. If it is null or empty, {@code service} label
-     *        will be loaded.
+     * @param iconUri The {@link android.net.Uri} to load the icon image. See
+     *            {@link android.content.ContentResolver#openInputStream}. If it is {@code null},
+     *            the application icon of {@code service} will be loaded.
+     * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
+     *            label will be loaded.
      * @hide
      */
     @SystemApi
@@ -620,7 +620,7 @@
                 return new HashSet<String>();
             }
             String[] ids = hiddenIdsString.split(TV_INPUT_SEPARATOR);
-            return new HashSet(Arrays.asList(ids));
+            return new HashSet<>(Arrays.asList(ids));
         }
 
         /**
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 6e075b2..45aa6d6 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -235,14 +235,14 @@
         }
 
         /**
-         * This is called when {@link TvInputService.Session#layoutSurface} is called to
-         * change the layout of surface.
+         * This is called when {@link TvInputService.Session#layoutSurface} is called to change the
+         * layout of surface.
          *
          * @param session A {@link TvInputManager.Session} associated with this callback
-         * @param l Left position.
-         * @param t Top position.
-         * @param r Right position.
-         * @param b Bottom position.
+         * @param left Left position.
+         * @param top Top position.
+         * @param right Right position.
+         * @param bottom Bottom position.
          * @hide
          */
         @SystemApi
@@ -1023,10 +1023,12 @@
         }
 
         /**
-         * Sets this as main session. See {@link TvView#setMainTvView} for about meaning of "main".
-         * @hide
+         * Sets this as the main session. The main session is a session whose corresponding TV
+         * input determines the HDMI-CEC active source device.
+         *
+         * @see TvView#setMain
          */
-        public void setMainSession() {
+        void setMain() {
             if (mToken == null) {
                 Log.w(TAG, "The session has been already released");
                 return;
@@ -1164,7 +1166,7 @@
          *            {@link TvTrackInfo#TYPE_SUBTITLE}.
          * @param trackId The ID of the track to select. When {@code null}, the currently selected
          *            track of the given type will be unselected.
-         * @see #getTracks()
+         * @see #getTracks
          */
         public void selectTrack(int type, String trackId) {
             if (type == TvTrackInfo.TYPE_AUDIO) {
@@ -1339,6 +1341,9 @@
                 Log.w(TAG, "The session has been already released");
                 return;
             }
+            if (unblockedRating == null) {
+                throw new IllegalArgumentException("unblockedRating cannot be null");
+            }
             try {
                 mService.requestUnblockContent(mToken, unblockedRating.flattenToString(), mUserId);
             } catch (RemoteException e) {
@@ -1462,14 +1467,14 @@
         // Assumes the event has already been removed from the queue.
         void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
             p.mHandled = handled;
-            if (p.mHandler.getLooper().isCurrentThread()) {
+            if (p.mEventHandler.getLooper().isCurrentThread()) {
                 // Already running on the callback handler thread so we can send the callback
                 // immediately.
                 p.run();
             } else {
                 // Post the event to the callback handler thread.
                 // In this case, the callback will be responsible for recycling the event.
-                Message msg = Message.obtain(p.mHandler, p);
+                Message msg = Message.obtain(p.mEventHandler, p);
                 msg.setAsynchronous(true);
                 msg.sendToTarget();
             }
@@ -1494,9 +1499,9 @@
                 p = new PendingEvent();
             }
             p.mEvent = event;
-            p.mToken = token;
+            p.mEventToken = token;
             p.mCallback = callback;
-            p.mHandler = handler;
+            p.mEventHandler = handler;
             return p;
         }
 
@@ -1568,24 +1573,24 @@
 
         private final class PendingEvent implements Runnable {
             public InputEvent mEvent;
-            public Object mToken;
+            public Object mEventToken;
             public FinishedInputEventCallback mCallback;
-            public Handler mHandler;
+            public Handler mEventHandler;
             public boolean mHandled;
 
             public void recycle() {
                 mEvent = null;
-                mToken = null;
+                mEventToken = null;
                 mCallback = null;
-                mHandler = null;
+                mEventHandler = null;
                 mHandled = false;
             }
 
             @Override
             public void run() {
-                mCallback.onFinishedInputEvent(mToken, mHandled);
+                mCallback.onFinishedInputEvent(mEventToken, mHandled);
 
-                synchronized (mHandler) {
+                synchronized (mEventHandler) {
                     recyclePendingEventLocked(this);
                 }
             }
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 8ffe6cc..e3292b6 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -94,6 +94,8 @@
     private final RemoteCallbackList<ITvInputServiceCallback> mCallbacks =
             new RemoteCallbackList<ITvInputServiceCallback>();
 
+    private TvInputManager mTvInputManager;
+
     @Override
     public final IBinder onBind(Intent intent) {
         return new ITvInputService.Stub() {
@@ -225,6 +227,17 @@
         return null;
     }
 
+    private boolean isPassthroughInput(String inputId) {
+        if (mTvInputManager == null) {
+            mTvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE);
+        }
+        TvInputInfo info = mTvInputManager.getTvInputInfo(inputId);
+        if (info != null && info.isPassthroughInput()) {
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Base class for derived classes to implement to provide a TV input session.
      */
@@ -504,12 +517,13 @@
 
         /**
          * Assigns a position of the {@link Surface} passed by {@link #onSetSurface}. The position
-         * is relative to an overlay view. {@see #onOverlayViewSizeChanged}.
+         * is relative to an overlay view.
          *
          * @param left Left position in pixels, relative to the overlay view.
          * @param top Top position in pixels, relative to the overlay view.
          * @param right Right position in pixels, relative to the overlay view.
          * @param bottm Bottom position in pixels, relative to the overlay view.
+         * @see #onOverlayViewSizeChanged
          * @hide
          */
         @SystemApi
@@ -537,29 +551,30 @@
         public abstract void onRelease();
 
         /**
-         * Set the current session as the "main" session. See {@link TvView#setMainTvView} for the
-         * meaning of "main".
+         * Sets the current session as the main session. The main session is a session whose
+         * corresponding TV input determines the HDMI-CEC active source device.
          * <p>
-         * This is primarily for HDMI-CEC active source management. TV input service that manages
-         * HDMI-CEC logical device should make sure not only to select the corresponding HDMI
-         * logical device as source device on {@code onSetMainSession(true)}, but also to select
-         * internal device on {@code onSetMainSession(false)}. Also, if surface is set to non-main
-         * session, it needs to select internal device after temporarily selecting corresponding
-         * HDMI logical device for set up.
+         * TV input service that manages HDMI-CEC logical device should implement {@link
+         * #onSetMain} to (1) select the corresponding HDMI logical device as the source device
+         * when {@code isMain} is {@code true}, and to (2) select the internal device (= TV itself)
+         * as the source device when {@code isMain} is {@code false} and the session is still main.
+         * Also, if a surface is passed to a non-main session and active source is changed to
+         * initiate the surface, the active source should be returned to the main session.
          * </p><p>
-         * It is guaranteed that {@code onSetMainSession(true)} for new session is called first,
-         * and {@code onSetMainSession(false)} for old session is called afterwards. This allows
-         * {@code onSetMainSession(false)} to be no-op when TV input service knows that the next
-         * main session corresponds to another HDMI logical device. Practically, this implies that
-         * one TV input service should handle all HDMI port and HDMI-CEC logical devices for smooth
-         * active source transition.
+         * {@link TvView} guarantees that, when tuning involves a session transition, {@code
+         * onSetMain(true)} for new session is called first, {@code onSetMain(false)} for old
+         * session is called afterwards. This allows {@code onSetMain(false)} to be no-op when TV
+         * input service knows that the next main session corresponds to another HDMI logical
+         * device. Practically, this implies that one TV input service should handle all HDMI port
+         * and HDMI-CEC logical devices for smooth active source transition.
          * </p>
          *
-         * @param isMainSession If true, session is main.
+         * @param isMain If true, session should become main.
+         * @see TvView#setMain
          * @hide
          */
         @SystemApi
-        public void onSetMainSession(boolean isMainSession) {
+        public void onSetMain(boolean isMain) {
         }
 
         /**
@@ -827,10 +842,10 @@
         }
 
         /**
-         * Calls {@link #onSetMainSession}.
+         * Calls {@link #onSetMain}.
          */
-        void setMainSession(boolean isMainSession) {
-            onSetMainSession(isMainSession);
+        void setMain(boolean isMain) {
+            onSetMain(isMain);
         }
 
         /**
@@ -1228,9 +1243,14 @@
                         HardwareSession proxySession =
                                 ((HardwareSession) sessionImpl);
                         String harewareInputId = proxySession.getHardwareInputId();
-                        if (TextUtils.isEmpty(harewareInputId)) {
+                        if (TextUtils.isEmpty(harewareInputId) ||
+                                !isPassthroughInput(harewareInputId)) {
+                            if (TextUtils.isEmpty(harewareInputId)) {
+                                Log.w(TAG, "Hardware input id is not setup yet.");
+                            } else {
+                                Log.w(TAG, "Invalid hardware input id : " + harewareInputId);
+                            }
                             sessionImpl.onRelease();
-                            Log.w(TAG, "Hardware input id is not setup yet.");
                             try {
                                 cb.onSessionCreated(null, null);
                             } catch (RemoteException e) {
@@ -1238,7 +1258,6 @@
                             }
                             return;
                         }
-                        // TODO: check if the given ID is really hardware TV input.
                         proxySession.mProxySession = stub;
                         proxySession.mProxySessionCallback = cb;
                         proxySession.mServiceHandler = mServiceHandler;
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index 6ddb2a2..e0aacd6 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -46,10 +46,12 @@
     private final int mAudioSampleRate;
     private final int mVideoWidth;
     private final int mVideoHeight;
+    private final float mVideoFrameRate;
     private final Bundle mExtra;
 
     private TvTrackInfo(int type, String id, String language, int audioChannelCount,
-            int audioSampleRate, int videoWidth, int videoHeight, Bundle extra) {
+            int audioSampleRate, int videoWidth, int videoHeight, float videoFrameRate,
+            Bundle extra) {
         mType = type;
         mId = id;
         mLanguage = language;
@@ -57,6 +59,7 @@
         mAudioSampleRate = audioSampleRate;
         mVideoWidth = videoWidth;
         mVideoHeight = videoHeight;
+        mVideoFrameRate = videoFrameRate;
         mExtra = extra;
     }
 
@@ -68,6 +71,7 @@
         mAudioSampleRate = in.readInt();
         mVideoWidth = in.readInt();
         mVideoHeight = in.readInt();
+        mVideoFrameRate = in.readFloat();
         mExtra = in.readBundle();
     }
 
@@ -137,6 +141,17 @@
     }
 
     /**
+     * Returns the frame rate of the video, in the unit of fps (frames per second). Valid only for
+     * {@link #TYPE_VIDEO} tracks.
+     */
+    public final float getVideoFrameRate() {
+        if (mType != TYPE_VIDEO) {
+            throw new IllegalStateException("Not a video track");
+        }
+        return mVideoFrameRate;
+    }
+
+    /**
      * Returns the extra information about the current track.
      */
     public final Bundle getExtra() {
@@ -163,6 +178,7 @@
         dest.writeInt(mAudioSampleRate);
         dest.writeInt(mVideoWidth);
         dest.writeInt(mVideoHeight);
+        dest.writeFloat(mVideoFrameRate);
         dest.writeBundle(mExtra);
     }
 
@@ -190,6 +206,7 @@
         private int mAudioSampleRate;
         private int mVideoWidth;
         private int mVideoHeight;
+        private float mVideoFrameRate;
         private Bundle mExtra;
 
         /**
@@ -279,6 +296,20 @@
         }
 
         /**
+         * Sets the frame rate of the video, in the unit fps (frames per rate). Valid only for
+         * {@link #TYPE_VIDEO} tracks.
+         *
+         * @param videoFrameRate The frame rate of the video.
+         */
+        public final Builder setVideoFrameRate(float videoFrameRate) {
+            if (mType != TYPE_VIDEO) {
+                throw new IllegalStateException("Not a video track");
+            }
+            mVideoFrameRate = videoFrameRate;
+            return this;
+        }
+
+        /**
          * Sets the extra information about the current track.
          *
          * @param extra The extra information.
@@ -295,7 +326,7 @@
          */
         public TvTrackInfo build() {
             return new TvTrackInfo(mType, mId, mLanguage, mAudioChannelCount, mAudioSampleRate,
-                    mVideoWidth, mVideoHeight, mExtra);
+                    mVideoWidth, mVideoHeight, mVideoFrameRate, mExtra);
         }
     }
 }
\ No newline at end of file
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 591f543..f348b9b 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -59,19 +59,6 @@
     // STOPSHIP: Turn debugging off.
     private static final boolean DEBUG = true;
 
-    /**
-     * Passed with {@link TvInputListener#onError(String, int)}. Indicates that the connection to
-     * the requested TV input was not established thus the view is unable to handle the further
-     * operations.
-     */
-    public static final int ERROR_INPUT_NOT_CONNECTED = 0;
-
-    /**
-     * Passed with {@link TvInputListener#onError(String, int)}. Indicates that the underlying TV
-     * input has been disconnected.
-     */
-    public static final int ERROR_INPUT_DISCONNECTED = 1;
-
     private static final int VIDEO_SIZE_VALUE_UNKNOWN = 0;
 
     private static final int ZORDER_MEDIA = 0;
@@ -116,8 +103,10 @@
     private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
         @Override
         public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-            Log.d(TAG, "surfaceChanged(holder=" + holder + ", format=" + format + ", width=" + width
-                    + ", height=" + height + ")");
+            if (DEBUG) {
+                Log.d(TAG, "surfaceChanged(holder=" + holder + ", format=" + format + ", width="
+                    + width + ", height=" + height + ")");
+            }
             mSurfaceFormat = format;
             mSurfaceWidth = width;
             mSurfaceHeight = height;
@@ -188,24 +177,27 @@
     }
 
     /**
-     * Sets this as main TvView.
+     * Sets this as the main {@link TvView}.
      * <p>
-     * Main TvView is the TvView which user is watching and interacting mainly.  It is used for
-     * determining internal behavior of hardware TV input devices. For example, this influences
-     * how HDMI-CEC active source will be managed.
+     * The main {@link TvView} is a {@link TvView} whose corresponding TV input determines the
+     * HDMI-CEC active source device. For an HDMI port input, one of source devices that is
+     * connected to that HDMI port becomes the active source. For an HDMI-CEC logical device input,
+     * the corresponding HDMI-CEC logical device becomes the active source. For any non-HDMI input
+     * (including the tuner, composite, S-Video, etc.), the internal device (= TV itself) becomes
+     * the active source.
      * </p><p>
-     * First tuned TvView becomes main automatically, and keeps to be main until setMainTvView() is
-     * called for other TvView. Note that main TvView won't be reset even when current main TvView
-     * is removed from view hierarchy.
+     * First tuned {@link TvView} becomes main automatically, and keeps to be main until {@link
+     * #setMain} is called for other {@link TvView}. Note that main {@link TvView} won't be reset
+     * even when current main {@link TvView} is removed from view hierarchy.
      * </p>
      * @hide
      */
     @SystemApi
-    public void setMainTvView() {
+    public void setMain() {
         synchronized (sMainTvViewLock) {
             sMainTvView = this;
             if (hasWindowFocus() && mSession != null) {
-                mSession.setMainSession();
+                mSession.setMain();
             }
         }
     }
@@ -327,6 +319,7 @@
      * This method is primarily used to un-tune the current TvView.
      */
     public void reset() {
+        if (DEBUG) Log.d(TAG, "reset()");
         if (mSession != null) {
             release();
             resetSurfaceView();
@@ -538,7 +531,7 @@
         // Set main again to regain main session.
         synchronized (sMainTvViewLock) {
             if (hasFocus && this == sMainTvView && mSession != null) {
-                mSession.setMainSession();
+                mSession.setMain();
             }
         }
     }
@@ -596,6 +589,7 @@
             mSurfaceView.getHolder().removeCallback(mSurfaceHolderCallback);
             removeView(mSurfaceView);
         }
+        mSurface = null;
         mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) {
             @Override
             protected void updateWindow(boolean force, boolean redrawNeeded) {
@@ -679,13 +673,20 @@
     public abstract static class TvInputListener {
 
         /**
-         * This is invoked when an error occurred while handling requested operation.
+         * This is invoked when an error occurred while establishing a connection to the underlying
+         * TV input.
          *
          * @param inputId The ID of the TV input bound to this view.
-         * @param errorCode The error code. For the details of error code, please see
-         *         {@link TvView}.
          */
-        public void onError(String inputId, int errorCode) {
+        public void onConnectionFailed(String inputId) {
+        }
+
+        /**
+         * This is invoked when the existing connection to the underlying TV input is lost.
+         *
+         * @param inputId The ID of the TV input bound to this view.
+         */
+        public void onDisconnected(String inputId) {
         }
 
         /**
@@ -821,11 +822,14 @@
                 }
                 return;
             }
+            if (DEBUG) {
+                Log.d(TAG, "onSessionCreated()");
+            }
             mSession = session;
             if (session != null) {
                 synchronized (sMainTvViewLock) {
                     if (hasWindowFocus() && TvView.this == sMainTvView) {
-                        mSession.setMainSession();
+                        mSession.setMain();
                     }
                 }
                 // mSurface may not be ready yet as soon as starting an application.
@@ -847,7 +851,7 @@
                 }
             } else {
                 if (mListener != null) {
-                    mListener.onError(mInputId, ERROR_INPUT_NOT_CONNECTED);
+                    mListener.onConnectionFailed(mInputId);
                 }
             }
         }
@@ -860,7 +864,7 @@
             mSessionCallback = null;
             mSession = null;
             if (mListener != null) {
-                mListener.onError(mInputId, ERROR_INPUT_DISCONNECTED);
+                mListener.onDisconnected(mInputId);
             }
         }
 
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 20a621b..4c225c1 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -16,11 +16,13 @@
 
 package com.android.defcontainer;
 
+import static android.net.TrafficStats.MB_IN_BYTES;
+
 import android.app.IntentService;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageCleanItem;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
@@ -37,8 +39,6 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.StatFs;
-import android.provider.Settings;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructStatVfs;
@@ -50,13 +50,11 @@
 import com.android.internal.os.IParcelFileDescriptorFactory;
 import com.android.internal.util.ArrayUtils;
 
-import dalvik.system.VMRuntime;
 import libcore.io.IoUtils;
 import libcore.io.Streams;
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -155,10 +153,12 @@
          *            containing one or more APKs.
          */
         @Override
-        public PackageInfoLite getMinimalPackageInfo(final String packagePath, int flags,
-                long threshold, String abiOverride) {
-            PackageInfoLite ret = new PackageInfoLite();
+        public PackageInfoLite getMinimalPackageInfo(String packagePath, int flags,
+                String abiOverride) {
+            final Context context = DefaultContainerService.this;
+            final boolean isForwardLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
 
+            PackageInfoLite ret = new PackageInfoLite();
             if (packagePath == null) {
                 Slog.i(TAG, "Invalid package file " + packagePath);
                 ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
@@ -167,10 +167,12 @@
 
             final File packageFile = new File(packagePath);
             final PackageParser.PackageLite pkg;
+            final long sizeBytes;
             try {
                 pkg = PackageParser.parsePackageLite(packageFile, 0);
-            } catch (PackageParserException e) {
-                Slog.w(TAG, "Failed to parse package at " + packagePath);
+                sizeBytes = calculateInstalledSizeInner(pkg, isForwardLocked, abiOverride);
+            } catch (PackageParserException | IOException e) {
+                Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
 
                 if (!packageFile.exists()) {
                     ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
@@ -185,55 +187,13 @@
             ret.versionCode = pkg.versionCode;
             ret.installLocation = pkg.installLocation;
             ret.verifiers = pkg.verifiers;
-            ret.recommendedInstallLocation = recommendAppInstallLocation(pkg, flags, threshold,
-                    abiOverride);
+            ret.recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
+                    pkg.installLocation, sizeBytes, flags);
             ret.multiArch = pkg.multiArch;
 
             return ret;
         }
 
-        /**
-         * Determine if package will fit on internal storage.
-         *
-         * @param packagePath absolute path to the package to be copied. Can be
-         *            a single monolithic APK file or a cluster directory
-         *            containing one or more APKs.
-         */
-        @Override
-        public boolean checkInternalFreeStorage(String packagePath, boolean isForwardLocked,
-                long threshold) throws RemoteException {
-            final File packageFile = new File(packagePath);
-            final PackageParser.PackageLite pkg;
-            try {
-                pkg = PackageParser.parsePackageLite(packageFile, 0);
-                return isUnderInternalThreshold(pkg, isForwardLocked, threshold);
-            } catch (PackageParserException | IOException e) {
-                Slog.w(TAG, "Failed to parse package at " + packagePath);
-                return false;
-            }
-        }
-
-        /**
-         * Determine if package will fit on external storage.
-         *
-         * @param packagePath absolute path to the package to be copied. Can be
-         *            a single monolithic APK file or a cluster directory
-         *            containing one or more APKs.
-         */
-        @Override
-        public boolean checkExternalFreeStorage(String packagePath, boolean isForwardLocked,
-                String abiOverride) throws RemoteException {
-            final File packageFile = new File(packagePath);
-            final PackageParser.PackageLite pkg;
-            try {
-                pkg = PackageParser.parsePackageLite(packageFile, 0);
-                return isUnderExternalThreshold(pkg, isForwardLocked, abiOverride);
-            } catch (PackageParserException | IOException e) {
-                Slog.w(TAG, "Failed to parse package at " + packagePath);
-                return false;
-            }
-        }
-
         @Override
         public ObbInfo getObbInfo(String filename) {
             try {
@@ -295,13 +255,10 @@
             final PackageParser.PackageLite pkg;
             try {
                 pkg = PackageParser.parsePackageLite(packageFile, 0);
-                return calculateContainerSize(pkg, isForwardLocked, abiOverride) * 1024 * 1024;
+                return calculateInstalledSizeInner(pkg, isForwardLocked, abiOverride);
             } catch (PackageParserException | IOException e) {
-                /*
-                 * Okay, something failed, so let's just estimate it to be 2x
-                 * the file size. Note this will be 0 if the file doesn't exist.
-                 */
-                return packageFile.length() * 2;
+                Slog.w(TAG, "Failed to calculate installed size: " + e);
+                return Long.MAX_VALUE;
             }
         }
     };
@@ -381,10 +338,12 @@
             return null;
         }
 
-        // Calculate size of container needed to hold base APK.
+        // Calculate size of container needed to hold base APK. Round up to
+        // nearest MB, and tack on an extra MB for filesystem overhead.
         final int sizeMb;
         try {
-            sizeMb = calculateContainerSize(pkg, handle, isForwardLocked, abis);
+            final long sizeBytes = calculateInstalledSizeInner(pkg, handle, isForwardLocked, abis);
+            sizeMb = ((int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES)) + 1;
         } catch (IOException e) {
             Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath());
             return null;
@@ -523,124 +482,23 @@
         }
     }
 
-    private static final int PREFER_INTERNAL = 1;
-    private static final int PREFER_EXTERNAL = 2;
-
-    private int recommendAppInstallLocation(PackageLite pkg, int flags, long threshold,
-            String abiOverride) {
-        int prefer;
-        boolean checkBoth = false;
-
-        final boolean isForwardLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
-
-        check_inner : {
-            /*
-             * Explicit install flags should override the manifest settings.
-             */
-            if ((flags & PackageManager.INSTALL_INTERNAL) != 0) {
-                prefer = PREFER_INTERNAL;
-                break check_inner;
-            } else if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) {
-                prefer = PREFER_EXTERNAL;
-                break check_inner;
-            }
-
-            /* No install flags. Check for manifest option. */
-            if (pkg.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
-                prefer = PREFER_INTERNAL;
-                break check_inner;
-            } else if (pkg.installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
-                prefer = PREFER_EXTERNAL;
-                checkBoth = true;
-                break check_inner;
-            } else if (pkg.installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
-                // We default to preferring internal storage.
-                prefer = PREFER_INTERNAL;
-                checkBoth = true;
-                break check_inner;
-            }
-
-            // Pick user preference
-            int installPreference = Settings.Global.getInt(getApplicationContext()
-                    .getContentResolver(),
-                    Settings.Global.DEFAULT_INSTALL_LOCATION,
-                    PackageHelper.APP_INSTALL_AUTO);
-            if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) {
-                prefer = PREFER_INTERNAL;
-                break check_inner;
-            } else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) {
-                prefer = PREFER_EXTERNAL;
-                break check_inner;
-            }
-
-            /*
-             * Fall back to default policy of internal-only if nothing else is
-             * specified.
-             */
-            prefer = PREFER_INTERNAL;
-        }
-
-        final boolean emulated = Environment.isExternalStorageEmulated();
-
-        boolean fitsOnInternal = false;
-        if (checkBoth || prefer == PREFER_INTERNAL) {
-            try {
-                fitsOnInternal = isUnderInternalThreshold(pkg, isForwardLocked, threshold);
-            } catch (IOException e) {
-                return PackageHelper.RECOMMEND_FAILED_INVALID_URI;
-            }
-        }
-
-        boolean fitsOnSd = false;
-        if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) {
-            try {
-                fitsOnSd = isUnderExternalThreshold(pkg, isForwardLocked, abiOverride);
-            } catch (IOException e) {
-                return PackageHelper.RECOMMEND_FAILED_INVALID_URI;
-            }
-        }
-
-        if (prefer == PREFER_INTERNAL) {
-            if (fitsOnInternal) {
-                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
-            }
-        } else if (!emulated && prefer == PREFER_EXTERNAL) {
-            if (fitsOnSd) {
-                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
-            }
-        }
-
-        if (checkBoth) {
-            if (fitsOnInternal) {
-                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
-            } else if (!emulated && fitsOnSd) {
-                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
-            }
-        }
-
-        /*
-         * If they requested to be on the external media by default, return that
-         * the media was unavailable. Otherwise, indicate there was insufficient
-         * storage space available.
-         */
-        if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)
-                && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
-            return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE;
-        } else {
-            return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
+    private long calculateInstalledSizeInner(PackageLite pkg, boolean isForwardLocked,
+            String abiOverride) throws IOException {
+        NativeLibraryHelper.Handle handle = null;
+        try {
+            handle = NativeLibraryHelper.Handle.create(pkg);
+            return calculateInstalledSizeInner(pkg, handle, isForwardLocked,
+                    calculateAbiList(handle, abiOverride, pkg.multiArch));
+        } finally {
+            IoUtils.closeQuietly(handle);
         }
     }
 
-    /**
-     * Measure a file to see if it fits within the free space threshold.
-     *
-     * @param threshold byte threshold to compare against
-     * @return true if file fits under threshold
-     * @throws FileNotFoundException when APK does not exist
-     */
-    private boolean isUnderInternalThreshold(PackageLite pkg, boolean isForwardLocked,
-            long threshold) throws IOException {
+    private long calculateInstalledSizeInner(PackageLite pkg, NativeLibraryHelper.Handle handle,
+            boolean isForwardLocked, String[] abis) throws IOException {
         long sizeBytes = 0;
+
+        // Include raw APKs, and possibly unpacked resources
         for (String codePath : pkg.getAllCodePaths()) {
             sizeBytes += new File(codePath).length();
 
@@ -649,47 +507,12 @@
             }
         }
 
-        final StatFs stat = new StatFs(Environment.getDataDirectory().getPath());
-        final long availBytes = stat.getAvailableBytes();
-        return (availBytes - sizeBytes) > threshold;
-    }
-
-    /**
-     * Measure a file to see if it fits in the external free space.
-     *
-     * @return true if file fits
-     * @throws IOException when file does not exist
-     */
-    private boolean isUnderExternalThreshold(PackageLite pkg, boolean isForwardLocked,
-            String abiOverride) throws IOException {
-        if (Environment.isExternalStorageEmulated()) {
-            return false;
+        // Include all relevant native code
+        if (!ArrayUtils.isEmpty(abis)) {
+            sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle, abis);
         }
 
-        final int sizeMb = calculateContainerSize(pkg, isForwardLocked, abiOverride);
-
-        final int availSdMb;
-        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
-            final StatFs sdStats = new StatFs(Environment.getExternalStorageDirectory().getPath());
-            final int blocksToMb = (1 << 20) / sdStats.getBlockSize();
-            availSdMb = sdStats.getAvailableBlocks() * blocksToMb;
-        } else {
-            availSdMb = -1;
-        }
-
-        return availSdMb > sizeMb;
-    }
-
-    private int calculateContainerSize(PackageLite pkg, boolean isForwardLocked, String abiOverride)
-            throws IOException {
-        NativeLibraryHelper.Handle handle = null;
-        try {
-            handle = NativeLibraryHelper.Handle.create(pkg);
-            return calculateContainerSize(pkg, handle, isForwardLocked,
-                    calculateAbiList(handle, abiOverride, pkg.multiArch));
-        } finally {
-            IoUtils.closeQuietly(handle);
-        }
+        return sizeBytes;
     }
 
     private String[] calculateAbiList(NativeLibraryHelper.Handle handle, String abiOverride,
@@ -731,43 +554,4 @@
 
         return null;
     }
-
-    /**
-     * Calculate the container size for a package.
-     * 
-     * @return size in megabytes (2^20 bytes)
-     * @throws IOException when there is a problem reading the file
-     */
-    private int calculateContainerSize(PackageLite pkg, NativeLibraryHelper.Handle handle,
-            boolean isForwardLocked, String[] abis) throws IOException {
-        // Calculate size of container needed to hold APKs.
-        long sizeBytes = 0;
-        for (String codePath : pkg.getAllCodePaths()) {
-            sizeBytes += new File(codePath).length();
-
-            if (isForwardLocked) {
-                sizeBytes += PackageHelper.extractPublicFiles(codePath, null);
-            }
-        }
-
-        // Check all the native files that need to be copied and add that to the
-        // container size.
-        if (abis != null) {
-            sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle, abis);
-        }
-
-        int sizeMb = (int) (sizeBytes >> 20);
-        if ((sizeBytes - (sizeMb * 1024 * 1024)) > 0) {
-            sizeMb++;
-        }
-
-        /*
-         * Add buffer size because we don't have a good way to determine the
-         * real FAT size. Your FAT size varies with how many directory entries
-         * you need, how big the whole filesystem is, and other such headaches.
-         */
-        sizeMb++;
-
-        return sizeMb;
-    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
index f009787..828c921 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
@@ -77,7 +77,7 @@
             if (isVisibleToUser()) {
                 dismiss(false /* authenticated */);
             } else {
-                // TODO: Play first half of unlock sound.
+                mViewMediatorCallback.playTrustedSound();
             }
         }
     };
diff --git a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
index 2e5450d..0c9dbc4 100644
--- a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
@@ -66,4 +66,9 @@
      * Report when the UI is ready for dismissing the whole Keyguard.
      */
     void readyForKeyguardDone();
+
+    /**
+     * Play the "device trusted" sound.
+     */
+    void playTrustedSound();
 }
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 9a62864..055587a 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -46,7 +46,7 @@
         android:label="@string/app_label"
         android:allowBackup= "false"
         android:supportsRtl="true"
-        android:icon="@*android:drawable/ic_print">
+        android:icon="@drawable/ic_print">
 
         <service
             android:name=".model.PrintSpoolerService"
diff --git a/packages/PrintSpooler/res/drawable-hdpi/ic_menu_print.png b/packages/PrintSpooler/res/drawable-hdpi/ic_menu_print.png
deleted file mode 100644
index 09ab1a2..0000000
--- a/packages/PrintSpooler/res/drawable-hdpi/ic_menu_print.png
+++ /dev/null
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png b/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png
deleted file mode 100644
index 637d94e..0000000
--- a/packages/PrintSpooler/res/drawable-mdpi/ic_menu_print.png
+++ /dev/null
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png b/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png
deleted file mode 100644
index 4d4b3cc..0000000
--- a/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_print.png
+++ /dev/null
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable/ic_print.xml b/packages/PrintSpooler/res/drawable/ic_print.xml
new file mode 100644
index 0000000..dc6e0fb
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/ic_print.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@*android:drawable/ic_print"
+    android:tint="@color/promoted_action_background_color" />
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
index db319e9..08702291 100644
--- a/packages/PrintSpooler/res/values/themes.xml
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -16,7 +16,10 @@
 
 <resources>
 
-    <style name="PrintActivity" parent="@android:style/Theme.Material.Settings">
+    <style name="PrintActivity" parent="@android:style/Theme.Material">
+        <item name="android:colorPrimary">@*android:color/material_blue_grey_900</item>
+        <item name="android:colorPrimaryDark">@*android:color/material_blue_grey_950</item>
+        <item name="android:colorAccent">@*android:color/material_deep_teal_A500</item>
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:windowContentOverlay">@null</item>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index 3134e93..5233c79 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -124,7 +124,9 @@
                 .setContentText(printJob.getPrinterName())
                 .setWhen(System.currentTimeMillis())
                 .setOngoing(true)
-                .setShowWhen(true);
+                .setShowWhen(true)
+                .setColor(mContext.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
         mNotificationManager.notify(0, builder.build());
     }
 
@@ -140,7 +142,9 @@
                 .setContentText(printJob.getPrinterName())
                 .setWhen(System.currentTimeMillis())
                 .setOngoing(true)
-                .setShowWhen(true);
+                .setShowWhen(true)
+                .setColor(mContext.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
         mNotificationManager.notify(0, builder.build());
     }
 
@@ -154,7 +158,9 @@
                 .setContentText(printJob.getPrinterName())
                 .setWhen(System.currentTimeMillis())
                 .setOngoing(true)
-                .setShowWhen(true);
+                .setShowWhen(true)
+                .setColor(mContext.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
            mNotificationManager.notify(0, builder.build());
     }
 
@@ -166,7 +172,9 @@
                 .setContentText(printJob.getPrinterName())
                 .setWhen(System.currentTimeMillis())
                 .setOngoing(true)
-                .setShowWhen(true);
+                .setShowWhen(true)
+                .setColor(mContext.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
         mNotificationManager.notify(0, builder.build());
     }
 
@@ -198,6 +206,8 @@
 
         builder.setNumber(printJobCount);
         builder.setStyle(inboxStyle);
+        builder.setColor(mContext.getResources().getColor(
+                com.android.internal.R.color.system_notification_accent_color));
 
         mNotificationManager.notify(0, builder.build());
     }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index 7715579..3905bada 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -96,7 +96,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        getActionBar().setIcon(R.drawable.ic_menu_print);
+        getActionBar().setIcon(R.drawable.ic_print);
 
         setContentView(R.layout.select_printer_activity);
 
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 478a5de..299e50c 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -73,6 +73,7 @@
     <integer name="def_lockscreen_sounds_enabled">1</integer>
     <string name="def_lock_sound" translatable="false">/system/media/audio/ui/Lock.ogg</string>
     <string name="def_unlock_sound" translatable="false">/system/media/audio/ui/Unlock.ogg</string>
+    <string name="def_trusted_sound" translatable="false">/system/media/audio/ui/Trusted.ogg</string>
     <string name="def_wireless_charging_started_sound" translatable="false">/system/media/audio/ui/WirelessChargingStarted.ogg</string>
 
     <bool name="def_lockscreen_disabled">false</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 7c92cde..13301fb 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -70,7 +70,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 106;
+    private static final int DATABASE_VERSION = 107;
 
     private Context mContext;
     private int mUserHandle;
@@ -1694,6 +1694,26 @@
             }
             upgradeVersion = 106;
         }
+
+        if (upgradeVersion < 107) {
+            // Add trusted sound setting
+            if (mUserHandle == UserHandle.USER_OWNER) {
+                db.beginTransaction();
+                SQLiteStatement stmt = null;
+                try {
+                    stmt = db.compileStatement("INSERT OR REPLACE INTO global(name,value)"
+                            + " VALUES(?,?);");
+                    loadStringSetting(stmt, Settings.Global.TRUSTED_SOUND,
+                            R.string.def_trusted_sound);
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                    if (stmt != null) stmt.close();
+                }
+            }
+            upgradeVersion = 107;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -2373,6 +2393,8 @@
                     R.string.def_lock_sound);
             loadStringSetting(stmt, Settings.Global.UNLOCK_SOUND,
                     R.string.def_unlock_sound);
+            loadStringSetting(stmt, Settings.Global.TRUSTED_SOUND,
+                    R.string.def_trusted_sound);
             loadIntegerSetting(stmt, Settings.Global.POWER_SOUNDS_ENABLED,
                     R.integer.def_power_sounds_enabled);
             loadStringSetting(stmt, Settings.Global.LOW_BATTERY_SOUND,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 6f41565..f1d2bee3 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -90,6 +90,7 @@
     <uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" />
     <uses-permission android:name="android.permission.FRAME_STATS" />
     <uses-permission android:name="android.permission.BIND_APPWIDGET" />
+    <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
 
     <application android:label="@string/app_label">
         <provider
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index 7a659ee..02a3aeb 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -84,14 +84,17 @@
         }
         notifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
-        final Notification.Builder builder = new Notification.Builder(context);
-        builder.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb);
-        builder.setContentTitle(context.getString(R.string.bugreport_finished_title));
-        builder.setTicker(context.getString(R.string.bugreport_finished_title));
-        builder.setContentText(context.getString(R.string.bugreport_finished_text));
-        builder.setContentIntent(PendingIntent.getActivity(
-                context, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT));
-        builder.setAutoCancel(true);
+        final Notification.Builder builder = new Notification.Builder(context)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                .setContentTitle(context.getString(R.string.bugreport_finished_title))
+                .setTicker(context.getString(R.string.bugreport_finished_title))
+                .setContentText(context.getString(R.string.bugreport_finished_text))
+                .setContentIntent(PendingIntent.getActivity(
+                        context, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT))
+                .setAutoCancel(true)
+                .setColor(context.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
+
         NotificationManager.from(context).notify(TAG, 0, builder.build());
 
         // Clean up older bugreports in background
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b8836a0..cbea664 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -111,7 +111,7 @@
     <uses-permission android:name="android.permission.CAMERA" />
 
     <!-- Screen Capturing -->
-    <uses-permission android:name="android.permission.CREATE_MEDIA_PROJECTION" />
+    <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
 
     <application
         android:name=".SystemUIApplication"
diff --git a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
deleted file mode 100644
index 0df1a96..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
+++ /dev/null
@@ -1,25 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="64dp"
-        android:height="64dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M20.0,8.0l-2.8,0.0c-0.5,-0.8 -1.1,-1.5 -1.8,-2.0L17.0,4.4L15.6,3.0l-2.2,2.2C13.0,5.1 12.5,5.0 12.0,5.0s-1.0,0.1 -1.4,0.2L8.4,3.0L7.0,4.4L8.6,6.0C7.9,6.5 7.3,7.2 6.8,8.0L4.0,8.0l0.0,2.0l2.1,0.0C6.0,10.3 6.0,10.7 6.0,11.0l0.0,1.0L4.0,12.0l0.0,2.0l2.0,0.0l0.0,1.0c0.0,0.3 0.0,0.7 0.1,1.0L4.0,16.0l0.0,2.0l2.8,0.0c1.0,1.8 3.0,3.0 5.2,3.0s4.2,-1.2 5.2,-3.0L20.0,18.0l0.0,-2.0l-2.1,0.0c0.1,-0.3 0.1,-0.7 0.1,-1.0l0.0,-1.0l2.0,0.0l0.0,-2.0l-2.0,0.0l0.0,-1.0c0.0,-0.3 0.0,-0.7 -0.1,-1.0L20.0,10.0L20.0,8.0zM14.0,16.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,16.0zM14.0,12.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,12.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/indeterminate.xml b/packages/SystemUI/res/drawable/indeterminate.xml
new file mode 100644
index 0000000..35e11e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/indeterminate.xml
@@ -0,0 +1,45 @@
+<!--
+ 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"
+    android:height="2dp"
+    android:viewportHeight="1"
+    android:viewportWidth="360"
+    android:width="360dp" >
+
+    <group
+        android:name="linear_indeterminate"
+        android:translateX="180.0"
+        android:translateY="0.0" >
+        <group
+            android:name="path1"
+            android:scaleX="0.1"
+            android:translateX="-522.59" >
+            <path
+                android:name="rect1"
+                android:fillColor="?android:attr/colorControlActivated"
+                android:pathData="m 0 0 l 288 0 l 0 1 l -288 0 z" />
+        </group>
+        <group
+            android:name="path2"
+            android:scaleX="0.1"
+            android:translateX="-197.6" >
+            <path
+                android:name="rect2"
+                android:fillColor="?android:attr/colorControlActivated"
+                android:pathData="m 0 0 l 288 0 l 0 1 l -288 0 z" />
+        </group>
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/indeterminate_anim.xml b/packages/SystemUI/res/drawable/indeterminate_anim.xml
new file mode 100644
index 0000000..52c6d16
--- /dev/null
+++ b/packages/SystemUI/res/drawable/indeterminate_anim.xml
@@ -0,0 +1,32 @@
+<!--
+ 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/indeterminate" >
+
+    <target
+        android:name="path1"
+        android:animation="@*android:anim/progress_indeterminate_horizontal_rect1_translate" />
+    <target
+        android:name="path1"
+        android:animation="@*android:anim/progress_indeterminate_horizontal_rect1_scale" />
+
+    <target
+        android:name="path2"
+        android:animation="@*android:anim/progress_indeterminate_horizontal_rect2_translate" />
+    <target
+        android:name="path2"
+        android:animation="@*android:anim/progress_indeterminate_horizontal_rect2_scale" />
+</animated-vector>
diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml
index fcc0f4a..faa2820 100644
--- a/packages/SystemUI/res/layout/keyguard_status_bar.xml
+++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml
@@ -60,7 +60,8 @@
             android:paddingEnd="@dimen/battery_level_padding_end"
             android:textColor="#ffffff"
             android:visibility="gone"
-            android:textSize="@dimen/battery_level_text_size"/>
+            android:textSize="@dimen/battery_level_text_size"
+            android:importantForAccessibility="noHideDescendants"/>
     </LinearLayout>
 
     <com.android.keyguard.CarrierText
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 828065b..5253ee0 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -69,6 +69,7 @@
         android:layout_gravity="bottom|right"
         android:layout_marginRight="15dp"
         android:layout_marginBottom="15dp"
+        android:translationZ="3dp"
         android:contentDescription="@string/recents_lock_to_app_button_label"
         android:background="@drawable/recents_lock_to_task_button_bg">
         <ImageView
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 1226fc5..aa276bc 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -72,7 +72,8 @@
             android:layout_marginStart="@dimen/header_battery_margin_expanded"
             android:paddingEnd="@dimen/battery_level_padding_end"
             android:textColor="#ffffff"
-            android:textSize="@dimen/battery_level_text_size"/>
+            android:textSize="@dimen/battery_level_text_size"
+            android:importantForAccessibility="noHideDescendants"/>
     </LinearLayout>
 
     <TextView
@@ -148,6 +149,16 @@
         android:layout_alignParentBottom="true"
         />
 
+    <ImageView
+        android:id="@+id/qs_detail_header_progress"
+        android:src="@drawable/indeterminate_anim"
+        android:alpha="0"
+        android:background="@color/qs_detail_progress_track"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        />
+
     <TextView
         android:id="@+id/header_debug_info"
         android:visibility="invisible"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 0cc74a8..40870bf 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -23,7 +23,6 @@
     <color name="system_bar_background_opaque">#ff000000</color>
     <color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black -->
     <color name="system_bar_background_transparent">#00000000</color>
-    <color name="system_bar_background_warning">#fff4511e</color><!-- deep orange 600 -->
     <color name="notification_panel_solid_background">#ff000000</color>
     <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
     <color name="status_bar_recents_app_label_color">#ffffffff</color>
@@ -45,6 +44,7 @@
     <color name="qs_subhead">#99FFFFFF</color><!-- 60% white -->
     <color name="qs_detail_empty">#24B0BEC5</color><!-- 14% blue grey 200-->
     <color name="qs_detail_transition">#66FFFFFF</color>
+    <color name="qs_detail_progress_track">#99009688</color><!-- 60% deep teal 500 -->
     <color name="data_usage_secondary">#99FFFFFF</color><!-- 60% white -->
     <color name="data_usage_graph_track">#33FFFFFF</color><!-- 20% white -->
     <color name="data_usage_graph_warning">#FFFFFFFF</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5415d19..1b8eeb2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -205,10 +205,10 @@
     <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
 
     <!-- The min translation in the Z index for the last task. -->
-    <dimen name="recents_task_view_z_min">5dp</dimen>
+    <dimen name="recents_task_view_z_min">25dp</dimen>
 
     <!-- The max translation in the Z index for the last task. -->
-    <dimen name="recents_task_view_z_max">65dp</dimen>
+    <dimen name="recents_task_view_z_max">100dp</dimen>
 
     <!-- The amount to translate when animating the removal of a task. -->
     <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d145172..d49312d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -273,6 +273,13 @@
     <!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_wifi_signal_full">Wifi signal full.</string>
 
+    <!-- Content description of the wifi label showing what we are connected to. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_wifi_name">Connected to <xliff:g id="wifi" example="Home Network">%s</xliff:g>.</string>
+
+    <!-- Content description of the bluetooth label showing what we are connected to. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_bluetooth_name">Connected to <xliff:g id="bluetooth" example="Car Audio">%s</xliff:g>.</string>
+
+
     <!-- Content description of the WiMAX signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_no_wimax">No WiMAX.</string>
     <!-- Content description of the WiMAX signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -390,6 +397,8 @@
     <string name="accessibility_desc_notification_shade">Notification shade.</string>
     <!-- Content description for the quick settings panel (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_desc_quick_settings">Quick settings.</string>
+    <!-- Content description for the lock screen (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_desc_lock_screen">Lock screen.</string>
     <!-- Content description for the settings button in the status bar header. [CHAR LIMIT=NONE] -->
     <string name="accessibility_desc_settings">Settings</string>
     <!-- Content description for the recent apps panel (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -398,7 +407,7 @@
     <!-- Content description of the user tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_user">User <xliff:g id="user" example="John Doe">%s</xliff:g>.</string>
     <!-- Content description of the wifi tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_wifi"><xliff:g id="signal" example="Three bars">%1$s</xliff:g>. <xliff:g id="network" example="MyWifiNetwork">%2$s</xliff:g></string>
+    <string name="accessibility_quick_settings_wifi"><xliff:g id="signal" example="Three bars">%1$s</xliff:g>.</string>
     <!-- Content description of the mobile data tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_mobile">Mobile <xliff:g id="signal" example="Three bars">%1$s</xliff:g>. <xliff:g id="type" example="4G">%2$s</xliff:g>. <xliff:g id="network" example="T-Mobile">%3$s</xliff:g>.</string>
     <!-- Content description of the battery tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -577,7 +586,7 @@
     <!-- QuickSettings: Cellular detail panel, remaining data title [CHAR LIMIT=NONE] -->
     <string name="quick_settings_cellular_detail_remaining_data">Remaining data</string>
     <!-- QuickSettings: Cellular detail panel, over limit title [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_cellular_detail_over_limit">Over limit</string>
+    <string name="quick_settings_cellular_detail_over_limit">Limit reached &#8211; data usage paused</string>
     <!-- QuickSettings: Cellular detail panel, data used format string [CHAR LIMIT=NONE] -->
     <string name="quick_settings_cellular_detail_data_used"><xliff:g id="data_used" example="2.0 GB">%s</xliff:g> used</string>
     <!-- QuickSettings: Cellular detail panel, data limit format string [CHAR LIMIT=NONE] -->
@@ -659,8 +668,6 @@
     <!-- Shows when people have clicked at the right edge of the screen to explain how to open the phone. In right-to-left languages, this is the opposite direction. [CHAR LIMIT=60] -->
     <string name="camera_hint">Swipe left for camera</string>
 
-    <string name="bugreport_tile_extended" translatable="false">%s\n%s (%s)</string>
-
     <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
     <string name="zen_mode_forever">Indefinitely</string>
 
@@ -700,10 +707,13 @@
     <string name="guest_exit_guest">Remove guest</string>
 
     <!-- Title of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
-    <string name="guest_exit_guest_dialog_title">Exiting guest session?</string>
+    <string name="guest_exit_guest_dialog_title">Remove guest?</string>
 
     <!-- Message of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
-    <string name="guest_exit_guest_dialog_message">Exiting the guest session will remove local data.</string>
+    <string name="guest_exit_guest_dialog_message">All apps and data in this session will be deleted.</string>
+
+    <!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] -->
+    <string name="guest_exit_guest_dialog_remove">Remove</string>
 
     <!-- Title of the notification when resuming an existing guest session [CHAR LIMIT=NONE] -->
     <string name="guest_wipe_session_title">Welcome back, guest!</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 27e58a4..48a031a 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -21,11 +21,23 @@
     </style>
 
     <!-- Alternate Recents theme -->
-    <style name="RecentsTheme" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar">
+    <style name="RecentsTheme" parent="@android:style/Theme">
+        <!-- NoTitle -->
+        <item name="android:windowNoTitle">true</item>
+        <!-- Wallpaper -->
+        <item name="android:windowBackground">@color/transparent</item>
+        <item name="android:colorBackgroundCacheHint">@null</item>
+        <item name="android:windowShowWallpaper">true</item>
+        <!-- Misc -->
         <item name="android:statusBarColor">@android:color/transparent</item>
         <item name="android:navigationBarColor">@android:color/transparent</item>
         <item name="android:windowDrawsSystemBarBackgrounds">true</item>
         <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
+        <item name="*android:lightingStyle">@style/RecentsLighting</item>
+    </style>
+
+    <style name="RecentsLighting" parent="@*android:style/Lighting">
+        <item name="*android:ambientShadowAlpha">0.30</item>
     </style>
 
     <!-- Animations for a non-full-screen window or activity. -->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index be11220..ad568b8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -262,6 +262,7 @@
     private SoundPool mLockSounds;
     private int mLockSoundId;
     private int mUnlockSoundId;
+    private int mTrustedSoundId;
     private int mLockSoundStreamId;
 
     /**
@@ -451,6 +452,11 @@
                 KeyguardViewMediator.this.keyguardDone(true /* authenticated */, true /* wakeUp */);
             }
         }
+
+        @Override
+        public void playTrustedSound() {
+            KeyguardViewMediator.this.playTrustedSound();
+        }
     };
 
     public void userActivity() {
@@ -500,6 +506,14 @@
         if (soundPath == null || mUnlockSoundId == 0) {
             Log.w(TAG, "failed to load unlock sound from " + soundPath);
         }
+        soundPath = Settings.Global.getString(cr, Settings.Global.TRUSTED_SOUND);
+        if (soundPath != null) {
+            mTrustedSoundId = mLockSounds.load(soundPath, 1);
+        }
+        if (soundPath == null || mTrustedSoundId == 0) {
+            Log.w(TAG, "failed to load trusted sound from " + soundPath);
+        }
+
         int lockSoundDefaultAttenuation = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_lockSoundVolumeDb);
         mLockSoundVolume = (float)Math.pow(10, (float)lockSoundDefaultAttenuation/20);
@@ -1155,11 +1169,14 @@
             return;
         }
 
+        playSound(locked ? mLockSoundId : mUnlockSoundId);
+    }
+
+    private void playSound(int soundId) {
+        if (soundId == 0) return;
         final ContentResolver cr = mContext.getContentResolver();
         if (Settings.System.getInt(cr, Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) == 1) {
-            final int whichSound = locked
-                ? mLockSoundId
-                : mUnlockSoundId;
+
             mLockSounds.stop(mLockSoundStreamId);
             // Init mAudioManager
             if (mAudioManager == null) {
@@ -1170,11 +1187,18 @@
             // If the stream is muted, don't play the sound
             if (mAudioManager.isStreamMute(mMasterStreamType)) return;
 
-            mLockSoundStreamId = mLockSounds.play(whichSound,
+            mLockSoundStreamId = mLockSounds.play(soundId,
                     mLockSoundVolume, mLockSoundVolume, 1/*priortiy*/, 0/*loop*/, 1.0f/*rate*/);
         }
     }
 
+    private void playTrustedSound() {
+        if (mSuppressNextLockSound) {
+            return;
+        }
+        playSound(mTrustedSoundId);
+    }
+
     private void updateActivityLockScreenState() {
         try {
             ActivityManagerNative.getDefault().setLockScreenShown(mShowing && !mOccluded);
diff --git a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
index 1ac8295..b3c0783 100644
--- a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
@@ -63,13 +63,13 @@
                 });
 
         final Dialog dialog = builder.create();
+        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
         dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
             public void onDismiss(DialogInterface dialog) {
                 finish();
             }
         });
 
-        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
         dialog.show();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index d455cec..14f93f7 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -162,7 +162,9 @@
                 .setPriority(Notification.PRIORITY_MAX)
                 .setCategory(Notification.CATEGORY_SYSTEM)
                 .setVisibility(Notification.VISIBILITY_PUBLIC)
-                .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_CHARGER), true);
+                .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_CHARGER), true)
+                .setColor(mContext.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
         final Notification n = nb.build();
         if (n.headsUpContentView != null) {
             n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
@@ -185,7 +187,9 @@
                 .setPriority(Notification.PRIORITY_MAX)
                 .setCategory(Notification.CATEGORY_SYSTEM)
                 .setVisibility(Notification.VISIBILITY_PUBLIC)
-                .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_WARNING), true);
+                .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_WARNING), true)
+                .setColor(mContext.getResources().getColor(
+                        com.android.internal.R.color.battery_saver_mode_color));
         if (hasBatterySettings()) {
             nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
         }
@@ -214,7 +218,9 @@
                 .setOngoing(true)
                 .setShowWhen(false)
                 .setCategory(Notification.CATEGORY_SYSTEM)
-                .setVisibility(Notification.VISIBILITY_PUBLIC);
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setColor(mContext.getResources().getColor(
+                        com.android.internal.R.color.battery_saver_mode_color));
         addStopSaverAction(nb);
         if (hasSaverSettings()) {
             nb.setContentIntent(pendingActivity(mOpenSaverSettings));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index c3144c1..bf01b7b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -234,8 +234,9 @@
             }
             @Override
             public void onScanStateChanged(boolean state) {
+                r.scanState = state;
                 if (mDetailRecord == r) {
-                    fireScanStateChanged(state);
+                    fireScanStateChanged(r.scanState);
                 }
             }
         };
@@ -310,9 +311,10 @@
             mDetailContent.removeAllViews();
             mDetail.bringToFront();
             mDetailContent.addView(r.detailView);
-            mDetailRecord = r;
+            setDetailRecord(r);
         } else {
             listener = mTeardownDetailWhenDone;
+            fireScanStateChanged(false);
         }
         fireShowingDetail(show ? detailAdapter : null);
         mClipper.animateCircularClip(x, y, show, listener);
@@ -345,8 +347,8 @@
         }
 
         for (TileRecord record : mRecords) {
-            if (record.tileView.getVisibility() == GONE) continue;
             record.tileView.setDual(record.tile.supportsDualTargets());
+            if (record.tileView.getVisibility() == GONE) continue;
             final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
             final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight;
             record.tileView.measure(exactly(cw), exactly(ch));
@@ -425,6 +427,14 @@
         }
     }
 
+    private void setDetailRecord(Record r) {
+        if (r == mDetailRecord) return;
+        mDetailRecord = r;
+        final boolean scanState = mDetailRecord instanceof TileRecord
+                && ((TileRecord) mDetailRecord).scanState;
+        fireScanStateChanged(scanState);
+    }
+
     private class H extends Handler {
         private static final int SHOW_DETAIL = 1;
         private static final int SET_TILE_VISIBILITY = 2;
@@ -448,12 +458,13 @@
         QSTileView tileView;
         int row;
         int col;
+        boolean scanState;
     }
 
     private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() {
         public void onAnimationEnd(Animator animation) {
             mDetailContent.removeAllViews();
-            mDetailRecord = null;
+            setDetailRecord(null);
         };
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 6975541..409cc46 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -286,6 +286,7 @@
         public Drawable icon;
         public String label;
         public String contentDescription;
+        public String dualLabelContentDescription;
 
         public boolean copyTo(State other) {
             if (other == null) throw new IllegalArgumentException();
@@ -294,12 +295,15 @@
                     || other.iconId != iconId
                     || !Objects.equals(other.icon, icon)
                     || !Objects.equals(other.label, label)
-                    || !Objects.equals(other.contentDescription, contentDescription);
+                    || !Objects.equals(other.contentDescription, contentDescription)
+                    || !Objects.equals(other.dualLabelContentDescription,
+                    dualLabelContentDescription);
             other.visible = visible;
             other.iconId = iconId;
             other.icon = icon;
             other.label = label;
             other.contentDescription = contentDescription;
+            other.dualLabelContentDescription = dualLabelContentDescription;
             return changed;
         }
 
@@ -315,6 +319,7 @@
             sb.append(",icon=").append(icon);
             sb.append(",label=").append(label);
             sb.append(",contentDescription=").append(contentDescription);
+            sb.append(",dualLabelContentDescription=").append(dualLabelContentDescription);
             return sb.append(']');
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 597bb93..2cc1f07 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -87,6 +87,7 @@
 
     private void recreateLabel() {
         CharSequence labelText = null;
+        CharSequence labelDescription = null;
         if (mLabel != null) {
             labelText = mLabel.getText();
             removeView(mLabel);
@@ -94,6 +95,7 @@
         }
         if (mDualLabel != null) {
             labelText = mDualLabel.getText();
+            labelDescription = mLabel.getContentDescription();
             removeView(mDualLabel);
             mDualLabel = null;
         }
@@ -113,6 +115,9 @@
             if (labelText != null) {
                 mDualLabel.setText(labelText);
             }
+            if (labelDescription != null) {
+                mDualLabel.setContentDescription(labelDescription);
+            }
             addView(mDualLabel);
         } else {
             mLabel = new TextView(mContext);
@@ -228,6 +233,7 @@
         }
         if (mDual) {
             mDualLabel.setText(state.label);
+            mDualLabel.setContentDescription(state.dualLabelContentDescription);
         } else {
             mLabel.setText(state.label);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 1b2c0b0..19b9ec1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -114,6 +114,12 @@
         }
         state.contentDescription = mContext.getString(
                 R.string.accessibility_quick_settings_bluetooth, stateContentDescription);
+        String bluetoothName = state.label;
+        if (connected) {
+            bluetoothName = state.dualLabelContentDescription = mContext.getString(
+                    R.string.accessibility_bluetooth_name, state.label);
+        }
+        state.dualLabelContentDescription = bluetoothName;
     }
 
     private final BluetoothController.Callback mCallback = new BluetoothController.Callback() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
deleted file mode 100644
index a308e84..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
+++ /dev/null
@@ -1,115 +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.systemui.qs.tiles;
-
-import android.app.ActivityManagerNative;
-import android.app.AlertDialog;
-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;
-import android.view.WindowManagerGlobal;
-
-import com.android.systemui.R;
-import com.android.systemui.qs.GlobalSetting;
-import com.android.systemui.qs.QSTile;
-
-/** Quick settings tile: Bug report **/
-public class BugreportTile extends QSTile<QSTile.State> {
-
-    private final GlobalSetting mSetting;
-
-    public BugreportTile(Host host) {
-        super(host);
-        mSetting = new GlobalSetting(mContext, mHandler, Global.BUGREPORT_IN_POWER_MENU) {
-            @Override
-            protected void handleValueChanged(int value) {
-                handleRefreshState(null);
-            }
-        };
-    }
-
-    @Override
-    protected State newTileState() {
-        return new State();
-    }
-
-    @Override
-    public void setListening(boolean listening) {
-        mSetting.setListening(listening);
-    }
-
-    @Override
-    protected void handleClick() {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mHost.collapsePanels();
-                mUiHandler.post(mShowDialog);
-            }
-        });
-    }
-
-    @Override
-    protected void handleUpdateState(State state, Object pushArg) {
-        state.visible = mSetting.getValue() != 0;
-        state.iconId = R.drawable.ic_qs_bugreport;
-        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() {
-        @Override
-        public void run() {
-            final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
-            builder.setPositiveButton(com.android.internal.R.string.report, new OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    if (which == DialogInterface.BUTTON_POSITIVE) {
-                        // Add a little delay before executing, to give the
-                        // dialog a chance to go away before it takes a
-                        // screenshot.
-                        mHandler.postDelayed(new Runnable() {
-                            @Override public void run() {
-                                try {
-                                    ActivityManagerNative.getDefault().requestBugReport();
-                                } catch (RemoteException e) {
-                                }
-                            }
-                        }, 500);
-                    }
-                }
-            });
-            builder.setMessage(com.android.internal.R.string.bugreport_message);
-            builder.setTitle(com.android.internal.R.string.bugreport_title);
-            builder.setCancelable(true);
-            final Dialog dialog = builder.create();
-            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-            try {
-                WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
-            } catch (RemoteException e) {
-            }
-            dialog.show();
-        }
-    };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 531ac31..6b3e871 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -37,8 +37,8 @@
 
 /** Quick settings tile: Cast **/
 public class CastTile extends QSTile<QSTile.BooleanState> {
-    private static final Intent WIFI_DISPLAY_SETTINGS =
-            new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+    private static final Intent CAST_SETTINGS =
+            new Intent(Settings.ACTION_CAST_SETTINGS);
 
     private final CastController mController;
     private final CastDetailAdapter mDetailAdapter;
@@ -144,7 +144,7 @@
 
         @Override
         public Intent getSettingsIntent() {
-            return WIFI_DISPLAY_SETTINGS;
+            return CAST_SETTINGS;
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 21254d4..edb5932 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -29,6 +29,8 @@
     private final SecureSetting mSetting;
     private final UsageTracker mUsageTracker;
 
+    private boolean mListening;
+
     public ColorInversionTile(Host host) {
         super(host);
 
@@ -36,18 +38,25 @@
                 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
             @Override
             protected void handleValueChanged(int value) {
-                handleRefreshState(value);
                 mUsageTracker.trackUsage();
+                if (mListening) {
+                    handleRefreshState(value);
+                }
             }
         };
         mUsageTracker = new UsageTracker(host.getContext(), ColorInversionTile.class);
+        if (mSetting.getValue() != 0 && !mUsageTracker.isRecentlyUsed()) {
+            mUsageTracker.trackUsage();
+        }
         mUsageTracker.setListening(true);
+        mSetting.setListening(true);
     }
 
     @Override
     protected void handleDestroy() {
         super.handleDestroy();
         mUsageTracker.setListening(false);
+        mSetting.setListening(false);
     }
 
     @Override
@@ -57,7 +66,7 @@
 
     @Override
     public void setListening(boolean listening) {
-        mSetting.setListening(listening);
+        mListening = listening;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 5651d49..a8bf026 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -132,8 +132,12 @@
         }
         state.contentDescription = mContext.getString(
                 R.string.accessibility_quick_settings_wifi,
-                signalContentDescription,
-                state.connected ? state.label : "");
+                signalContentDescription);
+        String wifiName = state.label;
+        if (state.connected) {
+            wifiName = r.getString(R.string.accessibility_wifi_name, state.label);
+        }
+        state.dualLabelContentDescription = wifiName;
     }
 
     private static String removeDoubleQuotes(String string) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index 667faa7..f0bdfa2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -53,7 +53,7 @@
 
     // Log function
     static final float XScale = 1.75f;  // The large the XScale, the longer the flat area of the curve
-    static final float LogBase = 300;
+    static final float LogBase = 3000;
     static final int PrecisionSteps = 250;
     static float[] xp;
     static float[] px;
@@ -84,7 +84,7 @@
                 left + size, mStackRect.top + size);
 
         // Update the affiliation offsets
-        float visibleTaskPct = 0.55f;
+        float visibleTaskPct = 0.5f;
         mWithinAffiliationOffset = mConfig.taskBarHeight;
         mBetweenAffiliationOffset = (int) (visibleTaskPct * mTaskRect.height());
     }
@@ -312,4 +312,4 @@
         }
         return px[xFloorIndex] + pFraction;
     }
-}
\ No newline at end of file
+}
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 5914b39..e514c90 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -21,12 +21,14 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Color;
+import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewOutlineProvider;
 import android.view.animation.AccelerateInterpolator;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
@@ -57,7 +59,7 @@
     ObjectAnimator mDimAnimator;
     float mMaxDimScale;
     int mDim;
-    AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(1.25f);
+    AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(1f);
     PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.MULTIPLY);
 
     Task mTask;
@@ -129,6 +131,14 @@
         mHeaderView = (TaskViewHeader) findViewById(R.id.task_view_bar);
         mThumbnailView = (TaskViewThumbnail) findViewById(R.id.task_view_thumbnail);
         mActionButtonView = findViewById(R.id.lock_to_app_fab);
+        mActionButtonView.setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                // Set the outline to match the FAB background
+                outline.setOval(0, 0, mActionButtonView.getWidth(),
+                        mActionButtonView.getHeight());
+            }
+        });
         if (mFooterView != null) {
             mFooterView.setCallbacks(this);
         }
@@ -469,7 +479,8 @@
             boolean occludesLaunchTarget) {
         if (isLaunchingTask) {
             // Disable the thumbnail clip and animate the bar out for the window animation out
-            mHeaderView.startLaunchTaskAnimation(mThumbnailView.disableTaskBarClipAsRunnable(), r);
+            mHeaderView.startLaunchTaskAnimation(mThumbnailView.disableTaskBarClipAsRunnable(), r,
+                    mIsFocused);
             // Animate the thumbnail alpha back into full opacity for the window animation out
             mThumbnailView.startLaunchTaskAnimation();
 
@@ -624,7 +635,7 @@
     public void setDim(int dim) {
         mDim = dim;
         // Defer setting hardware layers if we have not yet measured, or there is no dim to draw
-        if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0 && dim > 0) {
+        if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
             if (mDimAnimator != null) {
                 mDimAnimator.removeAllListeners();
                 mDimAnimator.cancel();
@@ -828,6 +839,10 @@
                 } else if (v == mHeaderView.mDismissButton) {
                     dismissTask();
                 } else {
+                    if (v == mActionButtonView) {
+                        // Reset the translation of the action button before we animate it out
+                        mActionButtonView.setTranslationZ(0f);
+                    }
                     mCb.onTaskViewClicked(tv, tv.getTask(),
                             (v == mFooterView || v == mActionButtonView));
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 4b09549..c7198fe 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -18,7 +18,9 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -59,7 +61,8 @@
     ColorDrawable mBackgroundColor;
     Drawable mLightDismissDrawable;
     Drawable mDarkDismissDrawable;
-    ValueAnimator mBackgroundColorAnimator;
+    AnimatorSet mFocusAnimator;
+    ValueAnimator backgroundColorAnimator;
 
     boolean mIsFullscreen;
     boolean mCurrentPrimaryColorIsDark;
@@ -117,6 +120,14 @@
 
     @Override
     protected void onFinishInflate() {
+        // Set the outline provider
+        setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                outline.setRect(0, 0, getMeasuredWidth(), getMeasuredHeight());
+            }
+        });
+
         // Initialize the icon and description views
         mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
         mActivityDescription = (TextView) findViewById(R.id.activity_description);
@@ -211,23 +222,29 @@
     void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) {
         // Animate the task bar of the first task view
         setVisibility(View.VISIBLE);
-        setTranslationY(-getMeasuredHeight());
+        setAlpha(0f);
         animate()
-                .translationY(0)
+                .alpha(1f)
                 .setStartDelay(delay)
-                .setInterpolator(mConfig.fastOutSlowInInterpolator)
+                .setInterpolator(mConfig.linearOutSlowInInterpolator)
                 .setDuration(mConfig.taskBarEnterAnimDuration)
                 .withEndAction(postAnimRunnable)
+                .withLayer()
                 .start();
     }
 
     /** Animates this task bar as it exits recents */
-    void startLaunchTaskAnimation(Runnable preAnimRunnable, final Runnable postAnimRunnable) {
+    void startLaunchTaskAnimation(Runnable preAnimRunnable, final Runnable postAnimRunnable,
+            boolean isFocused) {
+        if (isFocused) {
+            onTaskViewFocusChanged(false);
+        }
+
         // Animate the task bar out of the first task view
         animate()
-                .translationY(-getMeasuredHeight())
+                .alpha(0f)
                 .setStartDelay(0)
-                .setInterpolator(mConfig.fastOutLinearInInterpolator)
+                .setInterpolator(mConfig.linearOutSlowInInterpolator)
                 .setDuration(mConfig.taskBarExitAnimDuration)
                 .withStartAction(preAnimRunnable)
                 .withEndAction(new Runnable() {
@@ -236,6 +253,7 @@
                         post(postAnimRunnable);
                     }
                 })
+                .withLayer()
                 .start();
     }
 
@@ -278,10 +296,10 @@
     /** Notifies the associated TaskView has been focused. */
     void onTaskViewFocusChanged(boolean focused) {
         boolean isRunning = false;
-        if (mBackgroundColorAnimator != null) {
-            isRunning = mBackgroundColorAnimator.isRunning();
-            mBackgroundColorAnimator.removeAllUpdateListeners();
-            mBackgroundColorAnimator.cancel();
+        if (mFocusAnimator != null) {
+            isRunning = mFocusAnimator.isRunning();
+            mFocusAnimator.removeAllListeners();
+            mFocusAnimator.cancel();
         }
         if (focused) {
             int secondaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
@@ -302,42 +320,54 @@
             // Pulse the background color
             int currentColor = mBackgroundColor.getColor();
             int lightPrimaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
-            mBackgroundColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), lightPrimaryColor,
-                    currentColor);
-            mBackgroundColorAnimator.addListener(new AnimatorListenerAdapter() {
+            ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(),
+                    lightPrimaryColor, currentColor);
+            backgroundColor.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationStart(Animator animation) {
-                    mBackground.setState(new int[] {});
+                    mBackground.setState(new int[]{});
                 }
             });
-            mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            backgroundColor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                 @Override
                 public void onAnimationUpdate(ValueAnimator animation) {
                     mBackgroundColor.setColor((Integer) animation.getAnimatedValue());
                 }
             });
-            mBackgroundColorAnimator.setRepeatCount(ValueAnimator.INFINITE);
-            mBackgroundColorAnimator.setRepeatMode(ValueAnimator.REVERSE);
-            mBackgroundColorAnimator.setStartDelay(750);
-            mBackgroundColorAnimator.setDuration(750);
-            mBackgroundColorAnimator.start();
+            backgroundColor.setRepeatCount(ValueAnimator.INFINITE);
+            backgroundColor.setRepeatMode(ValueAnimator.REVERSE);
+            // Pulse the translation
+            ObjectAnimator translation = ObjectAnimator.ofFloat(this, "translationZ", 15f);
+            translation.setRepeatCount(ValueAnimator.INFINITE);
+            translation.setRepeatMode(ValueAnimator.REVERSE);
+
+            mFocusAnimator = new AnimatorSet();
+            mFocusAnimator.playTogether(backgroundColor, translation);
+            mFocusAnimator.setStartDelay(750);
+            mFocusAnimator.setDuration(750);
+            mFocusAnimator.start();
         } else {
             if (isRunning) {
                 // Restore the background color
                 int currentColor = mBackgroundColor.getColor();
-                mBackgroundColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), currentColor,
-                        mCurrentPrimaryColor);
-                mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(),
+                        currentColor, mCurrentPrimaryColor);
+                backgroundColor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                     @Override
                     public void onAnimationUpdate(ValueAnimator animation) {
                         mBackgroundColor.setColor((Integer) animation.getAnimatedValue());
                     }
                 });
-                mBackgroundColorAnimator.setRepeatCount(0);
-                mBackgroundColorAnimator.setDuration(150);
-                mBackgroundColorAnimator.start();
+                // Restore the translation
+                ObjectAnimator translation = ObjectAnimator.ofFloat(this, "translationZ", 0f);
+
+                mFocusAnimator = new AnimatorSet();
+                mFocusAnimator.playTogether(backgroundColor, translation);
+                mFocusAnimator.setDuration(150);
+                mFocusAnimator.start();
             } else {
                 mBackground.setState(new int[] {});
+                setTranslationZ(0f);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index d4c8ce3..d9fea47 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -164,7 +164,8 @@
             .setContentTitle(r.getString(R.string.screenshot_saving_title))
             .setContentText(r.getString(R.string.screenshot_saving_text))
             .setSmallIcon(R.drawable.stat_notify_image)
-            .setWhen(now);
+            .setWhen(now)
+            .setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color));
 
         mNotificationStyle = new Notification.BigPictureStyle()
             .bigPicture(preview);
@@ -177,7 +178,9 @@
                 .setContentText(r.getString(R.string.screenshot_saving_text))
                 .setSmallIcon(R.drawable.stat_notify_image)
                 .setCategory(Notification.CATEGORY_PROGRESS)
-                .setWhen(now);
+                .setWhen(now)
+                .setColor(r.getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
 
         mNotificationBuilder.setPublicVersion(mPublicNotificationBuilder.build());
 
@@ -304,7 +307,9 @@
                 .setContentText(r.getString(R.string.screenshot_saved_text))
                 .setContentIntent(PendingIntent.getActivity(params.context, 0, launchIntent, 0))
                 .setWhen(now)
-                .setAutoCancel(true);
+                .setAutoCancel(true)
+                .setColor(r.getColor(
+                        com.android.internal.R.color.system_notification_accent_color));;
 
             // Update the text in the public version as well
             mPublicNotificationBuilder
@@ -312,7 +317,9 @@
                 .setContentText(r.getString(R.string.screenshot_saved_text))
                 .setContentIntent(PendingIntent.getActivity(params.context, 0, launchIntent, 0))
                 .setWhen(now)
-                .setAutoCancel(true);
+                .setAutoCancel(true)
+                .setColor(r.getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
 
             mNotificationBuilder.setPublicVersion(mPublicNotificationBuilder.build());
 
@@ -717,7 +724,9 @@
             .setWhen(System.currentTimeMillis())
             .setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen
             .setCategory(Notification.CATEGORY_ERROR)
-            .setAutoCancel(true);
+            .setAutoCancel(true)
+            .setColor(context.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
         Notification n =
             new Notification.BigTextStyle(b)
                 .bigText(r.getString(R.string.screenshot_failed_text))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 152bfdc..32fb567 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -139,7 +139,7 @@
                 mOpaque = res.getColor(R.color.system_bar_background_opaque);
                 mSemiTransparent = res.getColor(R.color.system_bar_background_semi_transparent);
                 mTransparent = res.getColor(R.color.system_bar_background_transparent);
-                mWarning = res.getColor(R.color.system_bar_background_warning);
+                mWarning = res.getColor(com.android.internal.R.color.battery_saver_mode_color);
             }
             mGradient = res.getDrawable(gradientResourceId);
             mInterpolator = new LinearInterpolator();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 00d01f9..0905bb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -36,7 +36,6 @@
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.statusbar.ExpandableView;
@@ -160,6 +159,7 @@
     private boolean mShadeEmpty;
 
     private boolean mQsScrimEnabled = true;
+    private boolean mLastAnnouncementWasQuickSettings;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -426,8 +426,8 @@
     @Override
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
         if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
-            event.getText()
-                    .add(getContext().getString(R.string.accessibility_desc_notification_shade));
+            event.getText().add(getKeyguardOrLockScreenString());
+            mLastAnnouncementWasQuickSettings = false;
             return true;
         }
 
@@ -994,6 +994,10 @@
             setQsExpanded(true);
         } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
             setQsExpanded(false);
+            if (mLastAnnouncementWasQuickSettings && !mTracking) {
+                announceForAccessibility(getKeyguardOrLockScreenString());
+                mLastAnnouncementWasQuickSettings = false;
+            }
         }
         mQsExpansionHeight = height;
         mHeader.setExpansion(getHeaderExpansionFraction());
@@ -1007,6 +1011,22 @@
                 && !mStackScrollerOverscrolling && mQsScrimEnabled) {
             mQsNavbarScrim.setAlpha(getQsExpansionFraction());
         }
+
+        // Upon initialisation when we are not layouted yet we don't want to announce that we are
+        // fully expanded, hence the != 0.0f check.
+        if (height != 0.0f && mQsFullyExpanded && !mLastAnnouncementWasQuickSettings) {
+            announceForAccessibility(getContext().getString(
+                    R.string.accessibility_desc_quick_settings));
+            mLastAnnouncementWasQuickSettings = true;
+        }
+    }
+
+    private String getKeyguardOrLockScreenString() {
+        if (mStatusBarState == StatusBarState.KEYGUARD) {
+            return getContext().getString(R.string.accessibility_desc_lock_screen);
+        } else {
+            return getContext().getString(R.string.accessibility_desc_notification_shade);
+        }
     }
 
     private void updateNotificationScrim(float height) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 39b2022..8bc7dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.graphics.Outline;
 import android.graphics.Rect;
+import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.TypedValue;
@@ -68,6 +69,7 @@
     private View mQsDetailHeader;
     private TextView mQsDetailHeaderTitle;
     private Switch mQsDetailHeaderSwitch;
+    private ImageView mQsDetailHeaderProgress;
     private View mEmergencyCallsOnly;
     private TextView mBatteryLevel;
     private TextView mAlarmStatus;
@@ -137,6 +139,7 @@
         mQsDetailHeader.setAlpha(0);
         mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
         mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
+        mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress);
         mEmergencyCallsOnly = findViewById(R.id.header_emergency_calls_only);
         mBatteryLevel = (TextView) findViewById(R.id.battery_level);
         mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
@@ -658,6 +661,8 @@
     }
 
     private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
+        private boolean mScanState;
+
         @Override
         public void onToggleStateChanged(final boolean state) {
             post(new Runnable() {
@@ -693,7 +698,16 @@
         }
 
         private void handleScanStateChanged(boolean state) {
-            // TODO - waiting on framework asset
+            if (mScanState == state) return;
+            mScanState = state;
+            final Animatable anim = (Animatable) mQsDetailHeaderProgress.getDrawable();
+            if (state) {
+                mQsDetailHeaderProgress.animate().alpha(1f);
+                anim.start();
+            } else {
+                mQsDetailHeaderProgress.animate().alpha(0f);
+                anim.stop();
+            }
         }
 
         private void handleShowingDetail(final QSTile.DetailAdapter detail) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index e9581fc..10f457a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -22,6 +22,7 @@
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.hardware.input.InputManager;
+import android.os.Bundle;
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -33,10 +34,14 @@
 import android.view.SoundEffectConstants;
 import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ImageView;
 
 import com.android.systemui.R;
 
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
+
 public class KeyButtonView extends ImageView {
     private static final String TAG = "StatusBar.KeyButtonView";
     private static final boolean DEBUG = false;
@@ -95,6 +100,35 @@
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
     }
 
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        if (mCode != 0) {
+            info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, null));
+            if (mSupportsLongpress) {
+                info.addAction(
+                        new AccessibilityNodeInfo.AccessibilityAction(ACTION_LONG_CLICK, null));
+            }
+        }
+    }
+
+    @Override
+    public boolean performAccessibilityAction(int action, Bundle arguments) {
+        if (action == ACTION_CLICK && mCode != 0) {
+            sendEvent(KeyEvent.ACTION_DOWN, 0, SystemClock.uptimeMillis());
+            sendEvent(KeyEvent.ACTION_UP, 0);
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
+            playSoundEffect(SoundEffectConstants.CLICK);
+            return true;
+        } else if (action == ACTION_LONG_CLICK && mCode != 0 && mSupportsLongpress) {
+            sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
+            sendEvent(KeyEvent.ACTION_UP, 0);
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
+            return true;
+        }
+        return super.performAccessibilityAction(action, arguments);
+    }
+
     public void setQuiescentAlpha(float alpha, boolean animate) {
         mAnimateToQuiescent.cancel();
         alpha = Math.min(Math.max(alpha, 0), 1);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 4e9f37d..15a7047 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -602,6 +602,8 @@
             mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
             mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
             mDataSignalIconId = R.drawable.stat_sys_signal_null;
+            mContentDescriptionPhoneSignal = mContext.getString(
+                    AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
         } else {
             if (mSignalStrength == null) {
                 if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
@@ -665,8 +667,7 @@
                         mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
                         mDataTypeIconId = 0;
                         mQSDataTypeIconId = 0;
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_gprs);
+                        mContentDescriptionDataType = "";
                         break;
                     } else {
                         // fall through
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 47e3e73..d53aa47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -508,9 +508,9 @@
             setTitle(R.string.guest_exit_guest_dialog_title);
             setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
             setButton(DialogInterface.BUTTON_NEGATIVE,
-                    context.getString(android.R.string.no), this);
+                    context.getString(android.R.string.cancel), this);
             setButton(DialogInterface.BUTTON_POSITIVE,
-                    context.getString(android.R.string.yes), this);
+                    context.getString(R.string.guest_exit_guest_dialog_remove), this);
             setCanceledOnTouchOutside(false);
             mGuestId = guestId;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 481266b..dce5c37 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -309,7 +309,8 @@
                 pi = PendingIntent.getBroadcastAsUser(mContext, 0, intent, 0,
                         UserHandle.CURRENT);
             }
-
+            mUsbStorageNotification.color = mContext.getResources().getColor(
+                    com.android.internal.R.color.system_notification_accent_color);
             mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
             mUsbStorageNotification.visibility = Notification.VISIBILITY_PUBLIC;
             mUsbStorageNotification.category = Notification.CATEGORY_SYSTEM;
@@ -403,6 +404,8 @@
             }
 
             mMediaStorageNotification.icon = icon;
+            mMediaStorageNotification.color = mContext.getResources().getColor(
+                    com.android.internal.R.color.system_notification_accent_color);
             mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
             mMediaStorageNotification.visibility = Notification.VISIBILITY_PUBLIC;
             mMediaStorageNotification.category = Notification.CATEGORY_SYSTEM;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index b05c242..51876b8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -37,7 +37,7 @@
 import android.media.ToneGenerator;
 import android.media.VolumeProvider;
 import android.media.session.MediaController;
-import android.media.session.MediaController.VolumeInfo;
+import android.media.session.MediaController.AudioInfo;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
@@ -537,8 +537,8 @@
             if (mStreamControls != null) {
                 StreamControl sc = mStreamControls.get(streamType);
                 if (sc != null && sc.controller != null) {
-                    VolumeInfo vi = sc.controller.getVolumeInfo();
-                    return vi.getMaxVolume();
+                    AudioInfo ai = sc.controller.getAudioInfo();
+                    return ai.getMaxVolume();
                 }
             }
             return -1;
@@ -554,8 +554,8 @@
             if (mStreamControls != null) {
                 StreamControl sc = mStreamControls.get(streamType);
                 if (sc != null && sc.controller != null) {
-                    VolumeInfo vi = sc.controller.getVolumeInfo();
-                    return vi.getCurrentVolume();
+                    AudioInfo ai = sc.controller.getAudioInfo();
+                    return ai.getCurrentVolume();
                 }
             }
             return -1;
@@ -990,7 +990,7 @@
                     // We still don't have one, ignore the command.
                     Log.w(mTag, "sent remote volume change without a controller!");
                 } else {
-                    VolumeInfo vi = controller.getVolumeInfo();
+                    AudioInfo vi = controller.getAudioInfo();
                     index = vi.getCurrentVolume();
                     max = vi.getMaxVolume();
                     if ((vi.getVolumeControl() & VolumeProvider.VOLUME_CONTROL_FIXED) != 0) {
@@ -1362,7 +1362,7 @@
     };
 
     private final MediaController.Callback mMediaControllerCb = new MediaController.Callback() {
-        public void onVolumeInfoChanged(VolumeInfo info) {
+        public void onAudioInfoChanged(AudioInfo info) {
             onRemoteVolumeUpdateIfShown();
         }
     };
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 964acbd..73358c8 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -3559,6 +3559,10 @@
         if (transitionId != -1 && transitionId != R.transition.no_transition) {
             TransitionInflater inflater = TransitionInflater.from(getContext());
             transition = inflater.inflateTransition(transitionId);
+            if (transition instanceof TransitionSet &&
+                    ((TransitionSet)transition).getTransitionCount() == 0) {
+                transition = null;
+            }
         }
         return transition;
     }
diff --git a/policy/src/com/android/internal/policy/impl/PolicyControl.java b/policy/src/com/android/internal/policy/impl/PolicyControl.java
index ffdb520..9abd906 100644
--- a/policy/src/com/android/internal/policy/impl/PolicyControl.java
+++ b/policy/src/com/android/internal/policy/impl/PolicyControl.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.policy.impl;
 
+import android.app.ActivityManager;
 import android.content.Context;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -104,8 +105,9 @@
     }
 
     public static boolean disableImmersiveConfirmation(String pkg) {
-        return sImmersivePreconfirmationsFilter != null
-                && sImmersivePreconfirmationsFilter.matches(pkg);
+        return (sImmersivePreconfirmationsFilter != null
+                && sImmersivePreconfirmationsFilter.matches(pkg))
+                || ActivityManager.isRunningInTestHarness();
     }
 
     public static void reloadFromSetting(Context context) {
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 7db85f2..3cda6de 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -1868,7 +1868,7 @@
         }
     }
 
-    static void sendBufferNotification(int id) {
+    static void sendBufferNotification(long id) {
         synchronized(mAllocationMap) {
             Allocation a = mAllocationMap.get(new Long(id));
 
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 340efef..6c5c508 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -1156,7 +1156,12 @@
                 }
 
                 if (msg == RS_MESSAGE_TO_CLIENT_NEW_BUFFER) {
-                    Allocation.sendBufferNotification(subID);
+                    if (mRS.nContextGetUserMessage(mRS.mContext, rbuf) !=
+                        RS_MESSAGE_TO_CLIENT_NEW_BUFFER) {
+                        throw new RSDriverException("Error processing message from RenderScript.");
+                    }
+                    long bufferID = ((long)rbuf[1] << 32L) + ((long)rbuf[0] & 0xffffffffL);
+                    Allocation.sendBufferNotification(bufferID);
                     continue;
                 }
 
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 16df377..13a649a 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -222,7 +222,7 @@
 nDeviceCreate(JNIEnv *_env, jobject _this)
 {
     LOG_API("nDeviceCreate");
-    return (jlong)rsDeviceCreate();
+    return (jlong)(uintptr_t)rsDeviceCreate();
 }
 
 static void
@@ -243,7 +243,7 @@
 nContextCreate(JNIEnv *_env, jobject _this, jlong dev, jint ver, jint sdkVer, jint ct)
 {
     LOG_API("nContextCreate");
-    return (jlong)rsContextCreate((RsDevice)dev, ver, sdkVer, (RsContextType)ct, 0);
+    return (jlong)(uintptr_t)rsContextCreate((RsDevice)dev, ver, sdkVer, (RsContextType)ct, 0);
 }
 
 static jlong
@@ -267,7 +267,7 @@
     sc.samplesQ = samplesQ;
 
     LOG_API("nContextCreateGL");
-    return (jlong)rsContextCreateGL((RsDevice)dev, ver, sdkVer, sc, dpi);
+    return (jlong)(uintptr_t)rsContextCreateGL((RsDevice)dev, ver, sdkVer, sc, dpi);
 }
 
 static void
@@ -409,7 +409,7 @@
 nElementCreate(JNIEnv *_env, jobject _this, jlong con, jlong type, jint kind, jboolean norm, jint size)
 {
     LOG_API("nElementCreate, con(%p), type(%i), kind(%i), norm(%i), size(%i)", (RsContext)con, type, kind, norm, size);
-    return (jlong)rsElementCreate((RsContext)con, (RsDataType)type, (RsDataKind)kind, norm, size);
+    return (jlong)(uintptr_t)rsElementCreate((RsContext)con, (RsDataType)type, (RsDataKind)kind, norm, size);
 }
 
 static jlong
@@ -435,7 +435,7 @@
     const char **nameArray = names.c_str();
     size_t *sizeArray = names.c_str_len();
 
-    jlong id = (jlong)rsElementCreate2((RsContext)con,
+    jlong id = (jlong)(uintptr_t)rsElementCreate2((RsContext)con,
                                      (const RsElement *)ids, fieldCount,
                                      nameArray, fieldCount * sizeof(size_t),  sizeArray,
                                      (const uint32_t *)arraySizes, fieldCount);
@@ -445,7 +445,7 @@
     _env->ReleaseLongArrayElements(_ids, jIds, JNI_ABORT);
     _env->ReleaseIntArrayElements(_arraySizes, jArraySizes, JNI_ABORT);
 
-    return (jlong)id;
+    return (jlong)(uintptr_t)id;
 }
 
 static void
@@ -483,7 +483,7 @@
     rsaElementGetSubElements((RsContext)con, (RsElement)id, ids, names, arraySizes, (uint32_t)dataSize);
 
     for(uint32_t i = 0; i < dataSize; i++) {
-        const jlong id = (jlong)ids[i];
+        const jlong id = (jlong)(uintptr_t)ids[i];
         const jint arraySize = (jint)arraySizes[i];
         _env->SetObjectArrayElement(_names, i, _env->NewStringUTF(names[i]));
         _env->SetLongArrayRegion(_IDs, i, 1, &id);
@@ -504,7 +504,7 @@
     LOG_API("nTypeCreate, con(%p) eid(%p), x(%i), y(%i), z(%i), mips(%i), faces(%i), yuv(%i)",
             (RsContext)con, eid, dimx, dimy, dimz, mips, faces, yuv);
 
-    return (jlong)rsTypeCreate((RsContext)con, (RsElement)eid, dimx, dimy, dimz, mips, faces, yuv);
+    return (jlong)(uintptr_t)rsTypeCreate((RsContext)con, (RsElement)eid, dimx, dimy, dimz, mips, faces, yuv);
 }
 
 static void
@@ -521,7 +521,7 @@
     rsaTypeGetNativeData((RsContext)con, (RsType)id, typeData, 6);
 
     for(jint i = 0; i < elementCount; i ++) {
-        const jlong data = (jlong)typeData[i];
+        const jlong data = (jlong)(uintptr_t)typeData[i];
         _env->SetLongArrayRegion(_typeData, i, 1, &data);
     }
 }
@@ -532,7 +532,7 @@
 nAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mips, jint usage, jlong pointer)
 {
     LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)", (RsContext)con, (RsElement)type, mips, usage, (void *)pointer);
-    return (jlong) rsAllocationCreateTyped((RsContext)con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uintptr_t)pointer);
+    return (jlong)(uintptr_t) rsAllocationCreateTyped((RsContext)con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uintptr_t)pointer);
 }
 
 static void
@@ -600,7 +600,7 @@
 
     bitmap.lockPixels();
     const void* ptr = bitmap.getPixels();
-    jlong id = (jlong)rsAllocationCreateFromBitmap((RsContext)con,
+    jlong id = (jlong)(uintptr_t)rsAllocationCreateFromBitmap((RsContext)con,
                                                   (RsType)type, (RsAllocationMipmapControl)mip,
                                                   ptr, bitmap.getSize(), usage);
     bitmap.unlockPixels();
@@ -616,7 +616,7 @@
 
     bitmap.lockPixels();
     const void* ptr = bitmap.getPixels();
-    jlong id = (jlong)rsAllocationCreateTyped((RsContext)con,
+    jlong id = (jlong)(uintptr_t)rsAllocationCreateTyped((RsContext)con,
                                             (RsType)type, (RsAllocationMipmapControl)mip,
                                             (uint32_t)usage, (uintptr_t)ptr);
     bitmap.unlockPixels();
@@ -632,7 +632,7 @@
 
     bitmap.lockPixels();
     const void* ptr = bitmap.getPixels();
-    jlong id = (jlong)rsAllocationCubeCreateFromBitmap((RsContext)con,
+    jlong id = (jlong)(uintptr_t)rsAllocationCubeCreateFromBitmap((RsContext)con,
                                                       (RsType)type, (RsAllocationMipmapControl)mip,
                                                       ptr, bitmap.getSize(), usage);
     bitmap.unlockPixels();
@@ -810,7 +810,7 @@
 nAllocationGetType(JNIEnv *_env, jobject _this, jlong con, jlong a)
 {
     LOG_API("nAllocationGetType, con(%p), a(%p)", (RsContext)con, (RsAllocation)a);
-    return (jlong) rsaAllocationGetType((RsContext)con, (RsAllocation)a);
+    return (jlong)(uintptr_t) rsaAllocationGetType((RsContext)con, (RsAllocation)a);
 }
 
 static void
@@ -828,7 +828,7 @@
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
     ALOGV("______nFileA3D %p", asset);
 
-    jlong id = (jlong)rsaFileA3DCreateFromMemory((RsContext)con, asset->getBuffer(false), asset->getLength());
+    jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromMemory((RsContext)con, asset->getBuffer(false), asset->getLength());
     return id;
 }
 
@@ -846,7 +846,7 @@
         return 0;
     }
 
-    jlong id = (jlong)rsaFileA3DCreateFromAsset((RsContext)con, asset);
+    jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromAsset((RsContext)con, asset);
     return id;
 }
 
@@ -854,7 +854,7 @@
 nFileA3DCreateFromFile(JNIEnv *_env, jobject _this, jlong con, jstring fileName)
 {
     AutoJavaStringToUTF8 fileNameUTF(_env, fileName);
-    jlong id = (jlong)rsaFileA3DCreateFromFile((RsContext)con, fileNameUTF.c_str());
+    jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromFile((RsContext)con, fileNameUTF.c_str());
 
     return id;
 }
@@ -887,7 +887,7 @@
 nFileA3DGetEntryByIndex(JNIEnv *_env, jobject _this, jlong con, jlong fileA3D, jint index)
 {
     ALOGV("______nFileA3D %p", (RsFile) fileA3D);
-    jlong id = (jlong)rsaFileA3DGetEntryByIndex((RsContext)con, (uint32_t)index, (RsFile)fileA3D);
+    jlong id = (jlong)(uintptr_t)rsaFileA3DGetEntryByIndex((RsContext)con, (uint32_t)index, (RsFile)fileA3D);
     return id;
 }
 
@@ -898,7 +898,7 @@
                     jstring fileName, jfloat fontSize, jint dpi)
 {
     AutoJavaStringToUTF8 fileNameUTF(_env, fileName);
-    jlong id = (jlong)rsFontCreateFromFile((RsContext)con,
+    jlong id = (jlong)(uintptr_t)rsFontCreateFromFile((RsContext)con,
                                          fileNameUTF.c_str(), fileNameUTF.length(),
                                          fontSize, dpi);
 
@@ -912,7 +912,7 @@
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
     AutoJavaStringToUTF8 nameUTF(_env, name);
 
-    jlong id = (jlong)rsFontCreateFromMemory((RsContext)con,
+    jlong id = (jlong)(uintptr_t)rsFontCreateFromMemory((RsContext)con,
                                            nameUTF.c_str(), nameUTF.length(),
                                            fontSize, dpi,
                                            asset->getBuffer(false), asset->getLength());
@@ -934,7 +934,7 @@
         return 0;
     }
 
-    jlong id = (jlong)rsFontCreateFromMemory((RsContext)con,
+    jlong id = (jlong)(uintptr_t)rsFontCreateFromMemory((RsContext)con,
                                            str.c_str(), str.length(),
                                            fontSize, dpi,
                                            asset->getBuffer(false), asset->getLength());
@@ -1283,7 +1283,7 @@
 
     //rsScriptCSetText((RsContext)con, (const char *)script_ptr, length);
 
-    ret = (jlong)rsScriptCCreate((RsContext)con,
+    ret = (jlong)(uintptr_t)rsScriptCCreate((RsContext)con,
                                 resNameUTF.c_str(), resNameUTF.length(),
                                 cacheDirUTF.c_str(), cacheDirUTF.length(),
                                 (const char *)script_ptr, length);
@@ -1294,28 +1294,28 @@
                 _exception ? JNI_ABORT: 0);
     }
 
-    return (jlong)ret;
+    return (jlong)(uintptr_t)ret;
 }
 
 static jlong
 nScriptIntrinsicCreate(JNIEnv *_env, jobject _this, jlong con, jint id, jlong eid)
 {
     LOG_API("nScriptIntrinsicCreate, con(%p) id(%i) element(%p)", (RsContext)con, id, (void *)eid);
-    return (jlong)rsScriptIntrinsicCreate((RsContext)con, id, (RsElement)eid);
+    return (jlong)(uintptr_t)rsScriptIntrinsicCreate((RsContext)con, id, (RsElement)eid);
 }
 
 static jlong
 nScriptKernelIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot, jint sig)
 {
     LOG_API("nScriptKernelIDCreate, con(%p) script(%p), slot(%i), sig(%i)", (RsContext)con, (void *)sid, slot, sig);
-    return (jlong)rsScriptKernelIDCreate((RsContext)con, (RsScript)sid, slot, sig);
+    return (jlong)(uintptr_t)rsScriptKernelIDCreate((RsContext)con, (RsScript)sid, slot, sig);
 }
 
 static jlong
 nScriptFieldIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot)
 {
     LOG_API("nScriptFieldIDCreate, con(%p) script(%p), slot(%i)", (RsContext)con, (void *)sid, slot);
-    return (jlong)rsScriptFieldIDCreate((RsContext)con, (RsScript)sid, slot);
+    return (jlong)(uintptr_t)rsScriptFieldIDCreate((RsContext)con, (RsScript)sid, slot);
 }
 
 static jlong
@@ -1359,7 +1359,7 @@
         typesPtr[i] = (RsType)jTypesPtr[i];
     }
 
-    jlong id = (jlong)rsScriptGroupCreate((RsContext)con,
+    jlong id = (jlong)(uintptr_t)rsScriptGroupCreate((RsContext)con,
                                (RsScriptKernelID *)kernelsPtr, kernelsLen * sizeof(RsScriptKernelID),
                                (RsScriptKernelID *)srcPtr, srcLen * sizeof(RsScriptKernelID),
                                (RsScriptKernelID *)dstkPtr, dstkLen * sizeof(RsScriptKernelID),
@@ -1412,7 +1412,7 @@
                     jint depthFunc)
 {
     LOG_API("nProgramStoreCreate, con(%p)", (RsContext)con);
-    return (jlong)rsProgramStoreCreate((RsContext)con, colorMaskR, colorMaskG, colorMaskB, colorMaskA,
+    return (jlong)(uintptr_t)rsProgramStoreCreate((RsContext)con, colorMaskR, colorMaskG, colorMaskB, colorMaskA,
                                       depthMask, ditherEnable, (RsBlendSrcFunc)srcFunc,
                                       (RsBlendDstFunc)destFunc, (RsDepthFunc)depthFunc);
 }
@@ -1461,7 +1461,7 @@
     for(int i = 0; i < paramLen; ++i) {
         paramPtr[i] = (uintptr_t)jParamPtr[i];
     }
-    jlong ret = (jlong)rsProgramFragmentCreate((RsContext)con, shaderUTF.c_str(), shaderUTF.length(),
+    jlong ret = (jlong)(uintptr_t)rsProgramFragmentCreate((RsContext)con, shaderUTF.c_str(), shaderUTF.length(),
                                              nameArray, texCount, sizeArray,
                                              paramPtr, paramLen);
 
@@ -1493,7 +1493,7 @@
         paramPtr[i] = (uintptr_t)jParamPtr[i];
     }
 
-    jlong ret = (jlong)rsProgramVertexCreate((RsContext)con, shaderUTF.c_str(), shaderUTF.length(),
+    jlong ret = (jlong)(uintptr_t)rsProgramVertexCreate((RsContext)con, shaderUTF.c_str(), shaderUTF.length(),
                                            nameArray, texCount, sizeArray,
                                            paramPtr, paramLen);
 
@@ -1508,7 +1508,7 @@
 nProgramRasterCreate(JNIEnv *_env, jobject _this, jlong con, jboolean pointSprite, jint cull)
 {
     LOG_API("nProgramRasterCreate, con(%p), pointSprite(%i), cull(%i)", (RsContext)con, pointSprite, cull);
-    return (jlong)rsProgramRasterCreate((RsContext)con, pointSprite, (RsCullMode)cull);
+    return (jlong)(uintptr_t)rsProgramRasterCreate((RsContext)con, pointSprite, (RsCullMode)cull);
 }
 
 
@@ -1557,7 +1557,7 @@
                jint wrapS, jint wrapT, jint wrapR, jfloat aniso)
 {
     LOG_API("nSamplerCreate, con(%p)", (RsContext)con);
-    return (jlong)rsSamplerCreate((RsContext)con,
+    return (jlong)(uintptr_t)rsSamplerCreate((RsContext)con,
                                  (RsSamplerValue)magFilter,
                                  (RsSamplerValue)minFilter,
                                  (RsSamplerValue)wrapS,
@@ -1572,7 +1572,7 @@
 nPathCreate(JNIEnv *_env, jobject _this, jlong con, jint prim, jboolean isStatic, jlong _vtx, jlong _loop, jfloat q) {
     LOG_API("nPathCreate, con(%p)", (RsContext)con);
 
-    jlong id = (jlong)rsPathCreate((RsContext)con, (RsPathPrimitive)prim, isStatic,
+    jlong id = (jlong)(uintptr_t)rsPathCreate((RsContext)con, (RsPathPrimitive)prim, isStatic,
                                    (RsAllocation)_vtx,
                                    (RsAllocation)_loop, q);
     return id;
@@ -1600,7 +1600,7 @@
     jint primLen = _env->GetArrayLength(_prim);
     jint *primPtr = _env->GetIntArrayElements(_prim, NULL);
 
-    jlong id = (jlong)rsMeshCreate((RsContext)con,
+    jlong id = (jlong)(uintptr_t)rsMeshCreate((RsContext)con,
                                (RsAllocation *)vtxPtr, vtxLen,
                                (RsAllocation *)idxPtr, idxLen,
                                (uint32_t *)primPtr, primLen);
@@ -1640,7 +1640,7 @@
     rsaMeshGetVertices((RsContext)con, (RsMesh)mesh, allocs, (uint32_t)numVtxIDs);
 
     for(jint i = 0; i < numVtxIDs; i ++) {
-        const jlong alloc = (jlong)allocs[i];
+        const jlong alloc = (jlong)(uintptr_t)allocs[i];
         _env->SetLongArrayRegion(_ids, i, 1, &alloc);
     }
 
@@ -1658,7 +1658,7 @@
     rsaMeshGetIndices((RsContext)con, (RsMesh)mesh, allocs, prims, (uint32_t)numIndices);
 
     for(jint i = 0; i < numIndices; i ++) {
-        const jlong alloc = (jlong)allocs[i];
+        const jlong alloc = (jlong)(uintptr_t)allocs[i];
         const jint prim = (jint)prims[i];
         _env->SetLongArrayRegion(_idxIds, i, 1, &alloc);
         _env->SetIntArrayRegion(_primitives, i, 1, &prim);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index c44474d..5900612 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -871,6 +871,7 @@
                                 BackupManagerService.this, mActiveRestoreSession));
                     }
                 }
+                break;
             }
 
             case MSG_FULL_CONFIRMATION_TIMEOUT:
@@ -7538,6 +7539,9 @@
                 }
             }
 
+            // Clear any ongoing session timeout.
+            mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
+
             // If we have a PM token, we must under all circumstances be sure to
             // handshake when we've finished.
             if (mPmToken > 0) {
@@ -7545,6 +7549,11 @@
                 try {
                     mPackageManagerBinder.finishPackageInstall(mPmToken);
                 } catch (RemoteException e) { /* can't happen */ }
+            } else {
+                // We were invoked via an active restore session, not by the Package
+                // Manager, so start up the session timeout again.
+                mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT,
+                        TIMEOUT_RESTORE_INTERVAL);
             }
 
             // Kick off any work that may be needed regarding app widget restores
@@ -7558,11 +7567,6 @@
                 writeRestoreTokens();
             }
 
-            // Furthermore we need to reset the session timeout clock
-            mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
-            mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT,
-                    TIMEOUT_RESTORE_INTERVAL);
-
             // done; we can finally release the wakelock and be legitimately done.
             Slog.i(TAG, "Restore complete.");
             mWakelock.release();
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5bef4bf..67c01e5 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3602,6 +3602,8 @@
             notification.icon = icon;
             notification.flags = Notification.FLAG_AUTO_CANCEL;
             notification.tickerText = title;
+            notification.color = mContext.getResources().getColor(
+                    com.android.internal.R.color.system_notification_accent_color);
             notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
             notification.contentIntent = intent;
 
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index e0f9b9c..122786f 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -66,6 +66,7 @@
 import android.content.res.TypedArray;
 import android.database.ContentObserver;
 import android.inputmethodservice.InputMethodService;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
@@ -392,6 +393,7 @@
     private InputMethodInfo[] mIms;
     private int[] mSubtypeIds;
     private Locale mLastSystemLocale;
+    private boolean mShowImeWithHardKeyboard;
     private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
     private final IPackageManager mIPackageManager;
 
@@ -407,17 +409,25 @@
                     Settings.Secure.ENABLED_INPUT_METHODS), false, this);
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this);
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this);
         }
 
-        @Override public void onChange(boolean selfChange) {
+        @Override public void onChange(boolean selfChange, Uri uri) {
+            final Uri showImeUri =
+                    Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
             synchronized (mMethodMap) {
-                boolean enabledChanged = false;
-                String newEnabled = mSettings.getEnabledInputMethodsStr();
-                if (!mLastEnabled.equals(newEnabled)) {
-                    mLastEnabled = newEnabled;
-                    enabledChanged = true;
+                if (showImeUri.equals(uri)) {
+                    updateKeyboardFromSettingsLocked();
+                } else {
+                    boolean enabledChanged = false;
+                    String newEnabled = mSettings.getEnabledInputMethodsStr();
+                    if (!mLastEnabled.equals(newEnabled)) {
+                        mLastEnabled = newEnabled;
+                        enabledChanged = true;
+                    }
+                    updateInputMethodsFromSettingsLocked(enabledChanged);
                 }
-                updateFromSettingsLocked(enabledChanged);
             }
         }
     }
@@ -598,16 +608,14 @@
     private class HardKeyboardListener
             implements WindowManagerService.OnHardKeyboardStatusChangeListener {
         @Override
-        public void onHardKeyboardStatusChange(boolean available, boolean enabled) {
-            mHandler.sendMessage(mHandler.obtainMessage(
-                    MSG_HARD_KEYBOARD_SWITCH_CHANGED, available ? 1 : 0, enabled ? 1 : 0));
+        public void onHardKeyboardStatusChange(boolean available) {
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
+                        available ? 1 : 0));
         }
 
-        public void handleHardKeyboardStatusChange(boolean available,
-                boolean showImeWithHardKeyboard) {
+        public void handleHardKeyboardStatusChange(boolean available) {
             if (DEBUG) {
-                Slog.w(TAG, "HardKeyboardStatusChanged: available = " + available
-                        + ", showImeWithHardKeyboard= " + showImeWithHardKeyboard);
+                Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
             }
             synchronized(mMethodMap) {
                 if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
@@ -1580,6 +1588,8 @@
                     final CharSequence summary = InputMethodUtils.getImeAndSubtypeDisplayName(
                             mContext, imi, mCurrentSubtype);
 
+                    mImeSwitcherNotification.color = mContext.getResources().getColor(
+                            com.android.internal.R.color.system_notification_accent_color);
                     mImeSwitcherNotification.setLatestEventInfo(
                             mContext, title, summary, mImeSwitchPendingIntent);
                     if ((mNotificationManager != null)
@@ -1657,6 +1667,11 @@
     }
 
     void updateFromSettingsLocked(boolean enabledMayChange) {
+        updateInputMethodsFromSettingsLocked(enabledMayChange);
+        updateKeyboardFromSettingsLocked();
+    }
+
+    void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
         if (enabledMayChange) {
             List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
             for (int i=0; i<enabled.size(); i++) {
@@ -1710,6 +1725,18 @@
         // TODO: Make sure that mSwitchingController and mSettings are sharing the
         // the same enabled IMEs list.
         mSwitchingController.resetCircularListLocked(mContext);
+
+    }
+
+    public void updateKeyboardFromSettingsLocked() {
+        mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
+        if (mSwitchingDialog != null
+                && mSwitchingDialogTitleView != null
+                && mSwitchingDialog.isShowing()) {
+            final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
+                    com.android.internal.R.id.hard_keyboard_switch);
+            hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
+        }
     }
 
     /* package */ void setInputMethodLocked(String id, int subtypeId) {
@@ -2594,8 +2621,7 @@
 
             // --------------------------------------------------------------
             case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
-                mHardKeyboardListener.handleHardKeyboardStatusChange(
-                        msg.arg1 == 1, msg.arg2 == 1);
+                mHardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
                 return true;
         }
         return false;
@@ -2684,7 +2710,7 @@
             if (!map.containsKey(defaultImiId)) {
                 Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
                 if (chooseNewDefaultIMELocked()) {
-                    updateFromSettingsLocked(true);
+                    updateInputMethodsFromSettingsLocked(true);
                 }
             } else {
                 // Double check that the default IME is certainly enabled.
@@ -2811,11 +2837,11 @@
                             ? View.VISIBLE : View.GONE);
             final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
                     com.android.internal.R.id.hard_keyboard_switch);
-            hardKeySwitch.setChecked(mWindowManagerService.isShowImeWithHardKeyboardEnabled());
+            hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
             hardKeySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                 @Override
                 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                    mWindowManagerService.setShowImeWithHardKeyboard(isChecked);
+                    mSettings.setShowImeWithHardKeyboard(isChecked);
                     // Ensure that the input method dialog is dismissed when changing
                     // the hardware keyboard state.
                     hideInputMethodMenu();
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 64b0487..07cc864 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -69,6 +69,124 @@
         }
     }
 
+    private boolean filterEquals(IntentFilter f1, IntentFilter f2) {
+        int s1 = f1.countActions();
+        int s2 = f2.countActions();
+        if (s1 != s2) {
+            return false;
+        }
+        for (int i=0; i<s1; i++) {
+            if (!f2.hasAction(f1.getAction(i))) {
+                return false;
+            }
+        }
+        s1 = f1.countCategories();
+        s2 = f2.countCategories();
+        if (s1 != s2) {
+            return false;
+        }
+        for (int i=0; i<s1; i++) {
+            if (!f2.hasCategory(f1.getCategory(i))) {
+                return false;
+            }
+        }
+        s1 = f1.countDataTypes();
+        s2 = f2.countDataTypes();
+        if (s1 != s2) {
+            return false;
+        }
+        for (int i=0; i<s1; i++) {
+            if (!f2.hasExactDataType(f1.getDataType(i))) {
+                return false;
+            }
+        }
+        s1 = f1.countDataSchemes();
+        s2 = f2.countDataSchemes();
+        if (s1 != s2) {
+            return false;
+        }
+        for (int i=0; i<s1; i++) {
+            if (!f2.hasDataScheme(f1.getDataScheme(i))) {
+                return false;
+            }
+        }
+        s1 = f1.countDataAuthorities();
+        s2 = f2.countDataAuthorities();
+        if (s1 != s2) {
+            return false;
+        }
+        for (int i=0; i<s1; i++) {
+            if (!f2.hasDataAuthority(f1.getDataAuthority(i))) {
+                return false;
+            }
+        }
+        s1 = f1.countDataPaths();
+        s2 = f2.countDataPaths();
+        if (s1 != s2) {
+            return false;
+        }
+        for (int i=0; i<s1; i++) {
+            if (!f2.hasDataPath(f1.getDataPath(i))) {
+                return false;
+            }
+        }
+        s1 = f1.countDataSchemeSpecificParts();
+        s2 = f2.countDataSchemeSpecificParts();
+        if (s1 != s2) {
+            return false;
+        }
+        for (int i=0; i<s1; i++) {
+            if (!f2.hasDataSchemeSpecificPart(f1.getDataSchemeSpecificPart(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private ArrayList<F> collectFilters(F[] array, IntentFilter matching) {
+        ArrayList<F> res = null;
+        if (array != null) {
+            for (int i=0; i<array.length; i++) {
+                F cur = array[i];
+                if (cur == null) {
+                    break;
+                }
+                if (filterEquals(cur, matching)) {
+                    if (res == null) {
+                        res = new ArrayList<>();
+                    }
+                    res.add(cur);
+                }
+            }
+        }
+        return res;
+    }
+
+    public ArrayList<F> findFilters(IntentFilter matching) {
+        if (matching.countDataSchemes() == 1) {
+            // Fast case.
+            return collectFilters(mSchemeToFilter.get(matching.getDataScheme(0)), matching);
+        } else if (matching.countDataTypes() != 0 && matching.countActions() == 1) {
+            // Another fast case.
+            return collectFilters(mTypedActionToFilter.get(matching.getAction(0)), matching);
+        } else if (matching.countDataTypes() == 0 && matching.countDataSchemes() == 0
+                && matching.countActions() == 1) {
+            // Last fast case.
+            return collectFilters(mActionToFilter.get(matching.getAction(0)), matching);
+        } else {
+            ArrayList<F> res = null;
+            for (F cur : mFilters) {
+                if (filterEquals(cur, matching)) {
+                    if (res == null) {
+                        res = new ArrayList<>();
+                    }
+                    res.add(cur);
+                }
+            }
+            return res;
+        }
+    }
+
     public void removeFilter(F f) {
         removeFilterInternal(f);
         mFilters.remove(f);
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 6ab52c6..d1b4569 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -599,6 +599,8 @@
                 n.defaults = Notification.DEFAULT_LIGHTS;
                 n.flags = Notification.FLAG_ONGOING_EVENT;
                 n.when = 0;
+                n.color = context.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color);
                 n.setLatestEventInfo(
                         context,
                         context.getString(R.string.car_mode_disable_notification_title),
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 2a66baf..94d979e 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1700,6 +1700,8 @@
             subtitle = titleAndSubtitle.substring(index + 1);
         }
         UserHandle user = new UserHandle(userId);
+        n.color = mContext.getResources().getColor(
+                com.android.internal.R.color.system_notification_accent_color);
         n.setLatestEventInfo(mContext, title, subtitle,
                 PendingIntent.getActivityAsUser(mContext, 0, intent,
                         PendingIntent.FLAG_CANCEL_CURRENT, null, user));
@@ -2968,6 +2970,8 @@
                 UserHandle user = new UserHandle(userId);
                 final String notificationTitleFormat =
                         mContext.getText(R.string.notification_title).toString();
+                n.color = mContext.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color);
                 n.setLatestEventInfo(mContext,
                         String.format(notificationTitleFormat, account.name),
                         message, PendingIntent.getActivityAsUser(
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ecd8f11..05179a4 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1472,6 +1472,8 @@
                     notification.defaults = 0; // please be quiet
                     notification.sound = null;
                     notification.vibrate = null;
+                    notification.color = mContext.getResources().getColor(
+                            com.android.internal.R.color.system_notification_accent_color);
                     notification.setLatestEventInfo(context, text,
                             mContext.getText(R.string.heavy_weight_notification_detail),
                             PendingIntent.getActivityAsUser(mContext, 0, root.intent,
@@ -3434,6 +3436,70 @@
     }
 
     @Override
+    public final int startActivityAsCaller(IApplicationThread caller, String callingPackage,
+            Intent intent, String resolvedType, IBinder resultTo,
+            String resultWho, int requestCode, int startFlags,
+            String profileFile, ParcelFileDescriptor profileFd, Bundle options) {
+
+        // This is very dangerous -- it allows you to perform a start activity (including
+        // permission grants) as any app that may launch one of your own activities.  So
+        // we will only allow this to be done from activities that are part of the core framework,
+        // and then only when they are running as the system.
+        final ActivityRecord sourceRecord;
+        final int targetUid;
+        final String targetPackage;
+        synchronized (this) {
+            if (resultTo == null) {
+                throw new SecurityException("Must be called from an activity");
+            }
+            sourceRecord = mStackSupervisor.isInAnyStackLocked(resultTo);
+            if (sourceRecord == null) {
+                throw new SecurityException("Called with bad activity token: " + resultTo);
+            }
+            if (!sourceRecord.info.packageName.equals("android")) {
+                throw new SecurityException(
+                        "Must be called from an activity that is declared in the android package");
+            }
+            if (sourceRecord.app == null) {
+                throw new SecurityException("Called without a process attached to activity");
+            }
+            if (sourceRecord.app.uid != Process.SYSTEM_UID) {
+                // This is still okay, as long as this activity is running under the
+                // uid of the original calling activity.
+                if (sourceRecord.app.uid != sourceRecord.launchedFromUid) {
+                    throw new SecurityException(
+                            "Calling activity in uid " + sourceRecord.app.uid
+                                    + " must be system uid or original calling uid "
+                                    + sourceRecord.launchedFromUid);
+                }
+            }
+            targetUid = sourceRecord.launchedFromUid;
+            targetPackage = sourceRecord.launchedFromPackage;
+        }
+
+        // TODO: Switch to user app stacks here.
+        try {
+            int ret = mStackSupervisor.startActivityMayWait(null, targetUid, targetPackage, intent,
+                    resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
+                    null, null, null, null, options, UserHandle.getUserId(targetUid), null);
+            return ret;
+        } catch (SecurityException e) {
+            // XXX need to figure out how to propagate to original app.
+            // A SecurityException here is generally actually a fault of the original
+            // calling activity (such as a fairly granting permissions), so propagate it
+            // back to them.
+            /*
+            StringBuilder msg = new StringBuilder();
+            msg.append("While launching");
+            msg.append(intent.toString());
+            msg.append(": ");
+            msg.append(e.getMessage());
+            */
+            throw e;
+        }
+    }
+
+    @Override
     public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, String profileFile,
@@ -11402,6 +11468,7 @@
                 pw.println("  [-a] [-c] [-h] [cmd] ...");
                 pw.println("  cmd may be one of:");
                 pw.println("    a[ctivities]: activity stack state");
+                pw.println("    r[recents]: recent activities state");
                 pw.println("    b[roadcasts] [PACKAGE_NAME] [history [-s]]: broadcast state");
                 pw.println("    i[ntents] [PACKAGE_NAME]: pending intent state");
                 pw.println("    p[rocesses] [PACKAGE_NAME]: process state");
@@ -11435,6 +11502,10 @@
                 synchronized (this) {
                     dumpActivitiesLocked(fd, pw, args, opti, true, dumpClient, null);
                 }
+            } else if ("recents".equals(cmd) || "r".equals(cmd)) {
+                synchronized (this) {
+                    dumpRecentsLocked(fd, pw, args, opti, true, null);
+                }
             } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
                 String[] newArgs;
                 String name;
@@ -11578,6 +11649,11 @@
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
             }
+            dumpRecentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+            pw.println();
+            if (dumpAll) {
+                pw.println("-------------------------------------------------------------------------------");
+            }
             dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
             pw.println();
             if (dumpAll) {
@@ -11612,6 +11688,17 @@
             mStackSupervisor.dump(pw, "  ");
         }
 
+        if (!printedAnything) {
+            pw.println("  (nothing)");
+        }
+    }
+
+    void dumpRecentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+            int opti, boolean dumpAll, String dumpPackage) {
+        pw.println("ACTIVITY MANAGER RECENT ACTIVITIES (dumpsys activity recents)");
+
+        boolean printedAnything = false;
+
         if (mRecentTasks.size() > 0) {
             boolean printedHeader = false;
 
@@ -11625,9 +11712,6 @@
                     }
                 }
                 if (!printedHeader) {
-                    if (needSep) {
-                        pw.println();
-                    }
                     pw.println("  Recent tasks:");
                     printedHeader = true;
                     printedAnything = true;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index e528d57..abacb2d 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -575,6 +575,10 @@
 
     void makeFinishing() {
         if (!finishing) {
+            if (this == task.stack.getVisibleBehindActivity()) {
+                // A finishing activity should not remain as visible in the background
+                mStackSupervisor.requestVisibleBehindLocked(this, false);
+            }
             finishing = true;
             if (stopped) {
                 clearOptionsLocked();
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 1107139..931f448 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2659,13 +2659,20 @@
         }
 
         // A non-top activity is reporting a visibility change.
-        if (top.fullscreen || top.state != ActivityState.RESUMED || top.app == null ||
-                top.app.thread == null) {
+        if ((visible && (top.fullscreen || top.state != ActivityState.RESUMED)) ||
+                top.app == null || top.app.thread == null) {
             // Can't carry out this request.
             if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG, "requestVisibleBehind: returning top.fullscreen="
-                    + top.fullscreen+ " top.state=" + top.state + " top.app=" + top.app +
+                    + top.fullscreen + " top.state=" + top.state + " top.app=" + top.app +
                     " top.app.thread=" + top.app.thread);
             return false;
+        } else if (!visible && stack.getVisibleBehindActivity() != r) {
+            // Only the activity set as currently visible behind should actively reset its
+            // visible behind state.
+            if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG, "requestVisibleBehind: returning visible="
+                    + visible + " stack.getVisibleBehindActivity()=" +
+                    stack.getVisibleBehindActivity() + " r=" + r);
+            return false;
         }
 
         stack.setVisibleBehindActivity(visible ? r : null);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index d8da700..786196f 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -39,6 +39,7 @@
 import android.util.Slog;
 
 import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.PowerProfile;
 import com.android.server.LocalServices;
@@ -868,6 +869,9 @@
         if (noOutput) {
             return;
         }
+        if (BatteryStatsHelper.checkWifiOnly(mContext)) {
+            flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
+        }
         if (useCheckinFormat) {
             List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
             if (isRealCheckin) {
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 4c887dd..0dc163b 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -41,12 +41,17 @@
             String, Class<?>>();
     private static final Map<String, Class<?>> sSystemSettingToTypeMap = new HashMap<
             String, Class<?>>();
+    private static final Map<String, Class<?>> sGlobalSettingToTypeMap = new HashMap<
+            String, Class<?>>();
     static {
         sSecureSettingToTypeMap.put(Settings.Secure.LONG_PRESS_TIMEOUT, int.class);
         // add other secure settings here...
 
         sSystemSettingToTypeMap.put(Settings.System.TIME_12_24, String.class);
         // add other system settings here...
+
+        sGlobalSettingToTypeMap.put(Settings.Global.DEBUG_VIEW_ATTRIBUTES, int.class);
+        // add other global settings here...
     }
 
     private final Bundle mCoreSettings = new Bundle();
@@ -74,6 +79,7 @@
     private void sendCoreSettings() {
         populateSettings(mCoreSettings, sSecureSettingToTypeMap);
         populateSettings(mCoreSettings, sSystemSettingToTypeMap);
+        populateSettings(mCoreSettings, sGlobalSettingToTypeMap);
         mActivityManagerService.onCoreSettingsChange(mCoreSettings);
     }
 
@@ -89,6 +95,12 @@
             mActivityManagerService.mContext.getContentResolver().registerContentObserver(
                     uri, false, this);
         }
+
+        for (String setting : sGlobalSettingToTypeMap.keySet()) {
+            Uri uri = Settings.Global.getUriFor(setting);
+            mActivityManagerService.mContext.getContentResolver().registerContentObserver(
+                    uri, false, this);
+        }
     }
 
     private void populateSettings(Bundle snapshot, Map<String, Class<?>> map) {
@@ -101,32 +113,40 @@
                     final String value;
                     if (map == sSecureSettingToTypeMap) {
                         value = Settings.Secure.getString(context.getContentResolver(), setting);
-                    } else {
+                    } else if (map == sSystemSettingToTypeMap) {
                         value = Settings.System.getString(context.getContentResolver(), setting);
+                    } else {
+                        value = Settings.Global.getString(context.getContentResolver(), setting);
                     }
                     snapshot.putString(setting, value);
                 } else if (type == int.class) {
                     final int value;
                     if (map == sSecureSettingToTypeMap) {
                         value = Settings.Secure.getInt(context.getContentResolver(), setting);
-                    } else {
+                    } else if (map == sSystemSettingToTypeMap) {
                         value = Settings.System.getInt(context.getContentResolver(), setting);
+                    } else {
+                        value = Settings.Global.getInt(context.getContentResolver(), setting);
                     }
                     snapshot.putInt(setting, value);
                 } else if (type == float.class) {
                     final float value;
                     if (map == sSecureSettingToTypeMap) {
                         value = Settings.Secure.getFloat(context.getContentResolver(), setting);
-                    } else {
+                    } else if (map == sSystemSettingToTypeMap) {
                         value = Settings.System.getFloat(context.getContentResolver(), setting);
+                    } else {
+                        value = Settings.Global.getFloat(context.getContentResolver(), setting);
                     }
                     snapshot.putFloat(setting, value);
                 } else if (type == long.class) {
                     final long value;
                     if (map == sSecureSettingToTypeMap) {
                         value = Settings.Secure.getLong(context.getContentResolver(), setting);
-                    } else {
+                    } else if (map == sSystemSettingToTypeMap) {
                         value = Settings.System.getLong(context.getContentResolver(), setting);
+                    } else {
+                        value = Settings.Global.getLong(context.getContentResolver(), setting);
                     }
                     snapshot.putLong(setting, value);
                 }
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index f79c026..0a66a5c 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -450,6 +450,9 @@
                                         appInfo.packageName, null));
                                 PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0,
                                         runningIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+                                localForegroundNoti.color = ams.mContext.getResources().getColor(
+                                        com.android.internal
+                                                .R.color.system_notification_accent_color);
                                 localForegroundNoti.setLatestEventInfo(ctx,
                                         ams.mContext.getString(
                                                 com.android.internal.R.string
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index fa8626f..1fd114c 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -471,6 +471,8 @@
         mTetheredNotification.flags = Notification.FLAG_ONGOING_EVENT;
         mTetheredNotification.tickerText = title;
         mTetheredNotification.visibility = Notification.VISIBILITY_PUBLIC;
+        mTetheredNotification.color = mContext.getResources().getColor(
+                com.android.internal.R.color.system_notification_accent_color);
         mTetheredNotification.setLatestEventInfo(mContext, title, message, pi);
         mTetheredNotification.category = Notification.CATEGORY_STATUS;
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index eddf414..0f6b3ad 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -735,6 +735,8 @@
                         .setContentIntent(mStatusIntent)
                         .setDefaults(0)
                         .setOngoing(true)
+                        .setColor(mContext.getResources().getColor(
+                                com.android.internal.R.color.system_notification_accent_color))
                         .build();
                 nm.notifyAsUser(null, R.drawable.vpn_connected, notification, new UserHandle(user));
             }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 08d6fc9..949019e 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -3064,6 +3064,8 @@
                 new Notification(R.drawable.stat_notify_sync_error,
                         mContext.getString(R.string.contentServiceSync),
                         System.currentTimeMillis());
+            notification.color = mContext.getResources().getColor(
+                    com.android.internal.R.color.system_notification_accent_color);
             notification.setLatestEventInfo(mContext,
                     mContext.getString(R.string.contentServiceSyncNotificationTitle),
                     String.format(tooManyDeletesDescFormat.toString(), authorityName),
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index a05bf2c..9d008b9 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -502,6 +502,8 @@
                         .addAction(android.R.drawable.ic_menu_close_clear_cancel,
                                 r.getString(R.string.wifi_display_notification_disconnect),
                                 mDisconnectPendingIntent)
+                        .setColor(r.getColor(
+                                com.android.internal.R.color.system_notification_accent_color))
                         .build();
             } else {
                 notification = new Notification.Builder(context)
@@ -516,6 +518,8 @@
                         .addAction(android.R.drawable.ic_menu_close_clear_cancel,
                                 r.getString(R.string.wifi_display_notification_disconnect),
                                 mDisconnectPendingIntent)
+                        .setColor(r.getColor(
+                                com.android.internal.R.color.system_notification_accent_color))
                         .build();
             }
             mNotificationManager.notifyAsUser(null,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
index 46b2b3e..aed5dcc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
@@ -155,7 +155,7 @@
     }
 
     /**
-     * A mapping between andorid and cec keycode.
+     * A mapping between Android and CEC keycode.
      *
      * <p>Normal implementation of this looks like
      * <pre>
@@ -174,43 +174,28 @@
     private static class KeycodeEntry {
         private final int mAndroidKeycode;
         private final int mCecKeycode;
-        private final int mParam;
         private final boolean mIsRepeatable;
 
-        private KeycodeEntry(int androidKeycode, int cecKeycode, int param, boolean isRepeatable) {
+        private KeycodeEntry(int androidKeycode, int cecKeycode, boolean isRepeatable) {
             mAndroidKeycode = androidKeycode;
             mCecKeycode = cecKeycode;
-            mParam = param;
             mIsRepeatable = isRepeatable;
         }
 
         private KeycodeEntry(int androidKeycode, int cecKeycode) {
-            this(androidKeycode, cecKeycode, NO_PARAM, true);
+            this(androidKeycode, cecKeycode, true);
         }
 
-        private KeycodeEntry(int androidKeycode, int cecKeycode, boolean isRepeatable) {
-            this(androidKeycode, cecKeycode, NO_PARAM, isRepeatable);
-        }
-
-        private byte[] toCecKeycodeIfMatched(int androidKeycode) {
+        private int toCecKeycodeIfMatched(int androidKeycode) {
             if (mAndroidKeycode == androidKeycode) {
-                if (mParam == NO_PARAM) {
-                    return new byte[] {
-                        (byte) (mCecKeycode & 0xFF)
-                    };
-                } else {
-                    return new byte[] {
-                        (byte) (mCecKeycode & 0xFF),
-                        (byte) (mParam & 0xFF)
-                    };
-                }
+                return mCecKeycode;
             } else {
-                return null;
+                return UNSUPPORTED_KEYCODE;
             }
         }
 
-        private int toAndroidKeycodeIfMatched(int cecKeycode, int param) {
-            if (cecKeycode == mCecKeycode && mParam == param) {
+        private int toAndroidKeycodeIfMatched(int cecKeycode) {
+            if (cecKeycode == mCecKeycode) {
                 return mAndroidKeycode;
             } else {
                 return UNSUPPORTED_KEYCODE;
@@ -365,29 +350,28 @@
      * Translate Android keycode to Hdmi Cec keycode.
      *
      * @param keycode Android keycode. For details, refer {@link KeyEvent}
-     * @return array of byte which contains cec keycode and param if it has;
-     *         return null if failed to find matched cec keycode
+     * @return single byte CEC keycode if matched.
      */
-    static byte[] androidKeyToCecKey(int keycode) {
+    static int androidKeyToCecKey(int keycode) {
         for (int i = 0; i < KEYCODE_ENTRIES.length; ++i) {
-            byte[] cecKeycode = KEYCODE_ENTRIES[i].toCecKeycodeIfMatched(keycode);
-            if (cecKeycode != null) {
+            int cecKeycode = KEYCODE_ENTRIES[i].toCecKeycodeIfMatched(keycode);
+            if (cecKeycode != UNSUPPORTED_KEYCODE) {
                 return cecKeycode;
             }
         }
-        return null;
+        return UNSUPPORTED_KEYCODE;
     }
 
     /**
      * Translate Hdmi CEC keycode to Android keycode.
      *
-     * @param keycode Cec keycode. If has no param, put {@link #NO_PARAM}
+     * @param keycode CEC keycode
      * @return cec keycode corresponding to the given android keycode.
      *         If finds no matched keycode, return {@link #UNSUPPORTED_KEYCODE}
      */
-    static int cecKeyToAndroidKey(int keycode, int param) {
+    static int cecKeyToAndroidKey(int keycode) {
         for (int i = 0; i < KEYCODE_ENTRIES.length; ++i) {
-            int androidKey = KEYCODE_ENTRIES[i].toAndroidKeycodeIfMatched(keycode, param);
+            int androidKey = KEYCODE_ENTRIES[i].toAndroidKeycodeIfMatched(keycode);
             if (androidKey != UNSUPPORTED_KEYCODE) {
                 return androidKey;
             }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 4862f93..b43ad1b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -405,8 +405,9 @@
 
         final long downTime = SystemClock.uptimeMillis();
         final byte[] params = message.getParams();
-        final int keycode = HdmiCecKeycode.cecKeyToAndroidKey(params[0],
-                params.length > 1 ? params[1] : HdmiCecKeycode.NO_PARAM);
+        // Note that we don't support parameterized keycode now.
+        // TODO: translate parameterized keycode as well.
+        final int keycode = HdmiCecKeycode.cecKeyToAndroidKey(params[0]);
         int keyRepeatCount = 0;
         if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
             if (keycode == mLastKeycode) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 809fef4..73f5cfd 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -178,7 +178,6 @@
             invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
             return;
         }
-        // TODO: Handle MHL device
         int targetAddress = targetDevice.getLogicalAddress();
         ActiveSource active = getActiveSource();
         if (active.isValid() && targetAddress == active.logicalAddress) {
@@ -419,17 +418,25 @@
     @ServiceThreadOnly
     protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
-                mAddress, Locale.getDefault().getISO3Language());
         // TODO: figure out how to handle failed to get language code.
-        if (command != null) {
-            mService.sendCecCommand(command);
-        } else {
+        if (!broadcastMenuLanguage(Locale.getDefault().getISO3Language())) {
             Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString());
         }
         return true;
     }
 
+    @ServiceThreadOnly
+    boolean broadcastMenuLanguage(String language) {
+        assertRunOnServiceThread();
+        HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
+                mAddress, language);
+        if (command != null) {
+            mService.sendCecCommand(command);
+            return true;
+        }
+        return false;
+    }
+
     @Override
     @ServiceThreadOnly
     protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
@@ -1007,10 +1014,8 @@
     /**
      * Return external input devices.
      */
-    List<HdmiDeviceInfo> getSafeExternalInputs() {
-        synchronized (mLock) {
-            return mSafeExternalInputs;
-        }
+    List<HdmiDeviceInfo> getSafeExternalInputsLocked() {
+        return mSafeExternalInputs;
     }
 
     @ServiceThreadOnly
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 14c066e..5b99f14 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.hdmi;
 
+import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE;
+import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
 import static com.android.server.hdmi.Constants.DISABLED;
 import static com.android.server.hdmi.Constants.ENABLED;
 import static com.android.server.hdmi.Constants.OPTION_CEC_AUTO_WAKEUP;
@@ -76,6 +78,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * Provides a service for sending and processing HDMI control messages,
@@ -121,7 +124,7 @@
         void onPollingFinished(List<Integer> ackedAddress);
     }
 
-    private class PowerStateReceiver extends BroadcastReceiver {
+    private class HdmiControlBroadcastReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             switch (intent.getAction()) {
@@ -135,6 +138,12 @@
                         onWakeUp();
                     }
                     break;
+                case Intent.ACTION_CONFIGURATION_CHANGED:
+                    String language = Locale.getDefault().getISO3Language();
+                    if (!mLanguage.equals(language)) {
+                        onLanguageChanged(language);
+                    }
+                    break;
             }
         }
     }
@@ -202,6 +211,9 @@
     @GuardedBy("mLock")
     private boolean mMhlInputChangeEnabled;
 
+    @GuardedBy("mLock")
+    private List<HdmiDeviceInfo> mMhlDevices;
+
     // List of listeners registered by callers that want to get notified of
     // system audio mode changes.
     private final ArrayList<IHdmiSystemAudioModeChangeListener>
@@ -233,12 +245,16 @@
 
     private HdmiCecMessageValidator mMessageValidator;
 
-    private final PowerStateReceiver mPowerStateReceiver = new PowerStateReceiver();
+    private final HdmiControlBroadcastReceiver
+            mHdmiControlBroadcastReceiver = new HdmiControlBroadcastReceiver();
 
     @ServiceThreadOnly
     private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY;
 
     @ServiceThreadOnly
+    private String mLanguage = Locale.getDefault().getISO3Language();
+
+    @ServiceThreadOnly
     private boolean mStandbyMessageReceived = false;
 
     @ServiceThreadOnly
@@ -293,6 +309,7 @@
             Slog.i(TAG, "Device does not support MHL-control.");
         }
         initPortInfo();
+        mMhlDevices = Collections.emptyList();
         mMessageValidator = new HdmiCecMessageValidator(this);
         publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
 
@@ -301,7 +318,8 @@
             IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_SCREEN_OFF);
             filter.addAction(Intent.ACTION_SCREEN_ON);
-            getContext().registerReceiver(mPowerStateReceiver, filter);
+            filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+            getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter);
         }
     }
 
@@ -320,7 +338,6 @@
         }
     }
 
-
     private void registerContentObserver() {
         ContentResolver resolver = getContext().getContentResolver();
         String[] settings = new String[] {
@@ -330,7 +347,7 @@
                 Global.MHL_INPUT_SWITCHING_ENABLED,
                 Global.MHL_POWER_CHARGE_ENABLED
         };
-        for (String s: settings) {
+        for (String s : settings) {
             resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver,
                     UserHandle.USER_ALL);
         }
@@ -351,7 +368,7 @@
                     break;
                 case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED:
                     tv().setAutoWakeup(enabled);
-                    setOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled));
+                    setCecOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled));
                     break;
                 case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED:
                     tv().setAutoDeviceOff(enabled);
@@ -490,6 +507,10 @@
         }
     }
 
+    List<HdmiPortInfo> getPortInfo() {
+        return mPortInfo;
+    }
+
     /**
      * Returns HDMI port information for the given port id.
      *
@@ -684,16 +705,16 @@
     /**
      * Called when a new hotplug event is issued.
      *
-     * @param portNo hdmi port number where hot plug event issued.
+     * @param portId hdmi port number where hot plug event issued.
      * @param connected whether to be plugged in or not
      */
     @ServiceThreadOnly
-    void onHotplug(int portNo, boolean connected) {
+    void onHotplug(int portId, boolean connected) {
         assertRunOnServiceThread();
         for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
-            device.onHotplug(portNo, connected);
+            device.onHotplug(portId, connected);
         }
-        announceHotplugEvent(portNo, connected);
+        announceHotplugEvent(portId, connected);
     }
 
     /**
@@ -794,10 +815,15 @@
             HdmiMhlLocalDevice device = mMhlController.removeLocalDevice(portId);
             if (device != null) {
                 device.onDeviceRemoved();
+                // There is no explicit event for device removal unlike capability register event
+                // used for device addition . Hence we remove the device on hotplug event.
+                invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE);
+                updateSafeMhlInput();
             } else {
                 Slog.w(TAG, "No device to remove:[portId=" + portId);
             }
         }
+        announceHotplugEvent(portId, connected);
     }
 
     @ServiceThreadOnly
@@ -824,18 +850,45 @@
     }
 
     @ServiceThreadOnly
-    void handleCapabilityRegisterChanged(int portId, int adopterId, int deviceId) {
+    void handleMhlCapabilityRegisterChanged(int portId, int adopterId, int deviceId) {
         assertRunOnServiceThread();
         HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId);
-        // Hot plug event should be called before capability register change event.
+
+        // Hotplug event should already have been called before capability register change event.
         if (device != null) {
             device.setCapabilityRegister(adopterId, deviceId);
+            invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_ADD_DEVICE);
+            updateSafeMhlInput();
         } else {
             Slog.w(TAG, "No mhl device exists for capability register change event[portId:"
                     + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]");
         }
     }
 
+    @ServiceThreadOnly
+    private void updateSafeMhlInput() {
+        assertRunOnServiceThread();
+        List<HdmiDeviceInfo> inputs = Collections.emptyList();
+        SparseArray<HdmiMhlLocalDevice> devices = mMhlController.getAllLocalDevices();
+        for (int i = 0; i < devices.size(); ++i) {
+            HdmiMhlLocalDevice device = devices.valueAt(i);
+            HdmiDeviceInfo info = device.getInfo();
+            if (info != null) {
+                if (inputs.isEmpty()) {
+                    inputs = new ArrayList<>();
+                }
+                inputs.add(device.getInfo());
+            }
+        }
+        synchronized (mLock) {
+            mMhlDevices = inputs;
+        }
+    }
+
+    private List<HdmiDeviceInfo> getMhlDevicesLocked() {
+        return mMhlDevices;
+    }
+
     // Record class that monitors the event of the caller of being killed. Used to clean up
     // the listener list and record list accordingly.
     private final class HotplugEventListenerRecord implements IBinder.DeathRecipient {
@@ -964,6 +1017,17 @@
                         invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
                         return;
                     }
+                    if (mMhlController != null) {
+                        HdmiMhlLocalDevice device = mMhlController.getLocalDeviceById(deviceId);
+                        if (device != null) {
+                            // Upon selecting MHL device, we send RAP[Content On] to wake up
+                            // the connected mobile device, start routing control to switch ports.
+                            // callback is handled by MHL action.
+                            device.turnOn(callback);
+                            tv.doManualPortSwitching(device.getInfo().getPortId(), null);
+                            return;
+                        }
+                    }
                     tv.deviceSelect(deviceId, callback);
                 }
             });
@@ -1073,7 +1137,7 @@
         @Override
         public List<HdmiPortInfo> getPortInfo() {
             enforceAccessPermission();
-            return mPortInfo;
+            return HdmiControlService.this.getPortInfo();
         }
 
         @Override
@@ -1139,10 +1203,12 @@
             // No need to hold the lock for obtaining TV device as the local device instance
             // is preserved while the HDMI control is enabled.
             HdmiCecLocalDeviceTv tv = tv();
-            if (tv == null) {
-                return Collections.emptyList();
+            synchronized (mLock) {
+                List<HdmiDeviceInfo> cecDevices = (tv == null)
+                        ? Collections.<HdmiDeviceInfo>emptyList()
+                        : tv.getSafeExternalInputsLocked();
+                return HdmiUtils.mergeToUnmodifiableList(cecDevices, getMhlDevicesLocked());
             }
-            return tv.getSafeExternalInputs();
         }
 
         @Override
@@ -1643,12 +1709,28 @@
         });
     }
 
-    private void disableDevices(PendingActionClearedCallback callback) {
-        for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
-            device.disableDevice(mStandbyMessageReceived, callback);
-        }
+    @ServiceThreadOnly
+    private void onLanguageChanged(String language) {
+        assertRunOnServiceThread();
+        mLanguage = language;
+
         if (isTvDevice()) {
-            unregisterSettingsObserver();
+            tv().broadcastMenuLanguage(language);
+        }
+    }
+
+    private void disableDevices(PendingActionClearedCallback callback) {
+        if (mCecController != null) {
+            for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
+                device.disableDevice(mStandbyMessageReceived, callback);
+            }
+            if (isTvDevice()) {
+                unregisterSettingsObserver();
+            }
+        }
+
+        if (mMhlController != null) {
+            mMhlController.clearAllLocalDevices();
         }
     }
 
@@ -1720,7 +1802,7 @@
     }
 
     @ServiceThreadOnly
-    void setOption(int key, int value) {
+    void setCecOption(int key, int value) {
         assertRunOnServiceThread();
         mCecController.setOption(key, value);
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index 23f19ff..22a519b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -206,6 +206,22 @@
         return list;
     }
 
+    static <T> List<T> mergeToUnmodifiableList(List<T> a, List<T> b) {
+        if (a.isEmpty() && b.isEmpty()) {
+            return Collections.emptyList();
+        }
+        if (a.isEmpty()) {
+            return Collections.unmodifiableList(b);
+        }
+        if (b.isEmpty()) {
+            return Collections.unmodifiableList(a);
+        }
+        List<T> newList = new ArrayList<>();
+        newList.addAll(a);
+        newList.addAll(b);
+        return Collections.unmodifiableList(newList);
+    }
+
     /**
      * See if the new path is affecting the active path.
      *
diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java
index 9f09eb4..ed978e0 100644
--- a/services/core/java/com/android/server/hdmi/SendKeyAction.java
+++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java
@@ -109,12 +109,12 @@
     }
 
     private void sendKeyDown(int keycode) {
-        byte[] keycodeAndParam = getCecKeycodeAndParam(keycode);
-        if (keycodeAndParam == null) {
+        int cecKeycode = HdmiCecKeycode.androidKeyToCecKey(keycode);
+        if (cecKeycode == HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
             return;
         }
         sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(),
-                mTargetAddress, keycodeAndParam));
+                mTargetAddress, new byte[] { (byte) (cecKeycode & 0xFF) }));
     }
 
     private void sendKeyUp() {
@@ -141,13 +141,4 @@
         sendKeyDown(mLastKeycode);
         addTimer(mState, IRT_MS);
     }
-
-    // Converts the Android key code to corresponding CEC key code definition. Those CEC keys
-    // with additional parameters should be mapped from individual Android key code. 'Select
-    // Broadcast' with the parameter 'cable', for instance, shall have its counterpart such as
-    // KeyEvent.KEYCODE_TV_BROADCAST_CABLE.
-    // The return byte array contains both UI command (keycode) and optional parameter.
-    private byte[] getCecKeycodeAndParam(int keycode) {
-        return HdmiCecKeycode.androidKeyToCecKey(keycode);
-    }
 }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 7c1681c..93dceff 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -774,6 +774,8 @@
                     .setContentIntent(mKeyboardLayoutIntent)
                     .setSmallIcon(R.drawable.ic_settings_language)
                     .setPriority(Notification.PRIORITY_LOW)
+                    .setColor(mContext.getResources().getColor(
+                            com.android.internal.R.color.system_notification_accent_color))
                     .build();
             mNotificationManager.notifyAsUser(null,
                     R.string.select_keyboard_layout_notification_title,
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index f820a3c..84027e2 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -26,9 +26,6 @@
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
-import android.media.routing.IMediaRouter;
-import android.media.routing.IMediaRouterDelegate;
-import android.media.routing.IMediaRouterStateCallback;
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
 import android.media.session.ISessionController;
@@ -96,7 +93,6 @@
             new ArrayList<ISessionControllerCallback>();
 
     private long mFlags;
-    private IMediaRouter mMediaRouter;
     private PendingIntent mMediaButtonReceiver;
     private PendingIntent mLaunchIntent;
 
@@ -692,12 +688,6 @@
         }
 
         @Override
-        public void setMediaRouter(IMediaRouter router) {
-            mMediaRouter = router;
-            mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
-        }
-
-        @Override
         public void setMediaButtonReceiver(PendingIntent pi) {
             mMediaButtonReceiver = pi;
         }
@@ -1147,13 +1137,6 @@
         public boolean isTransportControlEnabled() {
             return MediaSessionRecord.this.isTransportControlEnabled();
         }
-
-        @Override
-        public IMediaRouterDelegate createMediaRouterDelegate(
-                IMediaRouterStateCallback callback) {
-            // todo
-            return null;
-        }
     }
 
     private class MessageHandler extends Handler {
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 289b5aa..69d1dc9 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -26,6 +26,8 @@
 import android.media.projection.IMediaProjectionManager;
 import android.media.projection.IMediaProjection;
 import android.media.projection.IMediaProjectionCallback;
+import android.media.projection.IMediaProjectionWatcherCallback;
+import android.media.projection.MediaProjectionInfo;
 import android.media.projection.MediaProjectionManager;
 import android.os.Binder;
 import android.os.Handler;
@@ -34,6 +36,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Slog;
 
@@ -59,15 +62,20 @@
     private static final String TAG = "MediaProjectionManagerService";
 
     private final Object mLock = new Object(); // Protects the list of media projections
-    private final Map<IBinder, MediaProjection> mProjectionGrants;
+    private final Map<IBinder, IBinder.DeathRecipient> mDeathEaters;
+    private final CallbackDelegate mCallbackDelegate;
 
     private final Context mContext;
     private final AppOpsManager mAppOps;
 
+    private IBinder mProjectionToken;
+    private MediaProjection mProjectionGrant;
+
     public MediaProjectionManagerService(Context context) {
         super(context);
         mContext = context;
-        mProjectionGrants = new ArrayMap<IBinder, MediaProjection>();
+        mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>();
+        mCallbackDelegate = new CallbackDelegate();
         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         Watchdog.getInstance().addMonitor(this);
     }
@@ -83,13 +91,97 @@
         synchronized (mLock) { /* check for deadlock */ }
     }
 
+    private void startProjectionLocked(final MediaProjection projection) {
+        if (mProjectionGrant != null) {
+            mProjectionGrant.stop();
+        }
+        mProjectionToken = projection.asBinder();
+        mProjectionGrant = projection;
+        dispatchStart(projection);
+    }
+
+    private void stopProjectionLocked(final MediaProjection projection) {
+        mProjectionToken = null;
+        mProjectionGrant = null;
+        dispatchStop(projection);
+    }
+
+    private void addCallback(final IMediaProjectionWatcherCallback callback) {
+        IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
+            @Override
+            public void binderDied() {
+                synchronized (mLock) {
+                    unlinkDeathRecipientLocked(callback);
+                    removeCallback(callback);
+                }
+            }
+        };
+        synchronized (mLock) {
+            mCallbackDelegate.add(callback);
+            linkDeathRecipientLocked(callback, deathRecipient);
+        }
+    }
+
+    private void removeCallback(IMediaProjectionWatcherCallback callback) {
+        synchronized (mLock) {
+            unlinkDeathRecipientLocked(callback);
+            removeCallback(callback);
+        }
+    }
+
+    private void linkDeathRecipientLocked(IMediaProjectionWatcherCallback callback,
+            IBinder.DeathRecipient deathRecipient) {
+        try {
+            final IBinder token = callback.asBinder();
+            token.linkToDeath(deathRecipient, 0);
+            mDeathEaters.put(token, deathRecipient);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to link to death for media projection monitoring callback", e);
+        }
+    }
+
+    private void unlinkDeathRecipientLocked(IMediaProjectionWatcherCallback callback) {
+        final IBinder token = callback.asBinder();
+        IBinder.DeathRecipient deathRecipient = mDeathEaters.remove(token);
+        if (deathRecipient != null) {
+            token.unlinkToDeath(deathRecipient, 0);
+        }
+    }
+
+    private void dispatchStart(MediaProjection projection) {
+        mCallbackDelegate.dispatchStart(projection);
+    }
+
+    private void dispatchStop(MediaProjection projection) {
+        mCallbackDelegate.dispatchStop(projection);
+    }
+
+    private boolean isValidMediaProjection(IBinder token) {
+        synchronized (mLock) {
+            if (mProjectionToken != null) {
+                return mProjectionToken.equals(token);
+            }
+            return false;
+        }
+    }
+
+    private MediaProjectionInfo getActiveProjectionInfo() {
+        synchronized (mLock) {
+            if (mProjectionGrant == null) {
+                return null;
+            }
+            return mProjectionGrant.getProjectionInfo();
+        }
+    }
+
     private void dump(final PrintWriter pw) {
         pw.println("MEDIA PROJECTION MANAGER (dumpsys media_projection)");
         synchronized (mLock) {
-            Collection<MediaProjection> projections = mProjectionGrants.values();
-            pw.println("Media Projections: size=" + projections.size());
-            for (MediaProjection mp : projections) {
-                mp.dump(pw, "  ");
+            pw.println("Media Projection: ");
+            if (mProjectionGrant != null ) {
+                mProjectionGrant.dump(pw);
+            } else {
+                pw.println("null");
             }
         }
     }
@@ -115,11 +207,14 @@
         @Override // Binder call
         public IMediaProjection createProjection(int uid, String packageName, int type,
                 boolean isPermanentGrant) {
-            if (mContext.checkCallingPermission(Manifest.permission.CREATE_MEDIA_PROJECTION)
+            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
                         != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Requires CREATE_MEDIA_PROJECTION in order to grant "
+                throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to grant "
                         + "projection permission");
             }
+            if (packageName == null || packageName.isEmpty()) {
+                throw new IllegalArgumentException("package name must not be empty");
+            }
             long callingToken = Binder.clearCallingIdentity();
             MediaProjection projection;
             try {
@@ -136,7 +231,71 @@
 
         @Override // Binder call
         public boolean isValidMediaProjection(IMediaProjection projection) {
-            return mProjectionGrants.containsKey(projection.asBinder());
+            return MediaProjectionManagerService.this.isValidMediaProjection(
+                    projection.asBinder());
+        }
+
+        @Override // Binder call
+        public MediaProjectionInfo getActiveProjectionInfo() {
+            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
+                        != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add "
+                        + "projection callbacks");
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return MediaProjectionManagerService.this.getActiveProjectionInfo();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void stopActiveProjection() {
+            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
+                        != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add "
+                        + "projection callbacks");
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (mProjectionGrant != null) {
+                    mProjectionGrant.stop();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
+        }
+
+        @Override //Binder call
+        public void addCallback(final IMediaProjectionWatcherCallback callback) {
+            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
+                        != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add "
+                        + "projection callbacks");
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                MediaProjectionManagerService.this.addCallback(callback);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void removeCallback(IMediaProjectionWatcherCallback callback) {
+            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
+                        != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to remove "
+                        + "projection callbacks");
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                MediaProjectionManagerService.this.removeCallback(callback);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
 
         @Override // Binder call
@@ -157,25 +316,27 @@
             }
         }
 
+
         private boolean checkPermission(String packageName, String permission) {
             return mContext.getPackageManager().checkPermission(permission, packageName)
                     == PackageManager.PERMISSION_GRANTED;
         }
     }
 
-    private final class MediaProjection extends IMediaProjection.Stub implements DeathRecipient {
-        public int uid;
-        public String packageName;
+    private final class MediaProjection extends IMediaProjection.Stub {
+        public final int uid;
+        public final String packageName;
+        public final UserHandle userHandle;
 
         private IBinder mToken;
+        private IBinder.DeathRecipient mDeathEater;
         private int mType;
-        private CallbackDelegate mCallbackDelegate;
 
         public MediaProjection(int type, int uid, String packageName) {
             mType = type;
             this.uid = uid;
             this.packageName = packageName;
-            mCallbackDelegate = new CallbackDelegate();
+            userHandle = new UserHandle(UserHandle.getUserId(uid));
         }
 
         @Override // Binder call
@@ -220,49 +381,50 @@
         }
 
         @Override // Binder call
-        public void start(IMediaProjectionCallback callback) {
+        public void start(final IMediaProjectionCallback callback) {
             if (callback == null) {
                 throw new IllegalArgumentException("callback must not be null");
             }
             synchronized (mLock) {
-                if (mProjectionGrants.containsKey(asBinder())) {
+                if (isValidMediaProjection(asBinder())) {
                     throw new IllegalStateException(
                             "Cannot start already started MediaProjection");
                 }
                 addCallback(callback);
                 try {
                     mToken = callback.asBinder();
-                    mToken.linkToDeath(this, 0);
+                    mDeathEater = new IBinder.DeathRecipient() {
+                        @Override
+                        public void binderDied() {
+                            mCallbackDelegate.remove(callback);
+                            stop();
+                        }
+                    };
+                    mToken.linkToDeath(mDeathEater, 0);
                 } catch (RemoteException e) {
                     Slog.w(TAG,
                             "MediaProjectionCallbacks must be valid, aborting MediaProjection", e);
                     return;
                 }
-                mProjectionGrants.put(asBinder(), this);
+                startProjectionLocked(this);
             }
         }
 
         @Override // Binder call
         public void stop() {
             synchronized (mLock) {
-                if (!mProjectionGrants.containsKey(asBinder())) {
+                if (!isValidMediaProjection(asBinder())) {
                     Slog.w(TAG, "Attempted to stop inactive MediaProjection "
                             + "(uid=" + Binder.getCallingUid() + ", "
                             + "pid=" + Binder.getCallingPid() + ")");
                     return;
                 }
-                mToken.unlinkToDeath(this, 0);
-                mCallbackDelegate.dispatchStop();
-                mProjectionGrants.remove(asBinder());
+                mToken.unlinkToDeath(mDeathEater, 0);
+                stopProjectionLocked(this);
             }
         }
 
         @Override
-        public void binderDied() {
-            stop();
-        }
-
-        @Override
         public void addCallback(IMediaProjectionCallback callback) {
             if (callback == null) {
                 throw new IllegalArgumentException("callback must not be null");
@@ -278,52 +440,143 @@
             mCallbackDelegate.remove(callback);
         }
 
-        public void dump(PrintWriter pw, String prefix) {
-            pw.println(prefix + "(" + packageName + ", uid=" + uid + "): " + typeToString(mType));
+        public MediaProjectionInfo getProjectionInfo() {
+            return new MediaProjectionInfo(packageName, userHandle);
+        }
+
+        public void dump(PrintWriter pw) {
+            pw.println("(" + packageName + ", uid=" + uid + "): " + typeToString(mType));
         }
     }
 
+
     private static class CallbackDelegate {
-        private static final int MSG_ON_STOP = 0;
-        private List<IMediaProjectionCallback> mCallbacks;
+        private Map<IBinder, IMediaProjectionCallback> mClientCallbacks;
+        private Map<IBinder, IMediaProjectionWatcherCallback> mWatcherCallbacks;
         private Handler mHandler;
         private Object mLock = new Object();
 
         public CallbackDelegate() {
             mHandler = new Handler(Looper.getMainLooper(), null, true /*async*/);
-            mCallbacks = new ArrayList<IMediaProjectionCallback>();
+            mClientCallbacks = new ArrayMap<IBinder, IMediaProjectionCallback>();
+            mWatcherCallbacks = new ArrayMap<IBinder, IMediaProjectionWatcherCallback>();
         }
 
         public void add(IMediaProjectionCallback callback) {
             synchronized (mLock) {
-                mCallbacks.add(callback);
+                mClientCallbacks.put(callback.asBinder(), callback);
+            }
+        }
+
+        public void add(IMediaProjectionWatcherCallback callback) {
+            synchronized (mLock) {
+                mWatcherCallbacks.put(callback.asBinder(), callback);
             }
         }
 
         public void remove(IMediaProjectionCallback callback) {
             synchronized (mLock) {
-                mCallbacks.remove(callback);
+                mClientCallbacks.remove(callback.asBinder());
             }
         }
 
-        public void dispatchStop() {
+        public void remove(IMediaProjectionWatcherCallback callback) {
             synchronized (mLock) {
-                for (final IMediaProjectionCallback callback : mCallbacks) {
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            try {
-                                callback.onStop();
-                            } catch (RemoteException e) {
-                                Slog.w(TAG, "Failed to notify media projection has stopped", e);
-                            }
-                        }
-                    });
+                mWatcherCallbacks.remove(callback.asBinder());
+            }
+        }
+
+        public void dispatchStart(MediaProjection projection) {
+            if (projection == null) {
+                Slog.e(TAG, "Tried to dispatch start notification for a null media projection."
+                        + " Ignoring!");
+                return;
+            }
+            synchronized (mLock) {
+                for (IMediaProjectionWatcherCallback callback : mWatcherCallbacks.values()) {
+                    MediaProjectionInfo info = projection.getProjectionInfo();
+                    mHandler.post(new WatcherStartCallback(info, callback));
+                }
+            }
+        }
+
+        public void dispatchStop(MediaProjection projection) {
+            if (projection == null) {
+                Slog.e(TAG, "Tried to dispatch stop notification for a null media projection."
+                        + " Ignoring!");
+                return;
+            }
+            synchronized (mLock) {
+                for (IMediaProjectionCallback callback : mClientCallbacks.values()) {
+                    mHandler.post(new ClientStopCallback(callback));
+                }
+
+                for (IMediaProjectionWatcherCallback callback : mWatcherCallbacks.values()) {
+                    MediaProjectionInfo info = projection.getProjectionInfo();
+                    mHandler.post(new WatcherStopCallback(info, callback));
                 }
             }
         }
     }
 
+    private static final class WatcherStartCallback implements Runnable {
+        private IMediaProjectionWatcherCallback mCallback;
+        private MediaProjectionInfo mInfo;
+
+        public WatcherStartCallback(MediaProjectionInfo info,
+                IMediaProjectionWatcherCallback callback) {
+            mInfo = info;
+            mCallback = callback;
+        }
+
+        @Override
+        public void run() {
+            try {
+                mCallback.onStart(mInfo);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to notify media projection has stopped", e);
+            }
+        }
+    }
+
+    private static final class WatcherStopCallback implements Runnable {
+        private IMediaProjectionWatcherCallback mCallback;
+        private MediaProjectionInfo mInfo;
+
+        public WatcherStopCallback(MediaProjectionInfo info,
+                IMediaProjectionWatcherCallback callback) {
+            mInfo = info;
+            mCallback = callback;
+        }
+
+        @Override
+        public void run() {
+            try {
+                mCallback.onStop(mInfo);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to notify media projection has stopped", e);
+            }
+        }
+    }
+
+    private static final class ClientStopCallback implements Runnable {
+        private IMediaProjectionCallback mCallback;
+
+        public ClientStopCallback(IMediaProjectionCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void run() {
+            try {
+                mCallback.onStop();
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to notify media projection has stopped", e);
+            }
+        }
+    }
+
+
     private static String typeToString(int type) {
         switch (type) {
             case MediaProjectionManager.TYPE_SCREEN_CAPTURE:
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index 907eeb2..857b9e9 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -20,10 +20,10 @@
 import android.net.IpConfiguration.IpAssignment;
 import android.net.IpConfiguration.ProxySettings;
 import android.net.LinkAddress;
-import android.net.LinkProperties;
 import android.net.NetworkUtils;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
+import android.net.StaticIpConfiguration;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.text.TextUtils;
@@ -41,6 +41,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.net.InetAddress;
+import java.net.Inet4Address;
 import java.util.Map;
 
 public class IpConfigStore {
@@ -69,40 +70,32 @@
     }
 
     private boolean writeConfig(DataOutputStream out, int configKey,
-                                  IpConfiguration config) throws IOException {
+                                IpConfiguration config) throws IOException {
         boolean written = false;
 
         try {
-            LinkProperties linkProperties = config.linkProperties;
             switch (config.ipAssignment) {
                 case STATIC:
                     out.writeUTF(IP_ASSIGNMENT_KEY);
                     out.writeUTF(config.ipAssignment.toString());
-                    for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) {
-                        out.writeUTF(LINK_ADDRESS_KEY);
-                        out.writeUTF(linkAddr.getAddress().getHostAddress());
-                        out.writeInt(linkAddr.getPrefixLength());
-                    }
-                    for (RouteInfo route : linkProperties.getRoutes()) {
-                        out.writeUTF(GATEWAY_KEY);
-                        LinkAddress dest = route.getDestinationLinkAddress();
-                        if (dest != null) {
-                            out.writeInt(1);
-                            out.writeUTF(dest.getAddress().getHostAddress());
-                            out.writeInt(dest.getPrefixLength());
-                        } else {
-                            out.writeInt(0);
+                    StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration;
+                    if (staticIpConfiguration != null) {
+                        if (staticIpConfiguration.ipAddress != null) {
+                            LinkAddress ipAddress = staticIpConfiguration.ipAddress;
+                            out.writeUTF(LINK_ADDRESS_KEY);
+                            out.writeUTF(ipAddress.getAddress().getHostAddress());
+                            out.writeInt(ipAddress.getPrefixLength());
                         }
-                        if (route.getGateway() != null) {
-                            out.writeInt(1);
-                            out.writeUTF(route.getGateway().getHostAddress());
-                        } else {
-                            out.writeInt(0);
+                        if (staticIpConfiguration.gateway != null) {
+                            out.writeUTF(GATEWAY_KEY);
+                            out.writeInt(0);  // Default route.
+                            out.writeInt(1);  // Have a gateway.
+                            out.writeUTF(staticIpConfiguration.gateway.getHostAddress());
                         }
-                    }
-                    for (InetAddress inetAddr : linkProperties.getDnsServers()) {
-                        out.writeUTF(DNS_KEY);
-                        out.writeUTF(inetAddr.getHostAddress());
+                        for (InetAddress inetAddr : staticIpConfiguration.dnsServers) {
+                            out.writeUTF(DNS_KEY);
+                            out.writeUTF(inetAddr.getHostAddress());
+                        }
                     }
                     written = true;
                     break;
@@ -121,7 +114,7 @@
 
             switch (config.proxySettings) {
                 case STATIC:
-                    ProxyInfo proxyProperties = linkProperties.getHttpProxy();
+                    ProxyInfo proxyProperties = config.httpProxy;
                     String exclusionList = proxyProperties.getExclusionListAsString();
                     out.writeUTF(PROXY_SETTINGS_KEY);
                     out.writeUTF(config.proxySettings.toString());
@@ -134,7 +127,7 @@
                     written = true;
                     break;
                 case PAC:
-                    ProxyInfo proxyPacProperties = linkProperties.getHttpProxy();
+                    ProxyInfo proxyPacProperties = config.httpProxy;
                     out.writeUTF(PROXY_SETTINGS_KEY);
                     out.writeUTF(config.proxySettings.toString());
                     out.writeUTF(PROXY_PAC_FILE);
@@ -159,7 +152,7 @@
                 out.writeInt(configKey);
             }
         } catch (NullPointerException e) {
-            loge("Failure in writing " + config.linkProperties + e);
+            loge("Failure in writing " + config + e);
         }
         out.writeUTF(EOS);
 
@@ -196,7 +189,7 @@
                 // Default is DHCP with no proxy
                 IpAssignment ipAssignment = IpAssignment.DHCP;
                 ProxySettings proxySettings = ProxySettings.NONE;
-                LinkProperties linkProperties = new LinkProperties();
+                StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
                 String proxyHost = null;
                 String pacFileUrl = null;
                 int proxyPort = -1;
@@ -213,13 +206,23 @@
                         } else if (key.equals(LINK_ADDRESS_KEY)) {
                             LinkAddress linkAddr = new LinkAddress(
                                     NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt());
-                            linkProperties.addLinkAddress(linkAddr);
+                            if (linkAddr.getAddress() instanceof Inet4Address &&
+                                    staticIpConfiguration.ipAddress == null) {
+                                staticIpConfiguration.ipAddress = linkAddr;
+                            } else {
+                                loge("Non-IPv4 or duplicate address: " + linkAddr);
+                            }
                         } else if (key.equals(GATEWAY_KEY)) {
                             LinkAddress dest = null;
                             InetAddress gateway = null;
                             if (version == 1) {
                                 // only supported default gateways - leave the dest/prefix empty
                                 gateway = NetworkUtils.numericToInetAddress(in.readUTF());
+                                if (staticIpConfiguration.gateway == null) {
+                                    staticIpConfiguration.gateway = gateway;
+                                } else {
+                                    loge("Duplicate gateway: " + gateway.getHostAddress());
+                                }
                             } else {
                                 if (in.readInt() == 1) {
                                     dest = new LinkAddress(
@@ -229,10 +232,16 @@
                                 if (in.readInt() == 1) {
                                     gateway = NetworkUtils.numericToInetAddress(in.readUTF());
                                 }
+                                RouteInfo route = new RouteInfo(dest, gateway);
+                                if (route.isIPv4Default() &&
+                                        staticIpConfiguration.gateway == null) {
+                                    staticIpConfiguration.gateway = gateway;
+                                } else {
+                                    loge("Non-IPv4 default or duplicate route: " + route);
+                                }
                             }
-                            linkProperties.addRoute(new RouteInfo(dest, gateway));
                         } else if (key.equals(DNS_KEY)) {
-                            linkProperties.addDnsServer(
+                            staticIpConfiguration.dnsServers.add(
                                     NetworkUtils.numericToInetAddress(in.readUTF()));
                         } else if (key.equals(PROXY_SETTINGS_KEY)) {
                             proxySettings = ProxySettings.valueOf(in.readUTF());
@@ -258,9 +267,11 @@
                     IpConfiguration config = new IpConfiguration();
                     networks.put(id, config);
 
-                    config.linkProperties = linkProperties;
                     switch (ipAssignment) {
                         case STATIC:
+                            config.staticIpConfiguration = staticIpConfiguration;
+                            config.ipAssignment = ipAssignment;
+                            break;
                         case DHCP:
                             config.ipAssignment = ipAssignment;
                             break;
@@ -276,16 +287,15 @@
 
                     switch (proxySettings) {
                         case STATIC:
-                            config.proxySettings = proxySettings;
-                            ProxyInfo ProxyInfo =
+                            ProxyInfo proxyInfo =
                                     new ProxyInfo(proxyHost, proxyPort, exclusionList);
-                            linkProperties.setHttpProxy(ProxyInfo);
+                            config.proxySettings = proxySettings;
+                            config.httpProxy = proxyInfo;
                             break;
                         case PAC:
+                            ProxyInfo proxyPacProperties = new ProxyInfo(pacFileUrl);
                             config.proxySettings = proxySettings;
-                            ProxyInfo proxyPacProperties =
-                                    new ProxyInfo(pacFileUrl);
-                            linkProperties.setHttpProxy(proxyPacProperties);
+                            config.httpProxy = proxyPacProperties;
                             break;
                         case NONE:
                             config.proxySettings = proxySettings;
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index a2e9d676..52e741b 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -304,16 +304,18 @@
     }
 
     private void showNotification(int titleRes, int iconRes) {
-        final Notification.Builder builder = new Notification.Builder(mContext);
-        builder.setWhen(0);
-        builder.setSmallIcon(iconRes);
-        builder.setContentTitle(mContext.getString(titleRes));
-        builder.setContentText(mContext.getString(R.string.vpn_lockdown_config));
-        builder.setContentIntent(mConfigIntent);
-        builder.setPriority(Notification.PRIORITY_LOW);
-        builder.setOngoing(true);
-        builder.addAction(
-                R.drawable.ic_menu_refresh, mContext.getString(R.string.reset), mResetIntent);
+        final Notification.Builder builder = new Notification.Builder(mContext)
+                .setWhen(0)
+                .setSmallIcon(iconRes)
+                .setContentTitle(mContext.getString(titleRes))
+                .setContentText(mContext.getString(R.string.vpn_lockdown_config))
+                .setContentIntent(mConfigIntent)
+                .setPriority(Notification.PRIORITY_LOW)
+                .setOngoing(true)
+                .addAction(R.drawable.ic_menu_refresh, mContext.getString(R.string.reset),
+                        mResetIntent)
+                .setColor(mContext.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
 
         NotificationManager.from(mContext).notify(TAG, 0, builder.build());
     }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index bb5243c..9e5fa41 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -791,6 +791,8 @@
         final Notification.Builder builder = new Notification.Builder(mContext);
         builder.setOnlyAlertOnce(true);
         builder.setWhen(0L);
+        builder.setColor(mContext.getResources().getColor(
+                com.android.internal.R.color.system_notification_accent_color));
 
         final Resources res = mContext.getResources();
         switch (type) {
@@ -916,6 +918,8 @@
         builder.setTicker(title);
         builder.setContentTitle(title);
         builder.setContentText(body);
+        builder.setColor(mContext.getResources().getColor(
+                com.android.internal.R.color.system_notification_accent_color));
 
         final Intent intent = buildAllowBackgroundDataIntent();
         builder.setContentIntent(
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index 1b59f52..97f0a1e 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -16,8 +16,6 @@
 
 package com.android.server.notification;
 
-import android.os.IBinder;
-
 public interface NotificationDelegate {
     void onSetDisabled(int status);
     void onClearAll(int callingUid, int callingPid, int userId);
@@ -29,7 +27,6 @@
             int uid, int initialPid, String message, int userId);
     void onPanelRevealed();
     void onPanelHidden();
-    boolean allowDisable(int what, IBinder token, String pkg);
     void onNotificationVisibilityChanged(
             String[] newlyVisibleKeys, String[] noLongerVisibleKeys);
     void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f2ac963..7117933 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -29,7 +29,6 @@
 import android.app.INotificationManager;
 import android.app.ITransientNotification;
 import android.app.Notification;
-import android.app.Notification.Builder;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
@@ -50,7 +49,6 @@
 import android.media.IRingtonePlayer;
 import android.net.Uri;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -585,11 +583,6 @@
         }
 
         @Override
-        public boolean allowDisable(int what, IBinder token, String pkg) {
-            return mZenModeHelper.allowDisable(what, token, pkg);
-        }
-
-        @Override
         public void onNotificationVisibilityChanged(
                 String[] newlyVisibleKeys, String[] noLongerVisibleKeys) {
             // Using ';' as separator since eventlogs uses ',' to separate
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index 525f5f8..f84409e 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -30,10 +30,7 @@
 
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
-import java.util.Arrays;
 import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
 
 public class ZenLog {
     private static final String TAG = "ZenLog";
@@ -45,10 +42,6 @@
     private static final String[] MSGS = new String[SIZE];
 
     private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
-    private static final Set<String> SYSTEM_PACKAGES = new HashSet<String>(Arrays.asList(
-            "android",
-            "com.android.systemui"
-            ));
 
     private static final int TYPE_INTERCEPTED = 1;
     private static final int TYPE_ALLOW_DISABLE = 2;
@@ -76,11 +69,6 @@
         append(TYPE_NOT_INTERCEPTED, record.getKey() + "," + reason);
     }
 
-    public static void traceAllowDisable(String pkg, boolean allowDisable, String reason) {
-        if (SYSTEM_PACKAGES.contains(pkg)) return;
-        append(TYPE_ALLOW_DISABLE, allowDisable + "," + pkg + "," + reason);
-    }
-
     public static void traceSetRingerMode(int ringerMode) {
         append(TYPE_SET_RINGER_MODE, ringerModeToString(ringerMode));
     }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 758f334..0b93690 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -35,7 +35,6 @@
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
@@ -265,18 +264,6 @@
         dispatchOnZenModeChanged();
     }
 
-    public boolean allowDisable(int what, IBinder token, String pkg) {
-        // TODO(cwren): delete this API before the next release. Bug:15344099
-        boolean allowDisable = true;
-        String reason = null;
-        if (isDefaultPhoneApp(pkg)) {
-            allowDisable = mZenMode == Global.ZEN_MODE_OFF || mConfig.allowCalls;
-            reason = mZenMode == Global.ZEN_MODE_OFF ? "zenOff" : "allowCalls";
-        }
-        ZenLog.traceAllowDisable(pkg, allowDisable, reason);
-        return allowDisable;
-    }
-
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mZenMode=");
         pw.println(Global.zenModeToString(mZenMode));
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index dca8ad4..0393518 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.INSTALL_ALL_USERS;
 import static android.content.pm.PackageManager.INSTALL_FROM_ADB;
 import static android.content.pm.PackageManager.INSTALL_REPLACE_EXISTING;
+import static android.net.TrafficStats.MB_IN_BYTES;
 import static com.android.internal.util.XmlUtils.readBitmapAttribute;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -42,6 +43,7 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.IPackageInstallerSession;
@@ -65,6 +67,7 @@
 import android.os.SELinux;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.StorageManager;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.text.TextUtils;
@@ -75,13 +78,14 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageHelper;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.IoThread;
-import com.android.server.pm.PackageInstallerSession.Snapshot;
 import com.google.android.collect.Sets;
 
 import libcore.io.IoUtils;
@@ -108,6 +112,7 @@
 
     // TODO: remove outstanding sessions when installer package goes away
     // TODO: notify listeners in other users when package has been installed there
+    // TODO: purge expired sessions periodically in addition to at reboot
 
     /** XML constants used in {@link #mSessionsFile} */
     private static final String TAG_SESSIONS = "sessions";
@@ -117,6 +122,7 @@
     private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
     private static final String ATTR_CREATED_MILLIS = "createdMillis";
     private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
+    private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
     private static final String ATTR_SEALED = "sealed";
     private static final String ATTR_MODE = "mode";
     private static final String ATTR_INSTALL_FLAGS = "installFlags";
@@ -139,6 +145,7 @@
     private final Context mContext;
     private final PackageManagerService mPm;
     private final AppOpsManager mAppOps;
+    private final StorageManager mStorage;
 
     private final File mStagingDir;
     private final HandlerThread mInstallThread;
@@ -165,10 +172,14 @@
     @GuardedBy("mSessions")
     private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>();
 
+    /** Sessions allocated to legacy users */
+    @GuardedBy("mSessions")
+    private final SparseBooleanArray mLegacySessions = new SparseBooleanArray();
+
     private static final FilenameFilter sStageFilter = new FilenameFilter() {
         @Override
         public boolean accept(File dir, String name) {
-            return name.startsWith("vmdl") && name.endsWith(".tmp");
+            return isStageName(name);
         }
     };
 
@@ -176,6 +187,7 @@
         mContext = context;
         mPm = pm;
         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mStorage = StorageManager.from(mContext);
 
         mStagingDir = stagingDir;
 
@@ -190,13 +202,16 @@
         synchronized (mSessions) {
             readSessionsLocked();
 
-            // Clean up orphaned staging directories
-            final ArraySet<File> stages = Sets.newArraySet(mStagingDir.listFiles(sStageFilter));
+            final ArraySet<File> unclaimed = Sets.newArraySet(mStagingDir.listFiles(sStageFilter));
+
+            // Ignore stages claimed by active sessions
             for (int i = 0; i < mSessions.size(); i++) {
                 final PackageInstallerSession session = mSessions.valueAt(i);
-                stages.remove(session.sessionStageDir);
+                unclaimed.remove(session.internalStageDir);
             }
-            for (File stage : stages) {
+
+            // Clean up orphaned staging directories
+            for (File stage : unclaimed) {
                 Slog.w(TAG, "Deleting orphan stage " + stage);
                 if (stage.isDirectory()) {
                     FileUtils.deleteContents(stage);
@@ -206,22 +221,64 @@
         }
     }
 
-    public static boolean isStageFile(File file) {
-        return sStageFilter.accept(null, file.getName());
+    public void onSecureContainersAvailable() {
+        synchronized (mSessions) {
+            final ArraySet<String> unclaimed = new ArraySet<>();
+            for (String cid : PackageHelper.getSecureContainerList()) {
+                if (isStageName(cid)) {
+                    unclaimed.add(cid);
+                }
+            }
+
+            // Ignore stages claimed by active sessions
+            for (int i = 0; i < mSessions.size(); i++) {
+                final PackageInstallerSession session = mSessions.valueAt(i);
+                final String cid = session.externalStageCid;
+
+                if (unclaimed.remove(cid)) {
+                    // Claimed by active session, mount it
+                    PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
+                            Process.SYSTEM_UID);
+                }
+            }
+
+            // Clean up orphaned staging containers
+            for (String cid : unclaimed) {
+                Slog.w(TAG, "Deleting orphan container " + cid);
+                PackageHelper.destroySdDir(cid);
+            }
+        }
+    }
+
+    public static boolean isStageName(String name) {
+        final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
+        final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
+        final boolean isLegacyContainer = name.startsWith("smdl2tmp");
+        return isFile || isContainer || isLegacyContainer;
     }
 
     @Deprecated
-    public File allocateSessionDir() throws IOException {
+    public File allocateInternalStageDirLegacy() throws IOException {
         synchronized (mSessions) {
             try {
                 final int sessionId = allocateSessionIdLocked();
-                return prepareSessionStageDir(sessionId);
+                mLegacySessions.put(sessionId, true);
+                return prepareInternalStageDir(sessionId);
             } catch (IllegalStateException e) {
                 throw new IOException(e);
             }
         }
     }
 
+    @Deprecated
+    public String allocateExternalStageCidLegacy() {
+        synchronized (mSessions) {
+            final int sessionId = allocateSessionIdLocked();
+            mLegacySessions.put(sessionId, true);
+            return "smdl" + sessionId + ".tmp";
+        }
+    }
+
     private void readSessionsLocked() {
         if (LOGD) Slog.v(TAG, "readSessionsLocked()");
 
@@ -246,9 +303,10 @@
                             Slog.w(TAG, "Abandoning old session first created at "
                                     + session.createdMillis);
                             valid = false;
-                        } else if (!session.sessionStageDir.exists()) {
-                            Slog.w(TAG, "Abandoning session with missing stage "
-                                    + session.sessionStageDir);
+                        } else if (session.internalStageDir != null
+                                && !session.internalStageDir.exists()) {
+                            Slog.w(TAG, "Abandoning internal session with missing stage "
+                                    + session.internalStageDir);
                             valid = false;
                         } else {
                             valid = true;
@@ -281,7 +339,9 @@
         final int userId = readIntAttribute(in, ATTR_USER_ID);
         final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
         final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
-        final File sessionStageDir = new File(readStringAttribute(in, ATTR_SESSION_STAGE_DIR));
+        final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
+        final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
+        final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
         final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
 
         final SessionParams params = new SessionParams(
@@ -299,7 +359,7 @@
 
         return new PackageInstallerSession(mInternalCallback, mContext, mPm,
                 mInstallThread.getLooper(), sessionId, userId, installerPackageName, params,
-                createdMillis, sessionStageDir, sealed);
+                createdMillis, stageDir, stageCid, sealed);
     }
 
     private void writeSessionsLocked() {
@@ -332,7 +392,6 @@
     private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session)
             throws IOException {
         final SessionParams params = session.params;
-        final Snapshot snapshot = session.snapshot();
 
         out.startTag(null, TAG_SESSION);
 
@@ -341,9 +400,14 @@
         writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
                 session.installerPackageName);
         writeLongAttribute(out, ATTR_CREATED_MILLIS, session.createdMillis);
-        writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
-                session.sessionStageDir.getAbsolutePath());
-        writeBooleanAttribute(out, ATTR_SEALED, snapshot.sealed);
+        if (session.internalStageDir != null) {
+            writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
+                    session.internalStageDir.getAbsolutePath());
+        }
+        if (session.externalStageCid != null) {
+            writeStringAttribute(out, ATTR_SESSION_STAGE_CID, session.externalStageCid);
+        }
+        writeBooleanAttribute(out, ATTR_SEALED, session.isSealed());
 
         writeIntAttribute(out, ATTR_MODE, params.mode);
         writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
@@ -372,6 +436,15 @@
 
     @Override
     public int createSession(SessionParams params, String installerPackageName, int userId) {
+        try {
+            return createSessionInternal(params, installerPackageName, userId);
+        } catch (IOException e) {
+            throw ExceptionUtils.wrap(e);
+        }
+    }
+
+    private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
+            throws IOException {
         final int callingUid = Binder.getCallingUid();
         mPm.enforceCrossUserPermission(callingUid, userId, true, "createSession");
 
@@ -393,14 +466,6 @@
             params.installFlags |= INSTALL_REPLACE_EXISTING;
         }
 
-        switch (params.mode) {
-            case SessionParams.MODE_FULL_INSTALL:
-            case SessionParams.MODE_INHERIT_EXISTING:
-                break;
-            default:
-                throw new IllegalArgumentException("Params must have valid mode set");
-        }
-
         // Defensively resize giant app icons
         if (params.appIcon != null) {
             final ActivityManager am = (ActivityManager) mContext.getSystemService(
@@ -413,13 +478,41 @@
             }
         }
 
-        // Sanity check that install could fit
-        if (params.sizeBytes > 0) {
-            try {
-                mPm.freeStorage(params.sizeBytes);
-            } catch (IOException e) {
-                throw ExceptionUtils.wrap(e);
+        // Figure out where we're going to be staging session data
+        final boolean stageInternal;
+
+        if (params.mode == SessionParams.MODE_FULL_INSTALL) {
+            // Brand new install, use best resolved location. This also verifies
+            // that target has enough free space for the install.
+            final int resolved = PackageHelper.resolveInstallLocation(mContext,
+                    params.installLocation, params.sizeBytes, params.installFlags);
+            if (resolved == PackageHelper.RECOMMEND_INSTALL_INTERNAL) {
+                stageInternal = true;
+            } else if (resolved == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
+                stageInternal = false;
+            } else {
+                throw new IOException("No storage with enough free space; res=" + resolved);
             }
+
+        } else if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
+            // We always stage inheriting sessions on internal storage first,
+            // since we don't want to grow containers until we're sure that
+            // everything looks legit.
+            stageInternal = true;
+            checkInternalStorage(params.sizeBytes);
+
+            // If we have a good hunch we'll end up on external storage, verify
+            // free space there too.
+            final ApplicationInfo info = mPm.getApplicationInfo(params.appPackageName, 0,
+                    userId);
+            if (info != null && (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+                checkExternalStorage(params.sizeBytes);
+
+                throw new UnsupportedOperationException("TODO: finish fleshing out ASEC support");
+            }
+
+        } else {
+            throw new IllegalArgumentException("Invalid install mode: " + params.mode);
         }
 
         final int sessionId;
@@ -437,14 +530,21 @@
                         "Too many historical sessions for UID " + callingUid);
             }
 
+            final long createdMillis = System.currentTimeMillis();
             sessionId = allocateSessionIdLocked();
 
-            final long createdMillis = System.currentTimeMillis();
-            final File sessionStageDir = prepareSessionStageDir(sessionId);
+            // We're staging to exactly one location
+            File stageDir = null;
+            String stageCid = null;
+            if (stageInternal) {
+                stageDir = prepareInternalStageDir(sessionId);
+            } else {
+                stageCid = prepareExternalStageCid(sessionId, params.sizeBytes);
+            }
 
             session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
                     mInstallThread.getLooper(), sessionId, userId, installerPackageName, params,
-                    createdMillis, sessionStageDir, false);
+                    createdMillis, stageDir, stageCid, false);
             mSessions.put(sessionId, session);
         }
 
@@ -453,6 +553,29 @@
         return sessionId;
     }
 
+    private void checkInternalStorage(long sizeBytes) throws IOException {
+        if (sizeBytes <= 0) return;
+
+        final File target = Environment.getDataDirectory();
+        final long targetBytes = sizeBytes + mStorage.getStorageLowBytes(target);
+
+        mPm.freeStorage(targetBytes);
+        if (target.getUsableSpace() < targetBytes) {
+            throw new IOException("Not enough internal space to write " + sizeBytes + " bytes");
+        }
+    }
+
+    private void checkExternalStorage(long sizeBytes) throws IOException {
+        if (sizeBytes <= 0) return;
+
+        final File target = Environment.getExternalStorageDirectory();
+        final long targetBytes = sizeBytes + mStorage.getStorageLowBytes(target);
+
+        if (target.getUsableSpace() < targetBytes) {
+            throw new IOException("Not enough external space to write " + sizeBytes + " bytes");
+        }
+    }
+
     @Override
     public IPackageInstallerSession openSession(int sessionId) {
         synchronized (mSessions) {
@@ -463,9 +586,7 @@
             if (!isCallingUidOwner(session)) {
                 throw new SecurityException("Caller has no access to session " + sessionId);
             }
-            if (session.openCount.getAndIncrement() == 0) {
-                mCallbacks.notifySessionOpened(sessionId, session.userId);
-            }
+            session.open();
             return session;
         }
     }
@@ -475,7 +596,8 @@
         int sessionId;
         do {
             sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
-            if (mSessions.get(sessionId) == null && mHistoricalSessions.get(sessionId) == null) {
+            if (mSessions.get(sessionId) == null && mHistoricalSessions.get(sessionId) == null
+                    && !mLegacySessions.get(sessionId, false)) {
                 return sessionId;
             }
         } while (n++ < 32);
@@ -483,11 +605,11 @@
         throw new IllegalStateException("Failed to allocate session ID");
     }
 
-    private File prepareSessionStageDir(int sessionId) {
+    private File prepareInternalStageDir(int sessionId) throws IOException {
         final File file = new File(mStagingDir, "vmdl" + sessionId + ".tmp");
 
         if (file.exists()) {
-            throw new IllegalStateException("Session dir already exists: " + file);
+            throw new IOException("Session dir already exists: " + file);
         }
 
         try {
@@ -495,16 +617,34 @@
             Os.chmod(file.getAbsolutePath(), 0755);
         } catch (ErrnoException e) {
             // This purposefully throws if directory already exists
-            throw new IllegalStateException("Failed to prepare session dir", e);
+            throw new IOException("Failed to prepare session dir", e);
         }
 
         if (!SELinux.restorecon(file)) {
-            throw new IllegalStateException("Failed to restorecon session dir");
+            throw new IOException("Failed to restorecon session dir");
         }
 
         return file;
     }
 
+    private String prepareExternalStageCid(int sessionId, long sizeBytes) throws IOException {
+        if (sizeBytes <= 0) {
+            throw new IOException("Session must provide valid size for ASEC");
+        }
+
+        final String cid = "smdl" + sessionId + ".tmp";
+
+        // Round up to nearest MB, plus another MB for filesystem overhead
+        final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1;
+
+        if (PackageHelper.createSdDir(sizeMb, cid, PackageManagerService.getEncryptKey(),
+                Process.SYSTEM_UID, true) == null) {
+            throw new IOException("Failed to create ASEC");
+        }
+
+        return cid;
+    }
+
     @Override
     public SessionInfo getSessionInfo(int sessionId) {
         synchronized (mSessions) {
@@ -643,7 +783,7 @@
         public void onUserActionRequired(Intent intent) {
             final Intent fillIn = new Intent();
             fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
-                    PackageInstaller.STATUS_USER_ACTION_REQUIRED);
+                    PackageInstaller.STATUS_PENDING_USER_ACTION);
             fillIn.putExtra(Intent.EXTRA_INTENT, intent);
             try {
                 mTarget.sendIntent(mContext, 0, fillIn, null, null);
@@ -679,7 +819,7 @@
         public void onUserActionRequired(Intent intent) {
             final Intent fillIn = new Intent();
             fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
-                    PackageInstaller.STATUS_USER_ACTION_REQUIRED);
+                    PackageInstaller.STATUS_PENDING_USER_ACTION);
             fillIn.putExtra(Intent.EXTRA_INTENT, intent);
             try {
                 mTarget.sendIntent(mContext, 0, fillIn, null, null);
@@ -817,6 +957,11 @@
             }
             pw.println();
             pw.decreaseIndent();
+
+            pw.println("Legacy install sessions:");
+            pw.increaseIndent();
+            pw.println(mLegacySessions.toString());
+            pw.decreaseIndent();
         }
     }
 
@@ -825,6 +970,10 @@
             mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
         }
 
+        public void onSessionOpened(PackageInstallerSession session) {
+            mCallbacks.notifySessionOpened(session.sessionId, session.userId);
+        }
+
         public void onSessionClosed(PackageInstallerSession session) {
             mCallbacks.notifySessionClosed(session.sessionId, session.userId);
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5ef24f2..0616460 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
+import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
 import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
@@ -58,6 +59,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageHelper;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -79,7 +81,6 @@
 
     // TODO: enforce INSTALL_ALLOW_TEST
     // TODO: enforce INSTALL_ALLOW_DOWNGRADE
-    // TODO: handle INSTALL_EXTERNAL, INSTALL_INTERNAL
 
     // TODO: treat INHERIT_EXISTING as installExistingPackage()
 
@@ -93,12 +94,24 @@
     final String installerPackageName;
     final SessionParams params;
     final long createdMillis;
-    final File sessionStageDir;
+
+    /** Internal location where staged data is written. */
+    final File internalStageDir;
+    /** External container where staged data is written. */
+    final String externalStageCid;
+
+    /**
+     * When a {@link SessionParams#MODE_INHERIT_EXISTING} session is installed
+     * into an ASEC, this is the container where the stage is combined with the
+     * existing install.
+     */
+    // TODO: persist this cid once we start splicing
+    String combinedCid;
 
     /** Note that UID is not persisted; it's always derived at runtime. */
     final int installerUid;
 
-    AtomicInteger openCount = new AtomicInteger();
+    private final AtomicInteger mOpenCount = new AtomicInteger();
 
     private final Object mLock = new Object();
 
@@ -119,6 +132,9 @@
     private int mFinalStatus;
     private String mFinalMessage;
 
+    @GuardedBy("mLock")
+    private File mResolvedStageDir;
+
     /**
      * Path to the resolved base APK for this session, which may point at an APK
      * inside the session (when the session defines the base), or it may point
@@ -165,7 +181,7 @@
     public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
             Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
             String installerPackageName, SessionParams params, long createdMillis,
-            File sessionStageDir, boolean sealed) {
+            File internalStageDir, String externalStageCid, boolean sealed) {
         mCallback = callback;
         mContext = context;
         mPm = pm;
@@ -176,7 +192,8 @@
         this.installerPackageName = installerPackageName;
         this.params = params;
         this.createdMillis = createdMillis;
-        this.sessionStageDir = sessionStageDir;
+        this.internalStageDir = internalStageDir;
+        this.externalStageCid = externalStageCid;
 
         mSealed = sealed;
 
@@ -195,23 +212,29 @@
 
     public SessionInfo generateInfo() {
         final SessionInfo info = new SessionInfo();
+        synchronized (mLock) {
+            info.sessionId = sessionId;
+            info.installerPackageName = installerPackageName;
+            info.resolvedBaseCodePath = mResolvedBaseCodePath;
+            info.progress = mProgress;
+            info.sealed = mSealed;
+            info.open = mOpenCount.get() > 0;
 
-        info.sessionId = sessionId;
-        info.installerPackageName = installerPackageName;
-        info.resolvedBaseCodePath = mResolvedBaseCodePath;
-        info.progress = mProgress;
-        info.sealed = mSealed;
-        info.open = openCount.get() > 0;
-
-        info.mode = params.mode;
-        info.sizeBytes = params.sizeBytes;
-        info.appPackageName = params.appPackageName;
-        info.appIcon = params.appIcon;
-        info.appLabel = params.appLabel;
-
+            info.mode = params.mode;
+            info.sizeBytes = params.sizeBytes;
+            info.appPackageName = params.appPackageName;
+            info.appIcon = params.appIcon;
+            info.appLabel = params.appLabel;
+        }
         return info;
     }
 
+    public boolean isSealed() {
+        synchronized (mLock) {
+            return mSealed;
+        }
+    }
+
     private void assertNotSealed(String cookie) {
         synchronized (mLock) {
             if (mSealed) {
@@ -220,6 +243,30 @@
         }
     }
 
+    /**
+     * Resolve the actual location where staged data should be written. This
+     * might point at an ASEC mount point, which is why we delay path resolution
+     * until someone actively works with the session.
+     */
+    private File getStageDir() throws IOException {
+        synchronized (mLock) {
+            if (mResolvedStageDir == null) {
+                if (internalStageDir != null) {
+                    mResolvedStageDir = internalStageDir;
+                } else {
+                    final String path = PackageHelper.getSdDir(externalStageCid);
+                    if (path != null) {
+                        mResolvedStageDir = new File(path);
+                    } else {
+                        throw new IOException(
+                                "Failed to resolve container path for " + externalStageCid);
+                    }
+                }
+            }
+            return mResolvedStageDir;
+        }
+    }
+
     @Override
     public void setClientProgress(float progress) {
         synchronized (mLock) {
@@ -253,7 +300,11 @@
     @Override
     public String[] getNames() {
         assertNotSealed("getNames");
-        return sessionStageDir.list();
+        try {
+            return getStageDir().list();
+        } catch (IOException e) {
+            throw ExceptionUtils.wrap(e);
+        }
     }
 
     @Override
@@ -267,8 +318,6 @@
 
     private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
             throws IOException {
-        // TODO: relay over to DCS when installing to ASEC
-
         // Quick sanity check of state, and allocate a pipe for ourselves. We
         // then do heavy disk allocation outside the lock, but this open pipe
         // will block any attempted install transitions.
@@ -285,7 +334,7 @@
             if (!FileUtils.isValidExtFilename(name)) {
                 throw new IllegalArgumentException("Invalid name: " + name);
             }
-            final File target = new File(sessionStageDir, name);
+            final File target = new File(getStageDir(), name);
 
             final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
                     O_CREAT | O_WRONLY, 0644);
@@ -331,7 +380,7 @@
             if (!FileUtils.isValidExtFilename(name)) {
                 throw new IllegalArgumentException("Invalid name: " + name);
             }
-            final File target = new File(sessionStageDir, name);
+            final File target = new File(getStageDir(), name);
 
             final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), O_RDONLY, 0);
             return new ParcelFileDescriptor(targetFd);
@@ -369,10 +418,18 @@
             // beyond this point we may have hardlinks to the valid install
         }
 
+        final File stageDir;
+        try {
+            stageDir = getStageDir();
+        } catch (IOException e) {
+            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
+                    "Failed to resolve stage dir", e);
+        }
+
         // Verify that stage looks sane with respect to existing application.
         // This currently only ensures packageName, versionCode, and certificate
         // consistency.
-        validateInstallLocked();
+        validateInstallLocked(stageDir);
 
         Preconditions.checkNotNull(mPackageName);
         Preconditions.checkNotNull(mSignatures);
@@ -394,7 +451,8 @@
         // Inherit any packages and native libraries from existing install that
         // haven't been overridden.
         if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
-            spliceExistingFilesIntoStage();
+            // TODO: implement splicing into existing ASEC
+            spliceExistingFilesIntoStage(stageDir);
         }
 
         // TODO: surface more granular state from dexopt
@@ -418,7 +476,8 @@
             }
         };
 
-        mPm.installStage(mPackageName, this.sessionStageDir, localObserver, params,
+        // TODO: send ASEC cid if that's where we staged things
+        mPm.installStage(mPackageName, this.internalStageDir, null, localObserver, params,
                 installerPackageName, installerUid, new UserHandle(userId));
     }
 
@@ -428,13 +487,13 @@
      * <p>
      * Renames package files in stage to match split names defined inside.
      */
-    private void validateInstallLocked() throws PackageManagerException {
+    private void validateInstallLocked(File stageDir) throws PackageManagerException {
         mPackageName = null;
         mVersionCode = -1;
         mSignatures = null;
         mResolvedBaseCodePath = null;
 
-        final File[] files = sessionStageDir.listFiles();
+        final File[] files = stageDir.listFiles();
         if (ArrayUtils.isEmpty(files)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
         }
@@ -480,7 +539,7 @@
                         "Invalid filename: " + targetName);
             }
 
-            final File targetFile = new File(sessionStageDir, targetName);
+            final File targetFile = new File(stageDir, targetName);
             if (!file.equals(targetFile)) {
                 file.renameTo(targetFile);
             }
@@ -550,7 +609,7 @@
      * Application is already installed; splice existing files that haven't been
      * overridden into our stage.
      */
-    private void spliceExistingFilesIntoStage() throws PackageManagerException {
+    private void spliceExistingFilesIntoStage(File stageDir) throws PackageManagerException {
         final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
 
         int n = 0;
@@ -559,7 +618,7 @@
             for (File oldFile : oldFiles) {
                 if (!PackageParser.isApkFile(oldFile)) continue;
 
-                final File newFile = new File(sessionStageDir, oldFile.getName());
+                final File newFile = new File(stageDir, oldFile.getName());
                 try {
                     Os.link(oldFile.getAbsolutePath(), newFile.getAbsolutePath());
                     n++;
@@ -588,9 +647,15 @@
         }
     }
 
+    public void open() {
+        if (mOpenCount.getAndIncrement() == 0) {
+            mCallback.onSessionOpened(this);
+        }
+    }
+
     @Override
     public void close() {
-        if (openCount.decrementAndGet() == 0) {
+        if (mOpenCount.decrementAndGet() == 0) {
             mCallback.onSessionClosed(this);
         }
     }
@@ -621,11 +686,22 @@
             mSealed = true;
             mDestroyed = true;
         }
-        FileUtils.deleteContents(sessionStageDir);
-        sessionStageDir.delete();
+        if (internalStageDir != null) {
+            FileUtils.deleteContents(internalStageDir);
+            internalStageDir.delete();
+        }
+        if (externalStageCid != null) {
+            PackageHelper.destroySdDir(externalStageCid);
+        }
     }
 
     void dump(IndentingPrintWriter pw) {
+        synchronized (mLock) {
+            dumpLocked(pw);
+        }
+    }
+
+    private void dumpLocked(IndentingPrintWriter pw) {
         pw.println("Session " + sessionId + ":");
         pw.increaseIndent();
 
@@ -633,7 +709,8 @@
         pw.printPair("installerPackageName", installerPackageName);
         pw.printPair("installerUid", installerUid);
         pw.printPair("createdMillis", createdMillis);
-        pw.printPair("sessionStageDir", sessionStageDir);
+        pw.printPair("internalStageDir", internalStageDir);
+        pw.printPair("externalStageCid", externalStageCid);
         pw.println();
 
         params.dump(pw);
@@ -650,18 +727,4 @@
 
         pw.decreaseIndent();
     }
-
-    Snapshot snapshot() {
-        return new Snapshot(this);
-    }
-
-    static class Snapshot {
-        final float clientProgress;
-        final boolean sealed;
-
-        public Snapshot(PackageInstallerSession session) {
-            clientProgress = session.mClientProgress;
-            sealed = session.mSealed;
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 63f3c0f..f47e64f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -140,6 +140,7 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Environment.UserEnvironment;
+import android.os.storage.StorageManager;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
@@ -211,6 +212,7 @@
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
 
 /**
  * Keep track of all those .apks everywhere.
@@ -311,8 +313,6 @@
 
     private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
 
-    static final String mTempContainerPrefix = "smdl2tmp";
-
     private static String sPreferredInstructionSet;
 
     final ServiceThread mHandlerThread;
@@ -2931,7 +2931,8 @@
         findPreferredActivity(intent, resolvedType,
                 flags, query, 0, false, true, false, userId);
         // Add the new activity as the last chosen for this filter
-        addPreferredActivityInternal(filter, match, null, activity, false, userId);
+        addPreferredActivityInternal(filter, match, null, activity, false, userId,
+                "Setting last chosen");
     }
 
     @Override
@@ -3203,24 +3204,22 @@
                 if (matches.get(i).getTargetUserId() == targetUserId) return true;
             }
         }
-
         ArrayList<String> packageNames = null;
         SparseArray<ArrayList<String>> fromSource =
                 mSettings.mCrossProfilePackageInfo.get(sourceUserId);
         if (fromSource != null) {
             packageNames = fromSource.get(targetUserId);
-        }
-        if (packageNames != null && packageNames.contains(intent.getPackage())) {
-            return true;
-        }
-        // We need the package name, so we try to resolve with the loosest flags possible
-        List<ResolveInfo> resolveInfos = mActivities.queryIntent(
-                intent, resolvedType, PackageManager.GET_UNINSTALLED_PACKAGES, targetUserId);
-        int count = resolveInfos.size();
-        for (int i = 0; i < count; i++) {
-            ResolveInfo resolveInfo = resolveInfos.get(i);
-            if (packageNames.contains(resolveInfo.activityInfo.packageName)) {
-                return true;
+            if (packageNames != null) {
+                // We need the package name, so we try to resolve with the loosest flags possible
+                List<ResolveInfo> resolveInfos = mActivities.queryIntent(intent, resolvedType,
+                        PackageManager.GET_UNINSTALLED_PACKAGES, targetUserId);
+                int count = resolveInfos.size();
+                for (int i = 0; i < count; i++) {
+                    ResolveInfo resolveInfo = resolveInfos.get(i);
+                    if (packageNames.contains(resolveInfo.activityInfo.packageName)) {
+                        return true;
+                    }
+                }
             }
         }
         return false;
@@ -3293,6 +3292,7 @@
                         intent, resolvedType, flags, userId);
                 if (resolveInfo != null) {
                     result.add(resolveInfo);
+                    Collections.sort(result, mResolvePrioritySorter);
                 }
                 return result;
             }
@@ -4102,21 +4102,24 @@
 
         for (File file : files) {
             final boolean isPackage = (isApkFile(file) || file.isDirectory())
-                    && !PackageInstallerService.isStageFile(file);
+                    && !PackageInstallerService.isStageName(file.getName());
             if (!isPackage) {
-                // Ignore entries which are not apk's
+                // Ignore entries which are not packages
                 continue;
             }
             try {
-                scanPackageLI(file, flags | PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);
+                scanPackageLI(file, flags | PackageParser.PARSE_MUST_BE_APK,
+                        scanMode, currentTime, null);
             } catch (PackageManagerException e) {
                 Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
 
-                // Don't mess around with apps in system partition.
+                // Delete invalid userdata apps
                 if ((flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                         e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
-                    // Delete the apk
-                    Slog.w(TAG, "Cleaning up failed install of " + file);
+                    Slog.w(TAG, "Deleting invalid package at " + file);
+                    if (file.isDirectory()) {
+                        FileUtils.deleteContents(file);
+                    }
                     file.delete();
                 }
             }
@@ -7840,19 +7843,19 @@
         verificationParams.setInstallerUid(uid);
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
-        msg.obj = new InstallParams(originFile, false, observer, filteredFlags,
+        msg.obj = new InstallParams(originFile, null, false, observer, filteredFlags,
                 installerPackageName, verificationParams, user, packageAbiOverride);
         mHandler.sendMessage(msg);
     }
 
-    void installStage(String packageName, File stageDir, IPackageInstallObserver2 observer,
-            PackageInstaller.SessionParams params, String installerPackageName, int installerUid,
-            UserHandle user) {
+    void installStage(String packageName, File stagedDir, String stagedCid,
+            IPackageInstallObserver2 observer, PackageInstaller.SessionParams params,
+            String installerPackageName, int installerUid, UserHandle user) {
         final VerificationParams verifParams = new VerificationParams(null, params.originatingUri,
                 params.referrerUri, installerUid, null);
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
-        msg.obj = new InstallParams(stageDir, true, observer, params.installFlags,
+        msg.obj = new InstallParams(stagedDir, stagedCid, true, observer, params.installFlags,
                 installerPackageName, verifParams, user, params.abiOverride);
         mHandler.sendMessage(msg);
     }
@@ -8552,10 +8555,12 @@
          * file, or a cluster directory. This location may be untrusted.
          */
         final File originFile;
+        final String originCid;
 
         /**
-         * Flag indicating that {@link #originFile} has already been staged,
-         * meaning downstream users don't need to defensively copy the contents.
+         * Flag indicating that {@link #originFile} or {@link #originCid} has
+         * already been staged, meaning downstream users don't need to
+         * defensively copy the contents.
          */
         boolean originStaged;
 
@@ -8568,11 +8573,12 @@
         final String packageAbiOverride;
         boolean multiArch;
 
-        InstallParams(File originFile, boolean originStaged, IPackageInstallObserver2 observer,
-                int flags, String installerPackageName, VerificationParams verificationParams,
-                UserHandle user, String packageAbiOverride) {
+        InstallParams(File originFile, String originCid, boolean originStaged,
+                IPackageInstallObserver2 observer, int flags, String installerPackageName,
+                VerificationParams verificationParams, UserHandle user, String packageAbiOverride) {
             super(user);
-            this.originFile = Preconditions.checkNotNull(originFile);
+            this.originFile = originFile;
+            this.originCid = originCid;
             this.originStaged = originStaged;
             this.observer = observer;
             this.flags = flags;
@@ -8583,9 +8589,8 @@
 
         @Override
         public String toString() {
-            return "InstallParams{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + originFile + "}";
+            return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
+                    + " file=" + originFile + " cid=" + originCid + "}";
         }
 
         public ManifestDigest getManifestDigest() {
@@ -8654,15 +8659,6 @@
             return pkgLite.recommendedInstallLocation;
         }
 
-        private long getMemoryLowThreshold() {
-            final DeviceStorageMonitorInternal
-                    dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
-            if (dsm == null) {
-                return 0L;
-            }
-            return dsm.getMemoryLowThreshold();
-        }
-
         /*
          * Invoke remote method to get package information and install
          * location values. Override install location based on default
@@ -8680,14 +8676,9 @@
                 Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
                 ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
             } else {
-                final long lowThreshold = getMemoryLowThreshold();
-                if (lowThreshold == 0L) {
-                    Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
-                }
-
                 // Remote call to find out default install location
                 final String originPath = originFile.getAbsolutePath();
-                pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags, lowThreshold,
+                pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags,
                         packageAbiOverride);
                 // Keep track of whether this package is a multiArch package until
                 // we perform a full scan of it. We need to do this because we might
@@ -8701,12 +8692,19 @@
                  */
                 if (pkgLite.recommendedInstallLocation
                         == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
-                    final long size = mContainerService.calculateInstalledSize(
+                    // TODO: focus freeing disk space on the target device
+                    final StorageManager storage = StorageManager.from(mContext);
+                    final long lowThreshold = storage.getStorageLowBytes(
+                            Environment.getDataDirectory());
+
+                    final long sizeBytes = mContainerService.calculateInstalledSize(
                             originPath, isForwardLocked(), packageAbiOverride);
-                    if (mInstaller.freeCache(size + lowThreshold) >= 0) {
+
+                    if (mInstaller.freeCache(sizeBytes + lowThreshold) >= 0) {
                         pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags,
-                                lowThreshold, packageAbiOverride);
+                                packageAbiOverride);
                     }
+
                     /*
                      * The cache free must have deleted the file we
                      * downloaded to install.
@@ -9236,24 +9234,11 @@
         }
 
         boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
-            final long lowThreshold;
+            final long sizeBytes = imcs.calculateInstalledSize(originFile.getAbsolutePath(),
+                    isFwdLocked(), abiOverride);
 
-            final DeviceStorageMonitorInternal
-                    dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
-            if (dsm == null) {
-                Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
-                lowThreshold = 0L;
-            } else {
-                if (dsm.isMemoryLow()) {
-                    Log.w(TAG, "Memory is reported as being too low; aborting package install");
-                    return false;
-                }
-
-                lowThreshold = dsm.getMemoryLowThreshold();
-            }
-
-            return imcs.checkInternalFreeStorage(originFile.getAbsolutePath(), isFwdLocked(),
-                    lowThreshold);
+            final StorageManager storage = StorageManager.from(mContext);
+            return (sizeBytes <= storage.getStorageBytesUntilLow(Environment.getDataDirectory()));
         }
 
         int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
@@ -9265,7 +9250,7 @@
                 resourceFile = originFile;
             } else {
                 try {
-                    final File tempDir = mInstallerService.allocateSessionDir();
+                    final File tempDir = mInstallerService.allocateInternalStageDirLegacy();
                     codeFile = tempDir;
                     resourceFile = tempDir;
                 } catch (IOException e) {
@@ -9570,12 +9555,22 @@
         }
 
         void createCopyFile() {
-            cid = getTempContainerId();
+            cid = mInstallerService.allocateExternalStageCidLegacy();
         }
 
         boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
-            return imcs.checkExternalFreeStorage(originFile.getAbsolutePath(), isFwdLocked(),
+            final long sizeBytes = imcs.calculateInstalledSize(packagePath, isFwdLocked(),
                     abiOverride);
+
+            final File target;
+            if (isExternal()) {
+                target = Environment.getExternalStorageDirectory();
+            } else {
+                target = Environment.getDataDirectory();
+            }
+
+            final StorageManager storage = StorageManager.from(mContext);
+            return (sizeBytes <= storage.getStorageBytesUntilLow(target));
         }
 
         private final boolean isExternal() {
@@ -11473,11 +11468,13 @@
     @Override
     public void addPreferredActivity(IntentFilter filter, int match,
             ComponentName[] set, ComponentName activity, int userId) {
-        addPreferredActivityInternal(filter, match, set, activity, true, userId);
+        addPreferredActivityInternal(filter, match, set, activity, true, userId,
+                "Adding preferred");
     }
 
     private void addPreferredActivityInternal(IntentFilter filter, int match,
-            ComponentName[] set, ComponentName activity, boolean always, int userId) {
+            ComponentName[] set, ComponentName activity, boolean always, int userId,
+            String opname) {
         // writer
         int callingUid = Binder.getCallingUid();
         enforceCrossUserPermission(callingUid, userId, true, "add preferred activity");
@@ -11499,10 +11496,11 @@
                         android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
             }
 
-            Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :");
+            PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId);
+            Slog.i(TAG, opname + " activity " + activity.flattenToShortString() + " for user "
+                    + userId + ":");
             filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
-            mSettings.editPreferredActivitiesLPw(userId).addFilter(
-                    new PreferredActivity(filter, match, set, activity, always));
+            pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
             mSettings.writePackageRestrictionsLPr(userId);
         }
     }
@@ -11525,7 +11523,6 @@
 
         final int callingUid = Binder.getCallingUid();
         enforceCrossUserPermission(callingUid, userId, true, "replace preferred activity");
-        final int callingUserId = UserHandle.getUserId(callingUid);
         synchronized (mPackages) {
             if (mContext.checkCallingOrSelfPermission(
                     android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
@@ -11540,30 +11537,63 @@
                         android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
             }
 
-            PreferredIntentResolver pir = mSettings.mPreferredActivities.get(callingUserId);
+            PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
             if (pir != null) {
-                Intent intent = new Intent(filter.getAction(0)).addCategory(filter.getCategory(0));
-                if (filter.countDataSchemes() == 1) {
-                    Uri.Builder builder = new Uri.Builder();
-                    builder.scheme(filter.getDataScheme(0));
-                    intent.setData(builder.build());
-                }
-                List<PreferredActivity> matches = pir.queryIntent(
-                        intent, null, true, callingUserId);
-                if (DEBUG_PREFERRED) {
-                    Slog.i(TAG, matches.size() + " preferred matches for " + intent);
-                }
-                for (int i = 0; i < matches.size(); i++) {
-                    PreferredActivity pa = matches.get(i);
+                // Get all of the existing entries that exactly match this filter.
+                ArrayList<PreferredActivity> existing = pir.findFilters(filter);
+                if (existing != null && existing.size() == 1) {
+                    PreferredActivity cur = existing.get(0);
                     if (DEBUG_PREFERRED) {
-                        Slog.i(TAG, "Removing preferred activity "
-                                + pa.mPref.mComponent + ":");
+                        Slog.i(TAG, "Checking replace of preferred:");
+                        filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
+                        if (!cur.mPref.mAlways) {
+                            Slog.i(TAG, "  -- CUR; not mAlways!");
+                        } else {
+                            Slog.i(TAG, "  -- CUR: mMatch=" + cur.mPref.mMatch);
+                            Slog.i(TAG, "  -- CUR: mSet="
+                                    + Arrays.toString(cur.mPref.mSetComponents));
+                            Slog.i(TAG, "  -- CUR: mComponent=" + cur.mPref.mShortComponent);
+                            Slog.i(TAG, "  -- NEW: mMatch="
+                                    + (match&IntentFilter.MATCH_CATEGORY_MASK));
+                            Slog.i(TAG, "  -- CUR: mSet=" + Arrays.toString(set));
+                            Slog.i(TAG, "  -- CUR: mComponent=" + activity.flattenToShortString());
+                        }
+                    }
+                    if (cur.mPref.mAlways && cur.mPref.mComponent.equals(activity)
+                            && cur.mPref.mMatch == (match&IntentFilter.MATCH_CATEGORY_MASK)
+                            && cur.mPref.sameSet(set)) {
+                        if (DEBUG_PREFERRED) {
+                            Slog.i(TAG, "Replacing with same preferred activity "
+                                    + cur.mPref.mShortComponent + " for user "
+                                    + userId + ":");
+                            filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
+                        } else {
+                            Slog.i(TAG, "Replacing with same preferred activity "
+                                    + cur.mPref.mShortComponent + " for user "
+                                    + userId);
+                        }
+                        return;
+                    }
+                }
+
+                if (existing != null) {
+                    if (DEBUG_PREFERRED) {
+                        Slog.i(TAG, existing.size() + " existing preferred matches for:");
                         filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
                     }
-                    pir.removeFilter(pa);
+                    for (int i = 0; i < existing.size(); i++) {
+                        PreferredActivity pa = existing.get(i);
+                        if (DEBUG_PREFERRED) {
+                            Slog.i(TAG, "Removing existing preferred activity "
+                                    + pa.mPref.mComponent + ":");
+                            pa.dump(new LogPrinter(Log.INFO, TAG), "  ");
+                        }
+                        pir.removeFilter(pa);
+                    }
                 }
             }
-            addPreferredActivityInternal(filter, match, set, activity, true, callingUserId);
+            addPreferredActivityInternal(filter, match, set, activity, true, userId,
+                    "Replacing preferred");
         }
     }
 
@@ -12621,7 +12651,7 @@
 
     private boolean mMediaMounted = false;
 
-    private String getEncryptKey() {
+    static String getEncryptKey() {
         try {
             String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(
                     SD_ENCRYPTION_KEYSTORE_NAME);
@@ -12641,30 +12671,6 @@
             Slog.e(TAG, "Failed to retrieve encryption keys with exception: " + ioe);
             return null;
         }
-
-    }
-
-    /* package */static String getTempContainerId() {
-        int tmpIdx = 1;
-        String list[] = PackageHelper.getSecureContainerList();
-        if (list != null) {
-            for (final String name : list) {
-                // Ignore null and non-temporary container entries
-                if (name == null || !name.startsWith(mTempContainerPrefix)) {
-                    continue;
-                }
-
-                String subStr = name.substring(mTempContainerPrefix.length());
-                try {
-                    int cid = Integer.parseInt(subStr);
-                    if (cid >= tmpIdx) {
-                        tmpIdx = cid + 1;
-                    }
-                } catch (NumberFormatException e) {
-                }
-            }
-        }
-        return mTempContainerPrefix + tmpIdx;
     }
 
     /*
@@ -12722,31 +12728,27 @@
      */
     private void updateExternalMediaStatusInner(boolean isMounted, boolean reportStatus,
             boolean externalStorage) {
-        // Collection of uids
-        int uidArr[] = null;
-        // Collection of stale containers
-        HashSet<String> removeCids = new HashSet<String>();
-        // Collection of packages on external media with valid containers.
-        HashMap<AsecInstallArgs, String> processCids = new HashMap<AsecInstallArgs, String>();
-        // Get list of secure containers.
-        final String list[] = PackageHelper.getSecureContainerList();
-        if (list == null || list.length == 0) {
-            Log.i(TAG, "No secure containers on sdcard");
+        ArrayMap<AsecInstallArgs, String> processCids = new ArrayMap<>();
+        int[] uidArr = EmptyArray.INT;
+
+        final String[] list = PackageHelper.getSecureContainerList();
+        if (ArrayUtils.isEmpty(list)) {
+            Log.i(TAG, "No secure containers found");
         } else {
             // Process list of secure containers and categorize them
             // as active or stale based on their package internal state.
-            int uidList[] = new int[list.length];
-            int num = 0;
+
             // reader
             synchronized (mPackages) {
                 for (String cid : list) {
+                    // Leave stages untouched for now; installer service owns them
+                    if (PackageInstallerService.isStageName(cid)) continue;
+
                     if (DEBUG_SD_INSTALL)
                         Log.i(TAG, "Processing container " + cid);
                     String pkgName = getAsecPackageName(cid);
                     if (pkgName == null) {
-                        if (DEBUG_SD_INSTALL)
-                            Log.i(TAG, "Container : " + cid + " stale");
-                        removeCids.add(cid);
+                        Slog.i(TAG, "Found stale container " + cid + " with no package name");
                         continue;
                     }
                     if (DEBUG_SD_INSTALL)
@@ -12754,8 +12756,7 @@
 
                     final PackageSetting ps = mSettings.mPackages.get(pkgName);
                     if (ps == null) {
-                        Log.i(TAG, "Deleting container with no matching settings " + cid);
-                        removeCids.add(cid);
+                        Slog.i(TAG, "Found stale container " + cid + " with no matching settings");
                         continue;
                     }
 
@@ -12781,35 +12782,25 @@
                         processCids.put(args, ps.codePathString);
                         final int uid = ps.appId;
                         if (uid != -1) {
-                            uidList[num++] = uid;
+                            uidArr = ArrayUtils.appendInt(uidArr, uid);
                         }
                     } else {
-                        Log.i(TAG, "Deleting stale container for " + cid);
-                        removeCids.add(cid);
+                        Slog.i(TAG, "Found stale container " + cid + ": expected codePath="
+                                + ps.codePathString);
                     }
                 }
             }
 
-            if (num > 0) {
-                // Sort uid list
-                Arrays.sort(uidList, 0, num);
-                // Throw away duplicates
-                uidArr = new int[num];
-                uidArr[0] = uidList[0];
-                int di = 0;
-                for (int i = 1; i < num; i++) {
-                    if (uidList[i - 1] != uidList[i]) {
-                        uidArr[di++] = uidList[i];
-                    }
-                }
-            }
+            Arrays.sort(uidArr);
         }
+
         // Process packages with valid entries.
         if (isMounted) {
             if (DEBUG_SD_INSTALL)
                 Log.i(TAG, "Loading packages");
-            loadMediaPackages(processCids, uidArr, removeCids);
+            loadMediaPackages(processCids, uidArr);
             startCleaningPackages();
+            mInstallerService.onSecureContainersAvailable();
         } else {
             if (DEBUG_SD_INSTALL)
                 Log.i(TAG, "Unloading packages");
@@ -12817,8 +12808,8 @@
         }
     }
 
-   private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
-           ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
+    private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
+            ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
         int size = pkgList.size();
         if (size > 0) {
             // Send broadcasts here
@@ -12843,11 +12834,10 @@
      * the cid is added to list of removeCids. We currently don't delete stale
      * containers.
      */
-   private void loadMediaPackages(HashMap<AsecInstallArgs, String> processCids, int uidArr[],
-            HashSet<String> removeCids) {
+    private void loadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int[] uidArr) {
         ArrayList<String> pkgList = new ArrayList<String>();
         Set<AsecInstallArgs> keys = processCids.keySet();
-        boolean doGc = false;
+
         for (AsecInstallArgs args : keys) {
             String codePath = processCids.get(args);
             if (DEBUG_SD_INSTALL)
@@ -12875,7 +12865,6 @@
                     parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
                 }
 
-                doGc = true;
                 synchronized (mInstallLock) {
                     PackageParser.Package pkg = null;
                     try {
@@ -12905,9 +12894,7 @@
 
             } finally {
                 if (retCode != PackageManager.INSTALL_SUCCEEDED) {
-                    // Don't destroy container here. Wait till gc clears things
-                    // up.
-                    removeCids.add(args.cid);
+                    Log.w(TAG, "Container " + args.cid + " is stale, retCode=" + retCode);
                 }
             }
         }
@@ -12942,21 +12929,6 @@
         if (pkgList.size() > 0) {
             sendResourcesChangedBroadcast(true, false, pkgList, uidArr, null);
         }
-        // Force gc to avoid any stale parser references that we might have.
-        if (doGc) {
-            Runtime.getRuntime().gc();
-        }
-        // List stale containers and destroy stale temporary containers.
-        if (removeCids != null) {
-            for (String cid : removeCids) {
-                if (cid.startsWith(mTempContainerPrefix)) {
-                    Log.i(TAG, "Destroying stale temporary container " + cid);
-                    PackageHelper.destroySdDir(cid);
-                } else {
-                    Log.w(TAG, "Container " + cid + " is stale");
-               }
-           }
-        }
     }
 
    /*
@@ -12980,7 +12952,7 @@
      * that we always have to post this message if status has been requested no
      * matter what.
      */
-    private void unloadMediaPackages(HashMap<AsecInstallArgs, String> processCids, int uidArr[],
+    private void unloadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int uidArr[],
             final boolean reportStatus) {
         if (DEBUG_SD_INSTALL)
             Log.i(TAG, "unloading media packages");
diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
index f437372..69c1909 100644
--- a/services/core/java/com/android/server/pm/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -44,10 +44,10 @@
     // Whether this is to be the one that's always chosen. If false, it's the most recently chosen.
     public boolean mAlways;
 
-    private final String[] mSetPackages;
-    private final String[] mSetClasses;
-    private final String[] mSetComponents;
-    private final String mShortComponent;
+    final String[] mSetPackages;
+    final String[] mSetClasses;
+    final String[] mSetComponents;
+    final String mShortComponent;
     private String mParseError;
 
     private final Callbacks mCallbacks;
@@ -193,7 +193,12 @@
     }
 
     public boolean sameSet(List<ResolveInfo> query, int priority) {
-        if (mSetPackages == null) return false;
+        if (mSetPackages == null) {
+            return query == null;
+        }
+        if (query == null) {
+            return false;
+        }
         final int NQ = query.size();
         final int NS = mSetPackages.length;
         int numMatch = 0;
@@ -215,6 +220,27 @@
         return numMatch == NS;
     }
 
+    public boolean sameSet(ComponentName[] comps) {
+        if (mSetPackages == null) return false;
+        final int NQ = comps.length;
+        final int NS = mSetPackages.length;
+        int numMatch = 0;
+        for (int i=0; i<NQ; i++) {
+            ComponentName cn = comps[i];
+            boolean good = false;
+            for (int j=0; j<NS; j++) {
+                if (mSetPackages[j].equals(cn.getPackageName())
+                        && mSetClasses[j].equals(cn.getClassName())) {
+                    numMatch++;
+                    good = true;
+                    break;
+                }
+            }
+            if (!good) return false;
+        }
+        return numMatch == NS;
+    }
+
     public void dump(PrintWriter out, String prefix, Object ident) {
         out.print(prefix); out.print(
                 Integer.toHexString(System.identityHashCode(ident)));
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 41db2c3..9734bd4 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -862,7 +862,8 @@
         }
     }
 
-    private void updateWakeLockWorkSourceInternal(IBinder lock, WorkSource ws, String historyTag) {
+    private void updateWakeLockWorkSourceInternal(IBinder lock, WorkSource ws, String historyTag,
+            int callingUid) {
         synchronized (mLock) {
             int index = findWakeLockIndexLocked(lock);
             if (index < 0) {
@@ -870,7 +871,8 @@
                     Slog.d(TAG, "updateWakeLockWorkSourceInternal: lock=" + Objects.hashCode(lock)
                             + " [not found], ws=" + ws);
                 }
-                throw new IllegalArgumentException("Wake lock not active");
+                throw new IllegalArgumentException("Wake lock not active: " + lock
+                        + " from uid " + callingUid);
             }
 
             WakeLock wakeLock = mWakeLocks.get(index);
@@ -2834,9 +2836,10 @@
                 ws = null;
             }
 
+            final int callingUid = Binder.getCallingUid();
             final long ident = Binder.clearCallingIdentity();
             try {
-                updateWakeLockWorkSourceInternal(lock, ws, historyTag);
+                updateWakeLockWorkSourceInternal(lock, ws, historyTag, callingUid);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 297dacf..f85e2d9 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -22,7 +22,6 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
@@ -39,9 +38,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 
 /**
@@ -187,10 +184,6 @@
 
     @Override
     public void disable(int what, IBinder token, String pkg) {
-        if (!mNotificationDelegate.allowDisable(what, token, pkg)) {
-            if (SPEW) Slog.d(TAG, "Blocking disable request from " + pkg);
-            return;
-        }
         disableInternal(mCurrentUserId, what, token, pkg);
     }
 
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index eb38f4a..468a344 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -453,6 +453,8 @@
         notification.icon = com.android.internal.R.drawable.stat_notify_disk_full;
         notification.tickerText = title;
         notification.flags |= Notification.FLAG_NO_CLEAR;
+        notification.color = context.getResources().getColor(
+                com.android.internal.R.color.system_notification_accent_color);
         notification.setLatestEventInfo(context, title, details, intent);
         notification.visibility = Notification.VISIBILITY_PUBLIC;
         notification.category = Notification.CATEGORY_SYSTEM;
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index e7dd82d..c7d95aa 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -19,12 +19,11 @@
 import android.media.tv.TvInputHardwareInfo;
 import android.media.tv.TvStreamConfig;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.Message;
-import android.view.Surface;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
+import android.view.Surface;
 
 import java.util.LinkedList;
 import java.util.Queue;
@@ -64,12 +63,12 @@
             int generation);
     private static native void nativeClose(long ptr);
 
-    private Object mLock = new Object();
+    private final Object mLock = new Object();
     private long mPtr = 0;
     private final Callback mCallback;
     private final Handler mHandler;
-    private SparseIntArray mStreamConfigGenerations = new SparseIntArray();
-    private SparseArray<TvStreamConfig[]> mStreamConfigs = new SparseArray<>();;
+    private final SparseIntArray mStreamConfigGenerations = new SparseIntArray();
+    private final SparseArray<TvStreamConfig[]> mStreamConfigs = new SparseArray<>();
 
     public TvInputHal(Callback callback) {
         mCallback = callback;
@@ -153,7 +152,7 @@
 
     // Handler.Callback implementation
 
-    private Queue<Message> mPendingMessageQueue = new LinkedList<Message>();
+    private final Queue<Message> mPendingMessageQueue = new LinkedList<Message>();
 
     @Override
     public boolean handleMessage(Message msg) {
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index ae9ae13..fa991c2 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -20,14 +20,12 @@
 import static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED;
 
 import android.content.Context;
-import android.content.Intent;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiHotplugEvent;
 import android.hardware.hdmi.IHdmiControlService;
 import android.hardware.hdmi.IHdmiDeviceEventListener;
 import android.hardware.hdmi.IHdmiHotplugEventListener;
-import android.hardware.hdmi.IHdmiInputChangeListener;
 import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
 import android.media.AudioDevicePort;
 import android.media.AudioFormat;
@@ -39,7 +37,6 @@
 import android.media.AudioPortConfig;
 import android.media.tv.ITvInputHardware;
 import android.media.tv.ITvInputHardwareCallback;
-import android.media.tv.TvContract;
 import android.media.tv.TvInputHardwareInfo;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvStreamConfig;
@@ -77,7 +74,6 @@
 class TvInputHardwareManager implements TvInputHal.Callback {
     private static final String TAG = TvInputHardwareManager.class.getSimpleName();
 
-    private final Context mContext;
     private final Listener mListener;
     private final TvInputHal mHal = new TvInputHal(this);
     private final SparseArray<Connection> mConnections = new SparseArray<>();
@@ -107,7 +103,6 @@
     private final Object mLock = new Object();
 
     public TvInputHardwareManager(Context context, Listener listener) {
-        mContext = context;
         mListener = listener;
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mHal.init();
@@ -963,7 +958,7 @@
                 Object obj = null;
                 switch (status) {
                     case HdmiControlManager.DEVICE_EVENT_ADD_DEVICE: {
-                        if (!mHdmiDeviceList.contains(deviceInfo)) {
+                        if (findHdmiDeviceInfo(deviceInfo.getId()) == null) {
                             mHdmiDeviceList.add(deviceInfo);
                         } else {
                             Slog.w(TAG, "The list already contains " + deviceInfo + "; ignoring.");
@@ -974,7 +969,8 @@
                         break;
                     }
                     case HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE: {
-                        if (!mHdmiDeviceList.remove(deviceInfo)) {
+                        HdmiDeviceInfo originalDeviceInfo = findHdmiDeviceInfo(deviceInfo.getId());
+                        if (!mHdmiDeviceList.remove(originalDeviceInfo)) {
                             Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring.");
                             return;
                         }
@@ -983,13 +979,14 @@
                         break;
                     }
                     case HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE: {
-                        if (!mHdmiDeviceList.remove(deviceInfo)) {
+                        HdmiDeviceInfo originalDeviceInfo = findHdmiDeviceInfo(deviceInfo.getId());
+                        if (!mHdmiDeviceList.remove(originalDeviceInfo)) {
                             Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring.");
                             return;
                         }
                         mHdmiDeviceList.add(deviceInfo);
                         messageType = ListenerHandler.HDMI_DEVICE_UPDATED;
-                        String inputId = mHdmiInputIdMap.get(deviceInfo.getLogicalAddress());
+                        String inputId = mHdmiInputIdMap.get(deviceInfo.getId());
                         SomeArgs args = SomeArgs.obtain();
                         args.arg1 = inputId;
                         args.arg2 = deviceInfo;
@@ -1006,6 +1003,15 @@
                 }
             }
         }
+
+        private HdmiDeviceInfo findHdmiDeviceInfo(int id) {
+            for (HdmiDeviceInfo info : mHdmiDeviceList) {
+                if (info.getId() == id) {
+                    return info;
+                }
+            }
+            return null;
+        }
     }
 
     private final class HdmiSystemAudioModeChangeListener extends
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 88ce860..a084cab 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -691,6 +691,10 @@
     private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
         SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
         if (sessionState.mSession != null) {
+            UserState userState = getUserStateLocked(userId);
+            if (sessionToken == userState.mainSessionToken) {
+                setMainLocked(sessionToken, false, callingUid, userId);
+            }
             try {
                 sessionState.mSession.release();
             } catch (RemoteException e) {
@@ -704,6 +708,9 @@
     private void removeSessionStateLocked(IBinder sessionToken, int userId) {
         UserState userState = getUserStateLocked(userId);
         if (sessionToken == userState.mainSessionToken) {
+            if (DEBUG) {
+                Slog.d(TAG, "mainSessionToken=null");
+            }
             userState.mainSessionToken = null;
         }
 
@@ -740,6 +747,25 @@
         mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_END, args).sendToTarget();
     }
 
+    private void setMainLocked(IBinder sessionToken, boolean isMain, int callingUid, int userId) {
+        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
+        if (sessionState.mHardwareSessionToken != null) {
+            sessionState = getSessionStateLocked(sessionState.mHardwareSessionToken,
+                    Process.SYSTEM_UID, userId);
+        }
+        ServiceState serviceState = getServiceStateLocked(sessionState.mInfo.getComponent(),
+                userId);
+        if (!serviceState.mIsHardware) {
+            return;
+        }
+        ITvInputSession session = getSessionLocked(sessionState);
+        try {
+            session.setMain(isMain);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "error in setMain", e);
+        }
+    }
+
     private void notifyInputAddedLocked(UserState userState, String inputId) {
         if (DEBUG) {
             Slog.d(TAG, "notifyInputAdded: inputId = " + inputId);
@@ -1050,6 +1076,9 @@
 
         @Override
         public void releaseSession(IBinder sessionToken, int userId) {
+            if (DEBUG) {
+                Slog.d(TAG, "releaseSession(): " + sessionToken);
+            }
             final int callingUid = Binder.getCallingUid();
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
                     userId, "releaseSession");
@@ -1065,6 +1094,9 @@
 
         @Override
         public void setMainSession(IBinder sessionToken, int userId) {
+            if (DEBUG) {
+                Slog.d(TAG, "setMainSession(): " + sessionToken);
+            }
             final int callingUid = Binder.getCallingUid();
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
                     userId, "setMainSession");
@@ -1075,50 +1107,19 @@
                     if (userState.mainSessionToken == sessionToken) {
                         return;
                     }
-
-                    SessionState newMainSessionState = getSessionStateLocked(
-                            sessionToken, callingUid, resolvedUserId);
-                    if (newMainSessionState.mHardwareSessionToken != null) {
-                        newMainSessionState = getSessionStateLocked(
-                                newMainSessionState.mHardwareSessionToken,
-                                Process.SYSTEM_UID, resolvedUserId);
+                    if (DEBUG) {
+                        Slog.d(TAG, "mainSessionToken=" + sessionToken);
                     }
-                    ServiceState newMainServiceState = getServiceStateLocked(
-                            newMainSessionState.mInfo.getComponent(), resolvedUserId);
-                    ITvInputSession newMainSession = getSessionLocked(newMainSessionState);
-
-                    ServiceState oldMainServiceState = null;
-                    ITvInputSession oldMainSession = null;
-                    if (userState.mainSessionToken != null) {
-                        SessionState oldMainSessionState = getSessionStateLocked(
-                                userState.mainSessionToken, Process.SYSTEM_UID, resolvedUserId);
-                        if (oldMainSessionState.mHardwareSessionToken != null) {
-                            oldMainSessionState = getSessionStateLocked(
-                                    oldMainSessionState.mHardwareSessionToken,
-                                    Process.SYSTEM_UID, resolvedUserId);
-                        }
-                        oldMainServiceState = getServiceStateLocked(
-                                oldMainSessionState.mInfo.getComponent(), resolvedUserId);
-                        oldMainSession = getSessionLocked(oldMainSessionState);
-                    }
-
+                    IBinder oldMainSessionToken = userState.mainSessionToken;
                     userState.mainSessionToken = sessionToken;
 
                     // Inform the new main session first.
-                    // See {@link TvInputService#onSetMainSession}.
-                    if (newMainServiceState.mIsHardware) {
-                        try {
-                            newMainSession.setMainSession(true);
-                        } catch (RemoteException e) {
-                            Slog.e(TAG, "error in setMainSession", e);
-                        }
+                    // See {@link TvInputService.Session#onSetMain}.
+                    if (sessionToken != null) {
+                        setMainLocked(sessionToken, true, callingUid, userId);
                     }
-                    if (oldMainSession != null && oldMainServiceState.mIsHardware) {
-                        try {
-                            oldMainSession.setMainSession(false);
-                        } catch (RemoteException e) {
-                            Slog.e(TAG, "error in setMainSession", e);
-                        }
+                    if (oldMainSessionToken != null) {
+                        setMainLocked(oldMainSessionToken, false, Process.SYSTEM_UID, userId);
                     }
                 }
             } finally {
@@ -1800,11 +1801,8 @@
                 UserState userState = getUserStateLocked(mUserId);
                 for (SessionState sessionState : userState.sessionStateMap.values()) {
                     if (mSessionToken == sessionState.mHardwareSessionToken) {
-                        try {
-                            sessionState.mSession.release();
-                        } catch (RemoteException e) {
-                            Slog.e(TAG, "error in release", e);
-                        }
+                        releaseSessionLocked(sessionState.mSessionToken, Process.SYSTEM_UID,
+                                mUserId);
                         try {
                             sessionState.mClient.onSessionReleased(sessionState.mSeq);
                         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 112972f..b57a090 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -51,6 +51,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.animation.ValueAnimator;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -58,6 +59,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
+import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
@@ -428,7 +430,7 @@
     /**
      * Stores for each user whether screencapture is disabled
      * This array is essentially a cache for all userId for
-     * {@link android.app.admin.DevicePolicyManager#getScreenCaptureDisabled(null, userId)}
+     * {@link android.app.admin.DevicePolicyManager#getScreenCaptureDisabled}
      */
     SparseArray<Boolean> mScreenCaptureDisabled = new SparseArray<Boolean>();
 
@@ -539,6 +541,21 @@
     boolean mHardKeyboardAvailable;
     boolean mShowImeWithHardKeyboard;
     OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
+    SettingsObserver mSettingsObserver;
+
+    private final class SettingsObserver extends ContentObserver {
+        public SettingsObserver() {
+            super(new Handler());
+            ContentResolver resolver = mContext.getContentResolver();
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            updateShowImeWithHardKeyboard();
+        }
+    }
 
     final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
 
@@ -838,6 +855,9 @@
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
+        mSettingsObserver = new SettingsObserver();
+        updateShowImeWithHardKeyboard();
+
         mHoldingScreenWakeLock = mPowerManager.newWakeLock(
                 PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG);
         mHoldingScreenWakeLock.setReferenceCounted(false);
@@ -2315,9 +2335,12 @@
                       return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             } else if (token.appWindowToken != null) {
-                Slog.i(TAG, "Non-null appWindowToken for system window of type=" + type);
-                // app token should be null for any other window types.
-                token.appWindowToken = null;
+                Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type);
+                // It is not valid to use an app token with other system types; we will
+                // instead make a new token for it (as if null had been passed in for the token).
+                attrs.token = null;
+                token = new WindowToken(this, null, -1, false);
+                addToken = true;
             }
 
             win = new WindowState(this, session, client, token,
@@ -7015,7 +7038,6 @@
             boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
             if (hardKeyboardAvailable != mHardKeyboardAvailable) {
                 mHardKeyboardAvailable = hardKeyboardAvailable;
-                mShowImeWithHardKeyboard = !hardKeyboardAvailable;
                 mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
                 mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
             }
@@ -7039,18 +7061,12 @@
         }
     }
 
-    public boolean isShowImeWithHardKeyboardEnabled() {
+    public void updateShowImeWithHardKeyboard() {
+        boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser(
+                mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0,
+                mCurrentUserId) == 1;
         synchronized (mWindowMap) {
-            return mShowImeWithHardKeyboard;
-        }
-    }
-
-    public void setShowImeWithHardKeyboard(boolean enabled) {
-        synchronized (mWindowMap) {
-            if (mShowImeWithHardKeyboard != enabled) {
-                mShowImeWithHardKeyboard = enabled;
-                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
-            }
+            mShowImeWithHardKeyboard = showImeWithHardKeyboard;
         }
     }
 
@@ -7062,15 +7078,14 @@
     }
 
     void notifyHardKeyboardStatusChange() {
-        final boolean available, showImeWithHardKeyboard;
+        final boolean available;
         final OnHardKeyboardStatusChangeListener listener;
         synchronized (mWindowMap) {
             listener = mHardKeyboardStatusChangeListener;
             available = mHardKeyboardAvailable;
-            showImeWithHardKeyboard = mShowImeWithHardKeyboard;
         }
         if (listener != null) {
-            listener.onHardKeyboardStatusChange(available, showImeWithHardKeyboard);
+            listener.onHardKeyboardStatusChange(available);
         }
     }
 
@@ -11053,7 +11068,7 @@
     }
 
     public interface OnHardKeyboardStatusChangeListener {
-        public void onHardKeyboardStatusChange(boolean available, boolean showIme);
+        public void onHardKeyboardStatusChange(boolean available);
     }
 
     void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 61c50d67..7bf090a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1211,6 +1211,12 @@
                 || w.mDecorFrame.isEmpty()) {
             // The universe background isn't cropped, nor windows without policy decor.
             w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
+        } else if (w.mAttrs.type == LayoutParams.TYPE_WALLPAPER && mAnimator.mAnimating) {
+            // If we're animating, the wallpaper crop should only be updated at the end of the
+            // animation.
+            mTmpClipRect.set(w.mSystemDecorRect);
+            applyDecorRect(w.mDecorFrame);
+            w.mSystemDecorRect.union(mTmpClipRect);
         } else {
             // Crop to the system decor specified by policy.
             applyDecorRect(w.mDecorFrame);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d46ae42..2c3c510 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1517,6 +1517,8 @@
             .setContentIntent(notifyIntent)
             .setPriority(Notification.PRIORITY_HIGH)
             .setShowWhen(false)
+            .setColor(mContext.getResources().getColor(
+                    com.android.internal.R.color.system_notification_accent_color))
             .build();
 
         // If this is a boot intent, this will fire for each user. But if this is a storage changed
@@ -4442,44 +4444,39 @@
      * This function can only be called by the device owner.
      * @param components The list of components allowed to enter lock task mode.
      */
-    public void setLockTaskPackages(String[] packages) throws SecurityException {
-        // Get the package names of the caller.
-        int uid = Binder.getCallingUid();
-        String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
-
+    public void setLockTaskPackages(ComponentName who, String[] packages) throws SecurityException {
         synchronized (this) {
-            // Check whether any of the package name is the device owner.
-            for (int i=0; i<packageNames.length; i++) {
-                String packageName = packageNames[i];
-                int userHandle = UserHandle.getUserId(uid);
-                if (isDeviceOwner(packageName)) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
-                    // If a package name is the device owner,
-                    // we update the component list.
-                    DevicePolicyData policy = getUserData(userHandle);
-                    policy.mLockTaskPackages.clear();
-                    if (packages != null) {
-                        for (int j = 0; j < packages.length; j++) {
-                            String pkg = packages[j];
-                            policy.mLockTaskPackages.add(pkg);
-                        }
-                    }
-
-                    // Store the settings persistently.
-                    saveSettingsLocked(userHandle);
-                    return;
+            int userHandle = Binder.getCallingUserHandle().getIdentifier();
+            DevicePolicyData policy = getUserData(userHandle);
+            policy.mLockTaskPackages.clear();
+            if (packages != null) {
+                for (int j = 0; j < packages.length; j++) {
+                    String pkg = packages[j];
+                    policy.mLockTaskPackages.add(pkg);
                 }
             }
+
+            // Store the settings persistently.
+            saveSettingsLocked(userHandle);
         }
-        throw new SecurityException();
     }
 
     /**
      * This function returns the list of components allowed to start the task lock mode.
      */
-    public String[] getLockTaskPackages() {
+    public String[] getLockTaskPackages(ComponentName who) {
         synchronized (this) {
-            int userHandle = UserHandle.USER_OWNER;
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+
+            int userHandle = Binder.getCallingUserHandle().getIdentifier();
             DevicePolicyData policy = getUserData(userHandle);
             return policy.mLockTaskPackages.toArray(new String[0]);
         }
@@ -4517,15 +4514,18 @@
         synchronized (this) {
             final DevicePolicyData policy = getUserData(userHandle);
             Bundle adminExtras = new Bundle();
-            adminExtras.putBoolean(DeviceAdminReceiver.EXTRA_LOCK_TASK_ENTERING, isEnabled);
             adminExtras.putString(DeviceAdminReceiver.EXTRA_LOCK_TASK_PACKAGE, pkg);
             for (ActiveAdmin admin : policy.mAdminList) {
                 boolean ownsDevice = isDeviceOwner(admin.info.getPackageName());
                 boolean ownsProfile = (getProfileOwner(userHandle) != null
                         && getProfileOwner(userHandle).equals(admin.info.getPackageName()));
                 if (ownsDevice || ownsProfile) {
-                    sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_LOCK_TASK_CHANGED,
-                            adminExtras, null);
+                    if (isEnabled) {
+                        sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_LOCK_TASK_ENTERING,
+                                adminExtras, null);
+                    } else {
+                        sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_LOCK_TASK_EXITING);
+                    }
                 }
             }
         }
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 7400dde..6a56de0 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -783,7 +783,9 @@
                     .setContentIntent(pendingIntent)
                     .setWhen(System.currentTimeMillis())
                     .setAutoCancel(true)
-                    .setShowWhen(true);
+                    .setShowWhen(true)
+                    .setColor(mContext.getResources().getColor(
+                            com.android.internal.R.color.system_notification_accent_color));
 
             NotificationManager notificationManager = (NotificationManager) mContext
                     .getSystemService(Context.NOTIFICATION_SERVICE);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index c0923ca..c078cb2 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -732,6 +732,8 @@
                                     "com.android.settings.UsbSettings"));
                     PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
                             intent, 0, null, UserHandle.CURRENT);
+                    notification.color = mContext.getResources().getColor(
+                            com.android.internal.R.color.system_notification_accent_color);
                     notification.setLatestEventInfo(mContext, title, message, pi);
                     notification.visibility = Notification.VISIBILITY_PUBLIC;
                     mNotificationManager.notifyAsUser(null, id, notification,
@@ -768,6 +770,8 @@
                                     "com.android.settings.DevelopmentSettings"));
                     PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
                             intent, 0, null, UserHandle.CURRENT);
+                    notification.color = mContext.getResources().getColor(
+                            com.android.internal.R.color.system_notification_accent_color);
                     notification.setLatestEventInfo(mContext, title, message, pi);
                     notification.visibility = Notification.VISIBILITY_PUBLIC;
                     mAdbNotificationShown = true;
diff --git a/telecomm/java/android/telecomm/AudioState.java b/telecomm/java/android/telecomm/AudioState.java
index dc28b16..491af14 100644
--- a/telecomm/java/android/telecomm/AudioState.java
+++ b/telecomm/java/android/telecomm/AudioState.java
@@ -56,14 +56,12 @@
     /** Bit vector of all routes supported by this call. */
     public final int supportedRouteMask;
 
-    /** @hide */
     public AudioState(boolean isMuted, int route, int supportedRouteMask) {
         this.isMuted = isMuted;
         this.route = route;
         this.supportedRouteMask = supportedRouteMask;
     }
 
-    /** @hide */
     public AudioState(AudioState state) {
         isMuted = state.isMuted;
         route = state.route;
diff --git a/telecomm/java/android/telecomm/Call.java b/telecomm/java/android/telecomm/Call.java
index 7223574..d90ec13 100644
--- a/telecomm/java/android/telecomm/Call.java
+++ b/telecomm/java/android/telecomm/Call.java
@@ -363,6 +363,7 @@
     private final Phone mPhone;
     private final String mTelecommCallId;
     private final InCallAdapter mInCallAdapter;
+    private final List<String> mChildrenIds = new ArrayList<>();
     private final List<Call> mChildren = new ArrayList<>();
     private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
     private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
@@ -370,7 +371,8 @@
     private final List<Call> mUnmodifiableConferenceableCalls =
             Collections.unmodifiableList(mConferenceableCalls);
 
-    private Call mParent = null;
+    private boolean mChildrenCached;
+    private String mParentId = null;
     private int mState;
     private List<String> mCannedTextResponses = null;
     private String mRemainingPostDialSequence;
@@ -513,7 +515,10 @@
      * child of any conference {@code Call}s.
      */
     public Call getParent() {
-        return mParent;
+        if (mParentId != null) {
+            return mPhone.internalGetCallByTelecommId(mParentId);
+        }
+        return null;
     }
 
     /**
@@ -523,6 +528,21 @@
      * {@code List} otherwise.
      */
     public List<Call> getChildren() {
+        if (!mChildrenCached) {
+            mChildrenCached = true;
+            mChildren.clear();
+
+            for(String id : mChildrenIds) {
+                Call call = mPhone.internalGetCallByTelecommId(id);
+                if (call == null) {
+                    // At least one child was still not found, so do not save true for "cached"
+                    mChildrenCached = false;
+                } else {
+                    mChildren.add(call);
+                }
+            }
+        }
+
         return mUnmodifiableChildren;
     }
 
@@ -648,16 +668,18 @@
             mState = state;
         }
 
-        if (parcelableCall.getParentCallId() != null) {
-            mParent = mPhone.internalGetCallByTelecommId(parcelableCall.getParentCallId());
+        String parentId = parcelableCall.getParentCallId();
+        boolean parentChanged = !Objects.equals(mParentId, parentId);
+        if (parentChanged) {
+            mParentId = parentId;
         }
 
-        mChildren.clear();
-        if (parcelableCall.getChildCallIds() != null) {
-            for (int i = 0; i < parcelableCall.getChildCallIds().size(); i++) {
-                mChildren.add(mPhone.internalGetCallByTelecommId(
-                        parcelableCall.getChildCallIds().get(i)));
-            }
+        List<String> childCallIds = parcelableCall.getChildCallIds();
+        boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
+        if (childrenChanged) {
+            mChildrenIds.clear();
+            mChildrenIds.addAll(parcelableCall.getChildCallIds());
+            mChildrenCached = false;
         }
 
         List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
@@ -689,6 +711,12 @@
         if (videoCallChanged) {
             fireVideoCallChanged(mVideoCall);
         }
+        if (parentChanged) {
+            fireParentChanged(getParent());
+        }
+        if (childrenChanged) {
+            fireChildrenChanged(getChildren());
+        }
 
         // If we have transitioned to DISCONNECTED, that means we need to notify clients and
         // remove ourselves from the Phone. Note that we do this after completing all state updates
diff --git a/telecomm/java/android/telecomm/Conference.java b/telecomm/java/android/telecomm/Conference.java
new file mode 100644
index 0000000..34b9dae
--- /dev/null
+++ b/telecomm/java/android/telecomm/Conference.java
@@ -0,0 +1,238 @@
+/*
+ * 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.telephony.DisconnectCause;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * Represents a conference call which can contain any number of {@link Connection} objects.
+ */
+public abstract class Conference {
+
+    /** @hide */
+    public abstract static class Listener {
+        public void onStateChanged(Conference conference, int oldState, int newState) {}
+        public void onDisconnected(Conference conference, int cause, String message) {}
+        public void onConnectionAdded(Conference conference, Connection connection) {}
+        public void onConnectionRemoved(Conference conference, Connection connection) {}
+        public void onDestroyed(Conference conference) {}
+        public void onCapabilitiesChanged(Conference conference, int capabilities) {}
+    }
+
+    private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
+    private final List<Connection> mChildConnections = new CopyOnWriteArrayList<>();
+    private final List<Connection> mUnmodifiableChildConnection =
+            Collections.unmodifiableList(mChildConnections);
+
+    private PhoneAccountHandle mPhoneAccount;
+    private int mState = Connection.STATE_NEW;
+    private int mDisconnectCause = DisconnectCause.NOT_VALID;
+    private int mCapabilities;
+    private String mDisconnectMessage;
+
+    public Conference(PhoneAccountHandle phoneAccount) {
+        mPhoneAccount = phoneAccount;
+    }
+
+    public final PhoneAccountHandle getPhoneAccount() {
+        return mPhoneAccount;
+    }
+
+    public final List<Connection> getConnections() {
+        return mUnmodifiableChildConnection;
+    }
+
+    public final int getState() {
+        return mState;
+    }
+
+    public final int getCapabilities() {
+        return mCapabilities;
+    }
+
+    /**
+     * Invoked when the Conference and all it's {@link Connection}s should be disconnected.
+     */
+    public void onDisconnect() {}
+
+    /**
+     * Invoked when the specified {@link Connection} should be separated from the conference call.
+     *
+     * @param connection The connection to separate.
+     */
+    public void onSeparate(Connection connection) {}
+
+    /**
+     * Invoked when the conference should be put on hold.
+     */
+    public void onHold() {}
+
+    /**
+     * Invoked when the conference should be moved from hold to active.
+     */
+    public void onUnhold() {}
+
+    /**
+     * Sets state to be on hold.
+     */
+    public final void setOnHold() {
+        setState(Connection.STATE_HOLDING);
+    }
+
+    /**
+     * Sets state to be active.
+     */
+    public final void setActive() {
+        setState(Connection.STATE_ACTIVE);
+    }
+
+    /**
+     * Sets state to disconnected.
+     *
+     * @param cause The reason for the disconnection, any of
+     *         {@link android.telephony.DisconnectCause}.
+     * @param message Optional call-service-provided message about the disconnect.
+     */
+    public final void setDisconnected(int cause, String message) {
+        mDisconnectCause = cause;
+        mDisconnectMessage = message;
+        setState(Connection.STATE_DISCONNECTED);
+        for (Listener l : mListeners) {
+            l.onDisconnected(this, mDisconnectCause, mDisconnectMessage);
+        }
+    }
+
+    /**
+     * Sets the cabilities of a conference.
+     */
+    public final void setCapabilities(int capabilities) {
+        if (capabilities != mCapabilities) {
+            mCapabilities = capabilities;
+
+            for (Listener l : mListeners) {
+                l.onCapabilitiesChanged(this, mCapabilities);
+            }
+        }
+    }
+
+    /**
+     * Adds the specified connection as a child of this conference.
+     *
+     * @param connection The connection to add.
+     * @return True if the connection was successfully added.
+     */
+    public boolean addConnection(Connection connection) {
+        if (connection != null && !mChildConnections.contains(connection)) {
+            if (connection.setConference(this)) {
+                mChildConnections.add(connection);
+                for (Listener l : mListeners) {
+                    l.onConnectionAdded(this, connection);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes the specified connection as a child of this conference.
+     *
+     * @param connection The connection to remove.
+     * @return True if the connection was successfully removed.
+     */
+    public void removeConnection(Connection connection) {
+        if (connection != null && mChildConnections.remove(connection)) {
+            connection.resetConference();
+            for (Listener l : mListeners) {
+                l.onConnectionRemoved(this, connection);
+            }
+        }
+    }
+
+    /**
+     * Tears down the conference object and any of it's current connections.
+     */
+    public void destroy() {
+        Log.d(this, "destroying conference : %s", this);
+        // Tear down the children.
+        for (Connection connection : new ArrayList<>(mChildConnections)) {
+            Log.d(this, "removing connection %s", connection);
+            removeConnection(connection);
+        }
+
+        // If not yet disconnected, set the conference call as disconnected first.
+        if (mState != Connection.STATE_DISCONNECTED) {
+            Log.d(this, "setting to disconnected");
+            setDisconnected(DisconnectCause.LOCAL, null);
+        }
+
+        // ...and notify.
+        for (Listener l : mListeners) {
+            l.onDestroyed(this);
+        }
+    }
+
+    /**
+     * Add a listener to be notified of a state change.
+     *
+     * @param listener The new listener.
+     * @return This conference.
+     * @hide
+     */
+    public final Conference addListener(Listener listener) {
+        mListeners.add(listener);
+        return this;
+    }
+
+    /**
+     * Removes the specified listener.
+     *
+     * @param listener The listener to remove.
+     * @return This conference.
+     * @hide
+     */
+    public final Conference removeListener(Listener listener) {
+        mListeners.remove(listener);
+        return this;
+    }
+
+    private void setState(int newState) {
+        if (newState != Connection.STATE_ACTIVE &&
+                newState != Connection.STATE_HOLDING &&
+                newState != Connection.STATE_DISCONNECTED) {
+            Log.w(this, "Unsupported state transition for Conference call.",
+                    Connection.stateToString(newState));
+            return;
+        }
+
+        if (mState != newState) {
+            int oldState = mState;
+            mState = newState;
+            for (Listener l : mListeners) {
+                l.onStateChanged(this, oldState, newState);
+            }
+        }
+    }
+}
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 78c34a1..c1d5715 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -36,6 +36,15 @@
 
 /**
  * Represents a connection to a remote endpoint that carries voice traffic.
+ * <p>
+ * Implementations create a custom subclass of {@code Connection} and return it to the framework
+ * as the return value of
+ * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}
+ * or
+ * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
+ * Implementations are then responsible for updating the state of the {@code Connection}, and
+ * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no
+ * longer used and associated resources may be recovered.
  */
 public abstract class Connection {
 
@@ -53,10 +62,6 @@
 
     public static final int STATE_DISCONNECTED = 6;
 
-    public static final int STATE_FAILED = 7;
-
-    public static final int STATE_CANCELED = 8;
-
     // Flag controlling whether PII is emitted into the logs
     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
 
@@ -74,7 +79,6 @@
         public void onRequestingRingback(Connection c, boolean ringback) {}
         public void onDestroyed(Connection c) {}
         public void onCallCapabilitiesChanged(Connection c, int callCapabilities) {}
-        public void onParentConnectionChanged(Connection c, Connection parent) {}
         public void onVideoProviderChanged(
                 Connection c, VideoProvider videoProvider) {}
         public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
@@ -82,6 +86,7 @@
         public void onStartActivityFromInCall(Connection c, PendingIntent intent) {}
         public void onConferenceableConnectionsChanged(
                 Connection c, List<Connection> conferenceableConnections) {}
+        public void onConferenceChanged(Connection c, Conference conference) {}
     }
 
     public static abstract class VideoProvider {
@@ -455,9 +460,6 @@
      */
     private final Set<Listener> mListeners = Collections.newSetFromMap(
             new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
-    private final List<Connection> mChildConnections = new ArrayList<>();
-    private final List<Connection> mUnmodifiableChildConnections =
-            Collections.unmodifiableList(mChildConnections);
     private final List<Connection> mConferenceableConnections = new ArrayList<>();
     private final List<Connection> mUnmodifiableConferenceableConnections =
             Collections.unmodifiableList(mConferenceableConnections);
@@ -470,7 +472,6 @@
     private int mCallerDisplayNamePresentation;
     private boolean mRequestingRingback = false;
     private int mCallCapabilities;
-    private Connection mParentConnection;
     private VideoProvider mVideoProvider;
     private boolean mAudioModeIsVoip;
     private StatusHints mStatusHints;
@@ -478,6 +479,8 @@
     private int mFailureCode;
     private String mFailureMessage;
     private boolean mIsCanceled;
+    private Conference mConference;
+    private ConnectionService mConnectionService;
 
     /**
      * Create a new Connection.
@@ -543,6 +546,14 @@
     }
 
     /**
+     * @return The conference that this connection is a part of.  Null if it is not part of any
+     *         conference.
+     */
+    public final Conference getConference() {
+        return mConference;
+    }
+
+    /**
      * Returns whether this connection is requesting that the system play a ringback tone
      * on its behalf.
      */
@@ -551,13 +562,6 @@
     }
 
     /**
-     * Returns whether this connection is a conference connection (has child connections).
-     */
-    public final boolean isConferenceConnection() {
-        return !mChildConnections.isEmpty();
-    }
-
-    /**
      * @return True if the connection's audio mode is VOIP.
      */
     public final boolean getAudioModeIsVoip() {
@@ -645,10 +649,6 @@
                 return "STATE_HOLDING";
             case STATE_DISCONNECTED:
                 return "DISCONNECTED";
-            case STATE_FAILED:
-                return "STATE_FAILED";
-            case STATE_CANCELED:
-                return "STATE_CANCELED";
             default:
                 Log.wtf(Connection.class, "Unknown state %d", state);
                 return "UNKNOWN";
@@ -656,34 +656,6 @@
     }
 
     /**
-     * TODO: Needs documentation.
-     */
-    public final void setParentConnection(Connection parentConnection) {
-        Log.d(this, "parenting %s to %s", this, parentConnection);
-        if (mParentConnection != parentConnection) {
-            if (mParentConnection != null) {
-                mParentConnection.removeChild(this);
-            }
-            mParentConnection = parentConnection;
-            if (mParentConnection != null) {
-                mParentConnection.addChild(this);
-                // do something if the child connections goes down to ZERO.
-            }
-            for (Listener l : mListeners) {
-                l.onParentConnectionChanged(this, mParentConnection);
-            }
-        }
-    }
-
-    public final Connection getParentConnection() {
-        return mParentConnection;
-    }
-
-    public final List<Connection> getChildConnections() {
-        return mUnmodifiableChildConnections;
-    }
-
-    /**
      * Returns the connection's {@link PhoneCapabilities}
      */
     public final int getCallCapabilities() {
@@ -723,33 +695,6 @@
     }
 
     /**
-     * Cancel the {@link Connection}. Once this is called, the {@link Connection} will not be used,
-     * and no subsequent {@link Connection}s will be attempted.
-     */
-    public final void setCanceled() {
-        Log.d(this, "setCanceled");
-        setState(STATE_CANCELED);
-    }
-
-    /**
-     * Move the {@link Connection} to the {@link #STATE_FAILED} state, with the given code
-     * ({@see DisconnectCause}) and message. This message is not shown to the user, but is useful
-     * for logging and debugging purposes.
-     * <p>
-     * After calling this, the {@link Connection} will not be used.
-     *
-     * @param code The {@link DisconnectCause} indicating why the connection
-     *             failed.
-     * @param message A message explaining why the {@link Connection} failed.
-     */
-    public final void setFailed(int code, String message) {
-        Log.d(this, "setFailed (%d: %s)", code, message);
-        mFailureCode = code;
-        mFailureMessage = message;
-        setState(STATE_FAILED);
-    }
-
-    /**
      * Set the video state for the connection.
      * Valid values: {@link VideoProfile.VideoState#AUDIO_ONLY},
      * {@link VideoProfile.VideoState#BIDIRECTIONAL},
@@ -936,6 +881,60 @@
         return mUnmodifiableConferenceableConnections;
     }
 
+    /*
+     * @hide
+     */
+    public final void setConnectionService(ConnectionService connectionService) {
+        if (mConnectionService != null) {
+            Log.e(this, new Exception(), "Trying to set ConnectionService on a connection " +
+                    "which is already associated with another ConnectionService.");
+        } else {
+            mConnectionService = connectionService;
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public final void unsetConnectionService(ConnectionService connectionService) {
+        if (mConnectionService != connectionService) {
+            Log.e(this, new Exception(), "Trying to remove ConnectionService from a Connection " +
+                    "that does not belong to the ConnectionService.");
+        } else {
+            mConnectionService = null;
+        }
+    }
+
+    /**
+     * Sets the conference that this connection is a part of. This will fail if the connection is
+     * already part of a conference call. {@link #resetConference} to un-set the conference first.
+     *
+     * @param conference The conference.
+     * @return {@code true} if the conference was successfully set.
+     * @hide
+     */
+    public final boolean setConference(Conference conference) {
+        // We check to see if it is already part of another conference.
+        if (mConference == null && mConnectionService != null &&
+                mConnectionService.containsConference(conference)) {
+            mConference = conference;
+            fireConferenceChanged();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Resets the conference that this connection is a part of.
+     * @hide
+     */
+    public final void resetConference() {
+        if (mConference != null) {
+            mConference = null;
+            fireConferenceChanged();
+        }
+    }
+
     /**
      * Launches an activity for this connection on top of the in-call UI.
      *
@@ -1022,11 +1021,6 @@
     public void onPostDialContinue(boolean proceed) {}
 
     /**
-     * TODO: Needs documentation.
-     */
-    public void onChildrenChanged(List<Connection> children) {}
-
-    /**
      * Called when the phone account UI was clicked.
      */
     public void onPhoneAccountClicked() {}
@@ -1073,22 +1067,9 @@
         return sNullConnection;
     }
 
-    private void addChild(Connection connection) {
-        Log.d(this, "adding child %s", connection);
-        mChildConnections.add(connection);
-        onChildrenChanged(mChildConnections);
-    }
-
-    private void removeChild(Connection connection) {
-        Log.d(this, "removing child %s", connection);
-        mChildConnections.remove(connection);
-        onChildrenChanged(mChildConnections);
-    }
-
     private void setState(int state) {
-        if (mState == STATE_FAILED || mState == STATE_CANCELED) {
-            Log.d(this, "Connection already %s; cannot transition out of this state.",
-                    stateToString(mState));
+        if (mState == STATE_DISCONNECTED && mState != state) {
+            Log.d(this, "Connection already DISCONNECTED; cannot transition out of this state.");
             return;
         }
         if (mState != state) {
@@ -1101,33 +1082,41 @@
         }
     }
 
+    static class FailureSignalingConnection extends Connection {
+        public FailureSignalingConnection(int code, String message) {
+            setDisconnected(code, message);
+        }
+    }
+
     /**
-     * Return a {@link Connection} which represents a failed connection attempt. The returned
-     * {@link Connection} will have {@link #getFailureCode()}, {@link #getFailureMessage()}, and
-     * {@link #getState()} set appropriately, but the {@link Connection} itself should not be used
-     * for anything.
+     * Return a {@code Connection} which represents a failed connection attempt. The returned
+     * {@code Connection} will have a {@link #getFailureCode()} and {@link #getFailureMessage()}
+     * as specified, a {@link #getState()} of {@link #STATE_DISCONNECTED}.
+     * <p>
+     * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate,
+     * so users of this method need not maintain a reference to its return value to destroy it.
      *
      * @param code The failure code ({@see DisconnectCause}).
      * @param message A reason for why the connection failed (not intended to be shown to the user).
-     * @return A {@link Connection} which indicates failure.
+     * @return A {@code Connection} which indicates failure.
      */
     public static Connection createFailedConnection(final int code, final String message) {
-        return new Connection() {{
-            setFailed(code, message);
-        }};
+        return new FailureSignalingConnection(code, message);
     }
 
-    private static final Connection CANCELED_CONNECTION = new Connection() {{
-        setCanceled();
-    }};
+    private static final Connection CANCELED_CONNECTION =
+            new FailureSignalingConnection(DisconnectCause.OUTGOING_CANCELED, null);
 
     /**
-     * Return a {@link Connection} which represents a canceled a connection attempt. The returned
-     * {@link Connection} will have state {@link #STATE_CANCELED}, and cannot be moved out of that
-     * state. This connection should not be used for anything, and no other {@link Connection}s
-     * should be attempted.
+     * Return a {@code Connection} which represents a canceled connection attempt. The returned
+     * {@code Connection} will have state {@link #STATE_DISCONNECTED}, and cannot be moved out of
+     * that state. This connection should not be used for anything, and no other
+     * {@code Connection}s should be attempted.
+     * <p>
+     * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate,
+     * so users of this method need not maintain a reference to its return value to destroy it.
      *
-     * @return A {@link Connection} which indicates that the underlying call should be canceled.
+     * @return A {@code Connection} which indicates that the underlying call should be canceled.
      */
     public static Connection createCanceledConnection() {
         return CANCELED_CONNECTION;
@@ -1139,6 +1128,12 @@
         }
     }
 
+    private final void fireConferenceChanged() {
+        for (Listener l : mListeners) {
+            l.onConferenceChanged(this, mConference);
+        }
+    }
+
     private final void clearConferenceableList() {
         for (Connection c : mConferenceableConnections) {
             c.removeConnectionListener(mConnectionDeathListener);
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index d2d4828..03b6c7b 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -39,6 +39,8 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
 
 /**
  * A {@link android.app.Service} that provides telephone connections to processes running on an
@@ -73,12 +75,14 @@
 
     private final Map<String, Connection> mConnectionById = new HashMap<>();
     private final Map<Connection, String> mIdByConnection = new HashMap<>();
+    private final Map<String, Conference> mConferenceById = new HashMap<>();
+    private final Map<Conference, String> mIdByConference = new HashMap<>();
     private final RemoteConnectionManager mRemoteConnectionManager = new RemoteConnectionManager();
-
-    private boolean mAreAccountsInitialized = false;
     private final List<Runnable> mPreInitializationConnectionRequests = new ArrayList<>();
     private final ConnectionServiceAdapter mAdapter = new ConnectionServiceAdapter();
 
+    private boolean mAreAccountsInitialized = false;
+
     private final IBinder mBinder = new IConnectionService.Stub() {
         @Override
         public void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
@@ -155,10 +159,10 @@
         }
 
         @Override
-        public void conference(String conferenceCallId, String callId) {
+        public void conference(String callId1, String callId2) {
             SomeArgs args = SomeArgs.obtain();
-            args.arg1 = conferenceCallId;
-            args.arg2 = callId;
+            args.arg1 = callId1;
+            args.arg2 = callId2;
             mHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget();
         }
 
@@ -270,9 +274,9 @@
                 case MSG_CONFERENCE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
-                        String conferenceCallId = (String) args.arg1;
-                        String callId = (String) args.arg2;
-                        conference(conferenceCallId, callId);
+                        String callId1 = (String) args.arg1;
+                        String callId2 = (String) args.arg2;
+                        conference(callId1, callId2);
                     } finally {
                         args.recycle();
                     }
@@ -301,6 +305,51 @@
         }
     };
 
+    private final Conference.Listener mConferenceListener = new Conference.Listener() {
+        @Override
+        public void onStateChanged(Conference conference, int oldState, int newState) {
+            String id = mIdByConference.get(conference);
+            switch (newState) {
+                case Connection.STATE_ACTIVE:
+                    mAdapter.setActive(id);
+                    break;
+                case Connection.STATE_HOLDING:
+                    mAdapter.setOnHold(id);
+                    break;
+                case Connection.STATE_DISCONNECTED:
+                    // handled by onDisconnected
+                    break;
+            }
+        }
+
+        @Override
+        public void onDisconnected(Conference conference, int cause, String message) {
+            String id = mIdByConference.get(conference);
+            mAdapter.setDisconnected(id, cause, message);
+        }
+
+        @Override
+        public void onConnectionAdded(Conference conference, Connection connection) {
+        }
+
+        @Override
+        public void onConnectionRemoved(Conference conference, Connection connection) {
+        }
+
+        @Override
+        public void onDestroyed(Conference conference) {
+            removeConference(conference);
+        }
+
+        @Override
+        public void onCapabilitiesChanged(Conference conference, int capabilities) {
+            String id = mIdByConference.get(conference);
+            Log.d(this, "call capabilities: conference: %s",
+                    PhoneCapabilities.toString(capabilities));
+            mAdapter.setCallCapabilities(id, capabilities);
+        }
+    };
+
     private final Connection.Listener mConnectionListener = new Connection.Listener() {
         @Override
         public void onStateChanged(Connection c, int state) {
@@ -383,13 +432,6 @@
         }
 
         @Override
-        public void onParentConnectionChanged(Connection c, Connection parent) {
-            String id = mIdByConnection.get(c);
-            String parentId = parent == null ? null : mIdByConnection.get(parent);
-            mAdapter.setIsConferenced(id, parentId);
-        }
-
-        @Override
         public void onVideoProviderChanged(Connection c, Connection.VideoProvider videoProvider) {
             String id = mIdByConnection.get(c);
             mAdapter.setVideoProvider(id, videoProvider);
@@ -426,6 +468,18 @@
             Collections.sort(conferenceableCallIds);
             mAdapter.setConferenceableConnections(id, conferenceableCallIds);
         }
+
+        @Override
+        public void onConferenceChanged(Connection connection, Conference conference) {
+            String id = mIdByConnection.get(connection);
+            if (id != null) {
+                String conferenceId = null;
+                if (conference != null) {
+                    conferenceId = mIdByConference.get(conference);
+                }
+                mAdapter.setIsConferenced(id, conferenceId);
+            }
+        }
     };
 
     /** {@inheritDoc} */
@@ -446,74 +500,26 @@
             boolean isIncoming) {
         Log.d(this, "call %s", request);
 
-        final Connection createdConnection;
-        if (isIncoming) {
-            createdConnection = onCreateIncomingConnection(callManagerAccount, request);
-        } else {
-            createdConnection = onCreateOutgoingConnection(callManagerAccount, request);
-        }
+        Connection createdConnection = isIncoming
+                ? onCreateIncomingConnection(callManagerAccount, request)
+                : onCreateOutgoingConnection(callManagerAccount, request);
 
-        if (createdConnection != null) {
-            Log.d(this, "adapter handleCreateConnectionSuccessful %s", callId);
-            if (createdConnection.getState() == Connection.STATE_INITIALIZING) {
-                // Wait for the connection to become initialized.
-                createdConnection.addConnectionListener(new Connection.Listener() {
-                    @Override
-                    public void onStateChanged(Connection c, int state) {
-                        switch (state) {
-                            case Connection.STATE_FAILED:
-                                Log.d(this, "Connection (%s) failed (%d: %s)", request,
-                                        c.getFailureCode(), c.getFailureMessage());
-                                Log.d(this, "adapter handleCreateConnectionFailed %s",
-                                        callId);
-                                mAdapter.handleCreateConnectionFailed(
-                                        callId,
-                                        request,
-                                        c.getFailureCode(),
-                                        c.getFailureMessage());
-                                break;
-                            case Connection.STATE_CANCELED:
-                                Log.d(this, "adapter handleCreateConnectionCanceled %s",
-                                        callId);
-                                mAdapter.handleCreateConnectionCancelled(callId, request);
-                                break;
-                            case Connection.STATE_INITIALIZING:
-                                Log.d(this, "State changed to STATE_INITIALIZING; ignoring");
-                                return; // Don't want to stop listening on this state transition.
-                        }
-                        c.removeConnectionListener(this);
-                    }
-                });
-                Log.d(this, "Connection created in state INITIALIZING");
-                connectionCreated(callId, request, createdConnection);
-            } else if (createdConnection.getState() == Connection.STATE_CANCELED) {
-                // Tell telecomm not to attempt any more services.
-                mAdapter.handleCreateConnectionCancelled(callId, request);
-            } else if (createdConnection.getState() == Connection.STATE_FAILED) {
-                mAdapter.handleCreateConnectionFailed(
-                        callId,
-                        request,
-                        createdConnection.getFailureCode(),
-                        createdConnection.getFailureMessage());
-            } else {
-                connectionCreated(callId, request, createdConnection);
-            }
-        } else {
+        if (createdConnection == null) {
+            Log.d(this, "adapter handleCreateConnectionComplete CANCELED %s", callId);
             // Tell telecomm to try a different service.
-            Log.d(this, "adapter handleCreateConnectionFailed %s", callId);
-            mAdapter.handleCreateConnectionFailed(
-                    callId,
-                    request,
-                    DisconnectCause.ERROR_UNSPECIFIED,
-                    null);
+            createdConnection = Connection.createCanceledConnection();
         }
+        connectionCreated(callId, request, createdConnection);
     }
 
     private void connectionCreated(
             String callId,
             ConnectionRequest request,
             Connection connection) {
-        addConnection(callId, connection);
+        if (!(connection instanceof Connection.FailureSignalingConnection)) {
+            addConnection(callId, connection);
+        }
+
         Uri handle = connection.getHandle();
         String number = handle == null ? "null" : handle.getSchemeSpecificPart();
         Log.v(this, "connectionCreated, parcelableconnection: %s, %d, %s",
@@ -522,7 +528,7 @@
                 PhoneCapabilities.toString(connection.getCallCapabilities()));
 
         Log.d(this, "adapter handleCreateConnectionSuccessful %s", callId);
-        mAdapter.handleCreateConnectionSuccessful(
+        mAdapter.handleCreateConnectionComplete(
                 callId,
                 request,
                 new ParcelableConnection(
@@ -538,7 +544,9 @@
                         connection.getVideoState(),
                         connection.isRequestingRingback(),
                         connection.getAudioModeIsVoip(),
-                        connection.getStatusHints()));
+                        connection.getStatusHints(),
+                        connection.getFailureCode(),
+                        connection.getFailureMessage()));
     }
 
     private void abort(String callId) {
@@ -586,38 +594,22 @@
         findConnectionForAction(callId, "stopDtmfTone").onStopDtmfTone();
     }
 
-    private void conference(final String conferenceCallId, String callId) {
-        Log.d(this, "conference %s, %s", conferenceCallId, callId);
+    private void conference(String callId1, String callId2) {
+        Log.d(this, "conference %s, %s", callId1, callId2);
 
-        Connection connection = findConnectionForAction(callId, "conference");
-        if (connection == Connection.getNullConnection()) {
-            Log.w(this, "Connection missing in conference request %s.", callId);
+        Connection connection1 = findConnectionForAction(callId1, "conference");
+        if (connection1 == Connection.getNullConnection()) {
+            Log.w(this, "Connection1 missing in conference request %s.", callId1);
             return;
         }
 
-        onCreateConferenceConnection(conferenceCallId, connection,
-                new Response<String, Connection>() {
-                    /** ${inheritDoc} */
-                    @Override
-                    public void onResult(String ignored, Connection... result) {
-                        Log.d(this, "onCreateConference.Response %s", (Object[]) result);
-                        if (result != null && result.length == 1) {
-                            Connection conferenceConnection = result[0];
-                            if (!mIdByConnection.containsKey(conferenceConnection)) {
-                                Log.v(this, "sending new conference call %s", conferenceCallId);
-                                mAdapter.addConferenceCall(conferenceCallId);
-                                addConnection(conferenceCallId, conferenceConnection);
-                            }
-                        }
-                    }
+        Connection connection2 = findConnectionForAction(callId2, "conference");
+        if (connection2 == Connection.getNullConnection()) {
+            Log.w(this, "Connection2 missing in conference request %s.", callId2);
+            return;
+        }
 
-                    /** ${inheritDoc} */
-                    @Override
-                    public void onError(String request, int code, String reason) {
-                        // no-op
-                    }
-                }
-        );
+        onConference(connection1, connection2);
     }
 
     private void splitFromConference(String callId) {
@@ -654,7 +646,8 @@
                     final List<ComponentName> componentNames,
                     final List<IBinder> services) {
                 mHandler.post(new Runnable() {
-                    @Override public void run() {
+                    @Override
+                    public void run() {
                         for (int i = 0; i < componentNames.size() && i < services.size(); i++) {
                             mRemoteConnectionManager.addConnectionService(
                                     componentNames.get(i),
@@ -669,7 +662,8 @@
             @Override
             public void onError() {
                 mHandler.post(new Runnable() {
-                    @Override public void run() {
+                    @Override
+                    public void run() {
                         mAreAccountsInitialized = true;
                     }
                 });
@@ -712,6 +706,40 @@
     }
 
     /**
+     * Adds a new conference call. When a conference call is created either as a result of an
+     * explicit request via {@link #onConference} or otherwise, the connection service should supply
+     * an instance of {@link Conference} by invoking this method. A conference call provided by this
+     * method will persist until {@link Conference#destroy} is invoked on the conference instance.
+     *
+     * @param conference The new conference object.
+     */
+    public final void addConference(Conference conference) {
+        String id = addConferenceInternal(conference);
+        if (id != null) {
+            List<String> connectionIds = new ArrayList<>(2);
+            for (Connection connection : conference.getConnections()) {
+                if (mIdByConnection.containsKey(connection)) {
+                    connectionIds.add(mIdByConnection.get(connection));
+                }
+            }
+            ParcelableConference parcelableConference = new ParcelableConference(
+                    conference.getPhoneAccount(),
+                    conference.getState(),
+                    conference.getCapabilities(),
+                    connectionIds);
+            mAdapter.addConferenceCall(id, parcelableConference);
+
+            // Go through any child calls and set the parent.
+            for (Connection connection : conference.getConnections()) {
+                String connectionId = mIdByConnection.get(connection);
+                if (connectionId != null) {
+                    mAdapter.setIsConferenced(connectionId, id);
+                }
+            }
+        }
+    }
+
+    /**
      * Returns all the active {@code Connection}s for which this {@code ConnectionService}
      * has taken responsibility.
      *
@@ -767,22 +795,14 @@
     }
 
     /**
-     * Returns a new or existing conference connection when the the user elects to convert the
-     * specified connection into a conference call. The specified connection can be any connection
-     * which had previously specified itself as conference-capable including both simple connections
-     * and connections previously returned from this method.
-     * <p>
-     * TODO: To be refactored out with conference call re-engineering<br/>
-     * TODO: Also remove class {@link Response} once this method is removed
+     * Conference two specified connections. Invoked when the user has made a request to merge the
+     * specified connections into a conference call. In response, the connection service should
+     * create an instance of {@link Conference} and pass it into {@link #addConference}.
      *
-     * @param connection The connection from which the user opted to start a conference call.
-     * @param token The token to be passed into the response callback.
-     * @param callback The callback for providing the potentially-new conference connection.
+     * @param connection1 A connection to merge into a conference call.
+     * @param connection2 A connection to merge into a conference call.
      */
-    public void onCreateConferenceConnection(
-            String token,
-            Connection connection,
-            Response<String, Connection> callback) {}
+    public void onConference(Connection connection1, Connection connection2) {}
 
     /**
      * Notifies that a connection has been added to this connection service and sent to Telecomm.
@@ -798,6 +818,13 @@
      */
     public void onConnectionRemoved(Connection connection) {}
 
+    /**
+     * @hide
+     */
+    public boolean containsConference(Conference conference) {
+        return mIdByConference.containsKey(conference);
+    }
+
     private void onAccountsInitialized() {
         mAreAccountsInitialized = true;
         for (Runnable r : mPreInitializationConnectionRequests) {
@@ -810,11 +837,13 @@
         mConnectionById.put(callId, connection);
         mIdByConnection.put(connection, callId);
         connection.addConnectionListener(mConnectionListener);
+        connection.setConnectionService(this);
         onConnectionAdded(connection);
     }
 
     private void removeConnection(Connection connection) {
         String id = mIdByConnection.get(connection);
+        connection.unsetConnectionService(this);
         connection.removeConnectionListener(mConnectionListener);
         mConnectionById.remove(mIdByConnection.get(connection));
         mIdByConnection.remove(connection);
@@ -822,6 +851,31 @@
         mAdapter.removeCall(id);
     }
 
+    private String addConferenceInternal(Conference conference) {
+        if (mIdByConference.containsKey(conference)) {
+            Log.w(this, "Re-adding an existing conference: %s.", conference);
+        } else if (conference != null) {
+            String id = UUID.randomUUID().toString();
+            mConferenceById.put(id, conference);
+            mIdByConference.put(conference, id);
+            conference.addListener(mConferenceListener);
+            return id;
+        }
+
+        return null;
+    }
+
+    private void removeConference(Conference conference) {
+        if (mIdByConference.containsKey(conference)) {
+            conference.removeListener(mConferenceListener);
+
+            String id = mIdByConference.get(conference);
+            mConferenceById.remove(id);
+            mIdByConference.remove(conference);
+            mAdapter.removeCall(id);
+        }
+    }
+
     private Connection findConnectionForAction(String callId, String action) {
         if (mConnectionById.containsKey(callId)) {
             return mConnectionById.get(callId);
diff --git a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
index 4144b81..41c6360 100644
--- a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
@@ -76,37 +76,13 @@
         }
     }
 
-    void handleCreateConnectionSuccessful(
+    void handleCreateConnectionComplete(
             String id,
             ConnectionRequest request,
             ParcelableConnection connection) {
         for (IConnectionServiceAdapter adapter : mAdapters) {
             try {
-                adapter.handleCreateConnectionSuccessful(id, request, connection);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    void handleCreateConnectionFailed(
-            String id,
-            ConnectionRequest request,
-            int errorCode,
-            String errorMsg) {
-        for (IConnectionServiceAdapter adapter : mAdapters) {
-            try {
-                adapter.handleCreateConnectionFailed(id, request, errorCode, errorMsg);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    void handleCreateConnectionCancelled(
-            String id,
-            ConnectionRequest request) {
-        for (IConnectionServiceAdapter adapter : mAdapters) {
-            try {
-                adapter.handleCreateConnectionCancelled(id, request);
+                adapter.handleCreateConnectionComplete(id, request, connection);
             } catch (RemoteException e) {
             }
         }
@@ -256,10 +232,10 @@
      *
      * @param callId The unique ID of the conference call.
      */
-    void addConferenceCall(String callId) {
+    void addConferenceCall(String callId, ParcelableConference parcelableConference) {
         for (IConnectionServiceAdapter adapter : mAdapters) {
             try {
-                adapter.addConferenceCall(callId);
+                adapter.addConferenceCall(callId, parcelableConference);
             } catch (RemoteException ignored) {
             }
         }
diff --git a/telecomm/java/android/telecomm/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecomm/ConnectionServiceAdapterServant.java
index 2632924..0e1c516 100644
--- a/telecomm/java/android/telecomm/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecomm/ConnectionServiceAdapterServant.java
@@ -38,29 +38,27 @@
  * @hide
  */
 final class ConnectionServiceAdapterServant {
-    private static final int MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL = 1;
-    private static final int MSG_HANDLE_CREATE_CONNECTION_FAILED = 2;
-    private static final int MSG_HANDLE_CREATE_CONNECTION_CANCELLED = 3;
-    private static final int MSG_SET_ACTIVE = 4;
-    private static final int MSG_SET_RINGING = 5;
-    private static final int MSG_SET_DIALING = 6;
-    private static final int MSG_SET_DISCONNECTED = 7;
-    private static final int MSG_SET_ON_HOLD = 8;
-    private static final int MSG_SET_REQUESTING_RINGBACK = 9;
-    private static final int MSG_SET_CALL_CAPABILITIES = 10;
-    private static final int MSG_SET_IS_CONFERENCED = 11;
-    private static final int MSG_ADD_CONFERENCE_CALL = 12;
-    private static final int MSG_REMOVE_CALL = 13;
-    private static final int MSG_ON_POST_DIAL_WAIT = 14;
-    private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 15;
-    private static final int MSG_SET_VIDEO_STATE = 16;
-    private static final int MSG_SET_VIDEO_CALL_PROVIDER = 17;
-    private static final int MSG_SET_AUDIO_MODE_IS_VOIP = 18;
-    private static final int MSG_SET_STATUS_HINTS = 19;
-    private static final int MSG_SET_HANDLE = 20;
-    private static final int MSG_SET_CALLER_DISPLAY_NAME = 21;
-    private static final int MSG_START_ACTIVITY_FROM_IN_CALL = 22;
-    private static final int MSG_SET_CONFERENCEABLE_CONNECTIONS = 23;
+    private static final int MSG_HANDLE_CREATE_CONNECTION_COMPLETE = 1;
+    private static final int MSG_SET_ACTIVE = 2;
+    private static final int MSG_SET_RINGING = 3;
+    private static final int MSG_SET_DIALING = 4;
+    private static final int MSG_SET_DISCONNECTED = 5;
+    private static final int MSG_SET_ON_HOLD = 6;
+    private static final int MSG_SET_REQUESTING_RINGBACK = 7;
+    private static final int MSG_SET_CALL_CAPABILITIES = 8;
+    private static final int MSG_SET_IS_CONFERENCED = 9;
+    private static final int MSG_ADD_CONFERENCE_CALL = 10;
+    private static final int MSG_REMOVE_CALL = 11;
+    private static final int MSG_ON_POST_DIAL_WAIT = 12;
+    private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 13;
+    private static final int MSG_SET_VIDEO_STATE = 14;
+    private static final int MSG_SET_VIDEO_CALL_PROVIDER = 15;
+    private static final int MSG_SET_AUDIO_MODE_IS_VOIP = 16;
+    private static final int MSG_SET_STATUS_HINTS = 17;
+    private static final int MSG_SET_HANDLE = 18;
+    private static final int MSG_SET_CALLER_DISPLAY_NAME = 19;
+    private static final int MSG_START_ACTIVITY_FROM_IN_CALL = 20;
+    private static final int MSG_SET_CONFERENCEABLE_CONNECTIONS = 21;
 
     private final IConnectionServiceAdapter mDelegate;
 
@@ -76,10 +74,10 @@
         // Internal method defined to centralize handling of RemoteException
         private void internalHandleMessage(Message msg) throws RemoteException {
             switch (msg.what) {
-                case MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL: {
+                case MSG_HANDLE_CREATE_CONNECTION_COMPLETE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
-                        mDelegate.handleCreateConnectionSuccessful(
+                        mDelegate.handleCreateConnectionComplete(
                                 (String) args.arg1,
                                 (ConnectionRequest) args.arg2,
                                 (ParcelableConnection) args.arg3);
@@ -88,30 +86,6 @@
                     }
                     break;
                 }
-                case MSG_HANDLE_CREATE_CONNECTION_FAILED: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        mDelegate.handleCreateConnectionFailed(
-                                (String) args.arg1,
-                                (ConnectionRequest) args.arg2,
-                                args.argi1,
-                                (String) args.arg3);
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_HANDLE_CREATE_CONNECTION_CANCELLED: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        mDelegate.handleCreateConnectionCancelled(
-                                (String) args.arg1,
-                                (ConnectionRequest) args.arg2);
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
                 case MSG_SET_ACTIVE:
                     mDelegate.setActive((String) msg.obj);
                     break;
@@ -149,9 +123,16 @@
                     }
                     break;
                 }
-                case MSG_ADD_CONFERENCE_CALL:
-                    mDelegate.addConferenceCall((String) msg.obj);
+                case MSG_ADD_CONFERENCE_CALL: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        mDelegate.addConferenceCall(
+                                (String) args.arg1, (ParcelableConference) args.arg2);
+                    } finally {
+                        args.recycle();
+                    }
                     break;
+                }
                 case MSG_REMOVE_CALL:
                     mDelegate.removeCall((String) msg.obj);
                     break;
@@ -237,7 +218,7 @@
 
     private final IConnectionServiceAdapter mStub = new IConnectionServiceAdapter.Stub() {
         @Override
-        public void handleCreateConnectionSuccessful(
+        public void handleCreateConnectionComplete(
                 String id,
                 ConnectionRequest request,
                 ParcelableConnection connection) {
@@ -245,31 +226,7 @@
             args.arg1 = id;
             args.arg2 = request;
             args.arg3 = connection;
-            mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL, args).sendToTarget();
-        }
-
-        @Override
-        public void handleCreateConnectionFailed(
-                String id,
-                ConnectionRequest request,
-                int errorCode,
-                String errorMessage) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = id;
-            args.arg2 = request;
-            args.argi1 = errorCode;
-            args.arg3 = errorMessage;
-            mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_FAILED, args).sendToTarget();
-        }
-
-        @Override
-        public void handleCreateConnectionCancelled(
-                String id,
-                ConnectionRequest request) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = id;
-            args.arg2 = request;
-            mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_CANCELLED, args).sendToTarget();
+            mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_COMPLETE, args).sendToTarget();
         }
 
         @Override
@@ -323,8 +280,11 @@
         }
 
         @Override
-        public void addConferenceCall(String callId) {
-            mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, callId).sendToTarget();
+        public void addConferenceCall(String callId, ParcelableConference parcelableConference) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = parcelableConference;
+            mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, args).sendToTarget();
         }
 
         @Override
diff --git a/telecomm/java/android/telecomm/InCallService.java b/telecomm/java/android/telecomm/InCallService.java
index de05d1c..5795e0e 100644
--- a/telecomm/java/android/telecomm/InCallService.java
+++ b/telecomm/java/android/telecomm/InCallService.java
@@ -16,6 +16,7 @@
 
 package android.telecomm;
 
+import android.annotation.SdkConstant;
 import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Intent;
@@ -39,6 +40,13 @@
  * {@hide}
  */
 public abstract class InCallService extends Service {
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.telecomm.InCallService";
+
     private static final int MSG_SET_IN_CALL_ADAPTER = 1;
     private static final int MSG_ADD_CALL = 2;
     private static final int MSG_UPDATE_CALL = 3;
diff --git a/media/java/android/media/routing/IMediaRouter.aidl b/telecomm/java/android/telecomm/ParcelableConference.aidl
similarity index 73%
copy from media/java/android/media/routing/IMediaRouter.aidl
copy to telecomm/java/android/telecomm/ParcelableConference.aidl
index 0abb258..a260085 100644
--- a/media/java/android/media/routing/IMediaRouter.aidl
+++ b/telecomm/java/android/telecomm/ParcelableConference.aidl
@@ -1,10 +1,11 @@
-/* Copyright (C) 2014 The Android Open Source Project
+/*
+ * Copyright 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
+ *     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,
@@ -13,10 +14,6 @@
  * limitations under the License.
  */
 
-package android.media.routing;
+package android.telecomm;
 
-/** @hide */
-interface IMediaRouter {
-
-}
-
+parcelable ParcelableConference;
diff --git a/telecomm/java/android/telecomm/ParcelableConference.java b/telecomm/java/android/telecomm/ParcelableConference.java
new file mode 100644
index 0000000..b279861
--- /dev/null
+++ b/telecomm/java/android/telecomm/ParcelableConference.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A parcelable representation of a conference connection.
+ * @hide
+ */
+public final class ParcelableConference implements Parcelable {
+
+    private PhoneAccountHandle mPhoneAccount;
+    private int mState;
+    private int mCapabilities;
+    private List<String> mConnectionIds;
+
+    public ParcelableConference(
+            PhoneAccountHandle phoneAccount,
+            int state,
+            int capabilities,
+            List<String> connectionIds) {
+        mPhoneAccount = phoneAccount;
+        mState = state;
+        mCapabilities = capabilities;
+        mConnectionIds = connectionIds;
+    }
+
+    @Override
+    public String toString() {
+        return (new StringBuffer())
+                .append("account: ")
+                .append(mPhoneAccount)
+                .append(", state: ")
+                .append(Connection.stateToString(mState))
+                .append(", capabilities: ")
+                .append(PhoneCapabilities.toString(mCapabilities))
+                .append(", children: ")
+                .append(mConnectionIds)
+                .toString();
+    }
+
+    public PhoneAccountHandle getPhoneAccount() {
+        return mPhoneAccount;
+    }
+
+    public int getState() {
+        return mState;
+    }
+
+    public int getCapabilities() {
+        return mCapabilities;
+    }
+
+    public List<String> getConnectionIds() {
+        return mConnectionIds;
+    }
+
+    public static final Parcelable.Creator<ParcelableConference> CREATOR =
+            new Parcelable.Creator<ParcelableConference> () {
+        @Override
+        public ParcelableConference createFromParcel(Parcel source) {
+            ClassLoader classLoader = ParcelableConference.class.getClassLoader();
+            PhoneAccountHandle phoneAccount = source.readParcelable(classLoader);
+            int state = source.readInt();
+            int capabilities = source.readInt();
+            List<String> connectionIds = new ArrayList<>(2);
+            source.readList(connectionIds, classLoader);
+
+            return new ParcelableConference(phoneAccount, state, capabilities, connectionIds);
+        }
+
+        @Override
+        public ParcelableConference[] newArray(int size) {
+            return new ParcelableConference[size];
+        }
+    };
+
+    /** {@inheritDoc} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Writes ParcelableConference object into a Parcel. */
+    @Override
+    public void writeToParcel(Parcel destination, int flags) {
+        destination.writeParcelable(mPhoneAccount, 0);
+        destination.writeInt(mState);
+        destination.writeInt(mCapabilities);
+        destination.writeList(mConnectionIds);
+    }
+}
diff --git a/telecomm/java/android/telecomm/ParcelableConnection.java b/telecomm/java/android/telecomm/ParcelableConnection.java
index 7a87b87..30ff5be 100644
--- a/telecomm/java/android/telecomm/ParcelableConnection.java
+++ b/telecomm/java/android/telecomm/ParcelableConnection.java
@@ -41,6 +41,8 @@
     private boolean mRequestingRingback;
     private boolean mAudioModeIsVoip;
     private StatusHints mStatusHints;
+    private int mFailureCode;
+    private String mFailureMessage;
 
     /** @hide */
     public ParcelableConnection(
@@ -55,7 +57,9 @@
             int videoState,
             boolean requestingRingback,
             boolean audioModeIsVoip,
-            StatusHints statusHints) {
+            StatusHints statusHints,
+            int failureCode,
+            String failureMessage) {
         mPhoneAccount = phoneAccount;
         mState = state;
         mCapabilities = capabilities;
@@ -68,6 +72,8 @@
         mRequestingRingback = requestingRingback;
         mAudioModeIsVoip = audioModeIsVoip;
         mStatusHints = statusHints;
+        mFailureCode = failureCode;
+        mFailureMessage = failureMessage;
     }
 
     public PhoneAccountHandle getPhoneAccount() {
@@ -119,6 +125,14 @@
         return mStatusHints;
     }
 
+    public final int getFailureCode() {
+        return mFailureCode;
+    }
+
+    public final String getFailureMessage() {
+        return mFailureMessage;
+    }
+
     @Override
     public String toString() {
         return new StringBuilder()
@@ -150,6 +164,8 @@
             boolean requestingRingback = source.readByte() == 1;
             boolean audioModeIsVoip = source.readByte() == 1;
             StatusHints statusHints = source.readParcelable(classLoader);
+            int disconnectCauseCode = source.readInt();
+            String disconnectCauseMessage = source.readString();
 
             return new ParcelableConnection(
                     phoneAccount,
@@ -163,7 +179,9 @@
                     videoState,
                     requestingRingback,
                     audioModeIsVoip,
-                    statusHints);
+                    statusHints,
+                    disconnectCauseCode,
+                    disconnectCauseMessage);
         }
 
         @Override
@@ -194,5 +212,7 @@
         destination.writeByte((byte) (mRequestingRingback ? 1 : 0));
         destination.writeByte((byte) (mAudioModeIsVoip ? 1 : 0));
         destination.writeParcelable(mStatusHints, 0);
+        destination.writeInt(mFailureCode);
+        destination.writeString(mFailureMessage);
     }
 }
diff --git a/telecomm/java/android/telecomm/RemoteConnection.java b/telecomm/java/android/telecomm/RemoteConnection.java
index f1cee10..30cfdde 100644
--- a/telecomm/java/android/telecomm/RemoteConnection.java
+++ b/telecomm/java/android/telecomm/RemoteConnection.java
@@ -233,9 +233,9 @@
     RemoteConnection(int failureCode, String failureMessage) {
         this("NULL", null, null);
         mConnected = false;
-        mState = Connection.STATE_FAILED;
-        mFailureCode = failureCode;
-        mFailureMessage = failureMessage;
+        mState = Connection.STATE_DISCONNECTED;
+        mFailureCode = DisconnectCause.OUTGOING_FAILURE;
+        mFailureMessage = failureMessage + " original code = " + failureCode;
     }
 
     /**
@@ -675,8 +675,9 @@
     }
 
     /**
-     * Create a RemoteConnection which is in the {@link Connection#STATE_FAILED} state. Attempting
-     * to use it for anything will almost certainly result in bad things happening. Do not do this.
+     * Create a RemoteConnection represents a failure, and which will be in
+     * {@link Connection#STATE_DISCONNECTED}. Attempting to use it for anything will almost
+     * certainly result in bad things happening. Do not do this.
      *
      * @return a failed {@link RemoteConnection}
      *
diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java
index 9a1729f..541df4e 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionService.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionService.java
@@ -48,7 +48,7 @@
 
     private final IConnectionServiceAdapter mServantDelegate = new IConnectionServiceAdapter() {
         @Override
-        public void handleCreateConnectionSuccessful(
+        public void handleCreateConnectionComplete(
                 String id,
                 ConnectionRequest request,
                 ParcelableConnection parcel) {
@@ -56,6 +56,7 @@
                     findConnectionForAction(id, "handleCreateConnectionSuccessful");
             if (connection != NULL_CONNECTION && mPendingConnections.contains(connection)) {
                 mPendingConnections.remove(connection);
+                // Unconditionally initialize the connection ...
                 connection.setState(parcel.getState());
                 connection.setCallCapabilities(parcel.getCapabilities());
                 connection.setHandle(
@@ -64,29 +65,15 @@
                         parcel.getCallerDisplayName(),
                         parcel.getCallerDisplayNamePresentation());
                 // TODO: Do we need to support video providers for remote connections?
+                if (connection.getState() == Connection.STATE_DISCONNECTED) {
+                    // ... then, if it was created in a disconnected state, that indicates
+                    // failure on the providing end, so immediately mark it destroyed
+                    connection.setDestroyed();
+                }
             }
         }
 
         @Override
-        public void handleCreateConnectionFailed(
-                String id,
-                ConnectionRequest request,
-                int errorCode,
-                String errorMessage) {
-            // TODO: How do we propagate the failure codes?
-            findConnectionForAction(id, "handleCreateConnectionFailed")
-                    .setDestroyed();
-        }
-
-        @Override
-        public void handleCreateConnectionCancelled(
-                String id,
-                ConnectionRequest request) {
-            findConnectionForAction(id, "handleCreateConnectionCancelled")
-                    .setDestroyed();
-        }
-
-        @Override
         public void setActive(String callId) {
             findConnectionForAction(callId, "setActive")
                     .setState(Connection.STATE_ACTIVE);
@@ -135,7 +122,7 @@
         }
 
         @Override
-        public void addConferenceCall(String callId) {
+        public void addConferenceCall(String callId, ParcelableConference parcelableConference) {
             // not supported for remote connections.
         }
 
diff --git a/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
index fd4e931..ef1769f 100644
--- a/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IConnectionServiceAdapter.aidl
@@ -20,6 +20,7 @@
 import android.net.Uri;
 import android.telecomm.ConnectionRequest;
 import android.telecomm.ParcelableConnection;
+import android.telecomm.ParcelableConference;
 import android.telecomm.StatusHints;
 
 import com.android.internal.telecomm.IVideoProvider;
@@ -33,20 +34,11 @@
  * {@hide}
  */
 oneway interface IConnectionServiceAdapter {
-    void handleCreateConnectionSuccessful(
+    void handleCreateConnectionComplete(
             String callId,
             in ConnectionRequest request,
             in ParcelableConnection connection);
 
-    void handleCreateConnectionFailed(
-            String callId,
-            in ConnectionRequest request,
-            int errorCode, String errorMessage);
-
-    void handleCreateConnectionCancelled(
-            String callId,
-            in ConnectionRequest request);
-
     void setActive(String callId);
 
     void setRinging(String callId);
@@ -63,7 +55,7 @@
 
     void setIsConferenced(String callId, String conferenceCallId);
 
-    void addConferenceCall(String callId);
+    void addConferenceCall(String callId, in ParcelableConference conference);
 
     void removeCall(String callId);
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c50110a..d4f8362 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2459,7 +2459,7 @@
      * @param filePath
      * @return The APDU response.
      */
-    byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
+    public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
             String filePath) {
         try {
             return getITelephony().iccExchangeSimIO(fileID, command, p1, p2,
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index 15d075c..c0898d30 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -23,6 +23,7 @@
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
     <application android:label="ActivityTest">
         <activity android:name="ActivityTestMain">
             <intent-filter>
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 0e063d6..9002125 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -34,6 +34,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.graphics.Bitmap;
+import android.view.WindowManager;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -130,6 +131,12 @@
                 mSecondUser = ui.id;
             }
         }
+
+        /*
+        AlertDialog ad = new AlertDialog.Builder(this).setTitle("title").setMessage("message").create();
+        ad.getWindow().getAttributes().type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
+        ad.show();
+        */
     }
 
     @Override
diff --git a/tests/OneMedia/Android.mk b/tests/OneMedia/Android.mk
index 4feac68..4d39728 100644
--- a/tests/OneMedia/Android.mk
+++ b/tests/OneMedia/Android.mk
@@ -9,9 +9,6 @@
 LOCAL_PACKAGE_NAME := OneMedia
 LOCAL_CERTIFICATE := platform
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-media-protocols
-
 LOCAL_PROGUARD_ENABLED := disabled
 
 include $(BUILD_PACKAGE)
diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml
index 95072a4..beafeb4 100644
--- a/tests/OneMedia/AndroidManifest.xml
+++ b/tests/OneMedia/AndroidManifest.xml
@@ -25,15 +25,6 @@
             android:name="com.android.onemedia.OnePlayerService"
             android:exported="true"
             android:process="com.android.onemedia.service" />
-        <service
-            android:name=".provider.OneMediaRouteProvider"
-            android:permission="android.permission.BIND_MEDIA_ROUTE_SERVICE"
-            android:exported="true"
-            android:process="com.android.onemedia.provider">
-            <intent-filter>
-                <action android:name="android.media.routing.MediaRouteService" />
-            </intent-filter>
-          </service>
     </application>
 
 </manifest>
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index 9afcf24..8b7c883 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -19,24 +19,16 @@
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.media.MediaMetadata;
-import android.media.routing.MediaRouteSelector;
-import android.media.routing.MediaRouter;
-import android.media.routing.MediaRouter.ConnectionRequest;
-import android.media.routing.MediaRouter.DestinationInfo;
-import android.media.routing.MediaRouter.RouteInfo;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
-import android.support.media.protocols.MediaPlayerProtocol;
-import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
 import android.view.KeyEvent;
 
 import com.android.onemedia.playback.LocalRenderer;
-import com.android.onemedia.playback.OneMRPRenderer;
 import com.android.onemedia.playback.Renderer;
 import com.android.onemedia.playback.RequestUtils;
 
@@ -47,7 +39,6 @@
     private static final String TAG = "PlayerSession";
 
     protected MediaSession mSession;
-    protected MediaRouter mRouter;
     protected Context mContext;
     protected Renderer mRenderer;
     protected MediaSession.Callback mCallback;
@@ -80,22 +71,11 @@
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
 
-        mRouter = new MediaRouter(mContext);
-        mRouter.addSelector(new MediaRouteSelector.Builder()
-                .addRequiredProtocol(MediaPlayerProtocol.class)
-                .build());
-        mRouter.addSelector(new MediaRouteSelector.Builder()
-                .setRequiredFeatures(MediaRouter.ROUTE_FEATURE_LIVE_AUDIO)
-                .setOptionalFeatures(MediaRouter.ROUTE_FEATURE_LIVE_VIDEO)
-                .build());
-        mRouter.setRoutingCallback(new RoutingCallback(), null);
-
         mSession = new MediaSession(mContext, "OneMedia");
         mSession.setCallback(mCallback);
         mSession.setPlaybackState(mPlaybackState);
         mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS
                 | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
-        mSession.setMediaRouter(mRouter);
         mSession.setActive(true);
         updateMetadata();
     }
@@ -113,10 +93,6 @@
             mSession.release();
             mSession = null;
         }
-        if (mRouter != null) {
-            mRouter.release();
-            mRouter = null;
-        }
     }
 
     public void setListener(Listener listener) {
@@ -266,63 +242,4 @@
             mRenderer.onPause();
         }
     }
-
-    private class RoutingCallback extends MediaRouter.RoutingCallback {
-        @Override
-        public void onConnectionStateChanged(int state) {
-            if (state == MediaRouter.CONNECTION_STATE_CONNECTING) {
-                if (mRenderer != null) {
-                    mRenderer.onStop();
-                }
-                mRenderer = null;
-                updateState(PlaybackState.STATE_CONNECTING);
-                return;
-            }
-
-            MediaRouter.ConnectionInfo connection = mRouter.getConnection();
-            if (connection != null) {
-                MediaPlayerProtocol protocol =
-                        connection.getProtocolObject(MediaPlayerProtocol.class);
-                if (protocol != null) {
-                    Log.d(TAG, "Connected to route using media player protocol");
-
-                    protocol.setCallback(new PlayerCallback(), null);
-                    mRenderer = new OneMRPRenderer(protocol);
-                    updateState(PlaybackState.STATE_NONE);
-                    return;
-                }
-            }
-
-            // Use local route
-            mRenderer = new LocalRenderer(mContext, null);
-            mRenderer.registerListener(mRenderListener);
-            updateState(PlaybackState.STATE_NONE);
-        }
-    }
-
-    private class PlayerCallback extends MediaPlayerProtocol.Callback {
-        @Override
-        public void onStatusUpdated(MediaStatus status, Bundle extras) {
-            if (status != null) {
-                Log.d(TAG, "Received status update: " + status.toBundle());
-                switch (status.getPlayerState()) {
-                    case MediaStatus.PLAYER_STATE_BUFFERING:
-                        updateState(PlaybackState.STATE_BUFFERING);
-                        break;
-                    case MediaStatus.PLAYER_STATE_IDLE:
-                        updateState(PlaybackState.STATE_STOPPED);
-                        break;
-                    case MediaStatus.PLAYER_STATE_PAUSED:
-                        updateState(PlaybackState.STATE_PAUSED);
-                        break;
-                    case MediaStatus.PLAYER_STATE_PLAYING:
-                        updateState(PlaybackState.STATE_PLAYING);
-                        break;
-                    case MediaStatus.PLAYER_STATE_UNKNOWN:
-                        updateState(PlaybackState.STATE_NONE);
-                        break;
-                }
-            }
-        }
-    }
 }
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java
deleted file mode 100644
index 55eb92c..0000000
--- a/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.android.onemedia.playback;
-
-import android.os.Bundle;
-import android.support.media.protocols.MediaPlayerProtocol;
-import android.support.media.protocols.MediaPlayerProtocol.MediaInfo;
-
-/**
- * Renderer for communicating with the OneMRP route
- */
-public class OneMRPRenderer extends Renderer {
-    private final MediaPlayerProtocol mProtocol;
-
-    public OneMRPRenderer(MediaPlayerProtocol protocol) {
-        super(null, null);
-        mProtocol = protocol;
-    }
-
-    @Override
-    public void setContent(Bundle request) {
-        MediaInfo mediaInfo = new MediaInfo(request.getString(RequestUtils.EXTRA_KEY_SOURCE),
-                MediaInfo.STREAM_TYPE_BUFFERED, "audio/mp3");
-        mProtocol.load(mediaInfo, true, 0, null);
-    }
-
-    @Override
-    public boolean onStop() {
-        mProtocol.stop(null);
-        return true;
-    }
-
-    @Override
-    public boolean onPlay() {
-        mProtocol.play(null);
-        return true;
-    }
-
-    @Override
-    public boolean onPause() {
-        mProtocol.pause(null);
-        return true;
-    }
-
-    @Override
-    public long getSeekPosition() {
-        return -1;
-    }
-}
diff --git a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
deleted file mode 100644
index 5845e48..0000000
--- a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
+++ /dev/null
@@ -1,270 +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.onemedia.provider;
-
-import android.media.routing.MediaRouteSelector;
-import android.media.routing.MediaRouteService;
-import android.media.routing.MediaRouter.ConnectionInfo;
-import android.media.routing.MediaRouter.ConnectionRequest;
-import android.media.routing.MediaRouter.DestinationInfo;
-import android.media.routing.MediaRouter.DiscoveryRequest;
-import android.media.routing.MediaRouter.RouteInfo;
-import android.media.session.PlaybackState;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Process;
-import android.support.media.protocols.MediaPlayerProtocol;
-import android.support.media.protocols.MediaPlayerProtocol.MediaInfo;
-import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
-import android.os.Looper;
-import android.os.ResultReceiver;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.onemedia.playback.LocalRenderer;
-import com.android.onemedia.playback.Renderer;
-import com.android.onemedia.playback.RequestUtils;
-
-import java.util.ArrayList;
-
-/**
- * Test of MediaRouteProvider. Show a dummy provider with a simple interface for
- * playing music.
- */
-public class OneMediaRouteProvider extends MediaRouteService {
-    private static final String TAG = "OneMRP";
-    private static final boolean DEBUG = true;
-
-    private static final String TEST_DESTINATION_ID = "testDestination";
-    private static final String TEST_ROUTE_ID = "testRoute";
-
-    private Renderer mRenderer;
-    private RenderListener mRenderListener;
-    private PlaybackState mPlaybackState;
-    private Handler mHandler;
-
-    private OneStub mStub;
-
-    @Override
-    public void onCreate() {
-        mHandler = new Handler();
-        mRenderer = new LocalRenderer(this, null);
-        mRenderListener = new RenderListener();
-        PlaybackState.Builder bob = new PlaybackState.Builder();
-        bob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY);
-        mPlaybackState = bob.build();
-
-        mRenderer.registerListener(mRenderListener);
-    }
-
-    @Override
-    public ClientSession onCreateClientSession(ClientInfo client) {
-        if (client.getUid() != Process.myUid()) {
-            // for testing purposes, only allow connections from this application
-            // since this provider is not fully featured
-            return null;
-        }
-        return new OneSession(client);
-    }
-
-    private final class OneSession extends ClientSession {
-        private final ClientInfo mClient;
-
-        public OneSession(ClientInfo client) {
-            mClient = client;
-        }
-
-        @Override
-        public boolean onStartDiscovery(DiscoveryRequest req, DiscoveryCallback callback) {
-            for (MediaRouteSelector selector : req.getSelectors()) {
-                if (isMatch(selector)) {
-                    DestinationInfo destination = new DestinationInfo.Builder(
-                            TEST_DESTINATION_ID, getServiceMetadata(), "OneMedia")
-                            .setDescription("Test route from OneMedia app.")
-                            .build();
-                    ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
-                    routes.add(new RouteInfo.Builder(
-                            TEST_ROUTE_ID, destination, selector).build());
-                    callback.onDestinationFound(destination, routes);
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public void onStopDiscovery() {
-        }
-
-        @Override
-        public boolean onConnect(ConnectionRequest req, ConnectionCallback callback) {
-            if (req.getRoute().getId().equals(TEST_ROUTE_ID)) {
-                mStub = new OneStub();
-                ConnectionInfo connection = new ConnectionInfo.Builder(req.getRoute())
-                        .setProtocolStub(MediaPlayerProtocol.class, mStub)
-                        .build();
-                callback.onConnected(connection);
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public void onDisconnect() {
-            mStub = null;
-        }
-
-        private boolean isMatch(MediaRouteSelector selector) {
-            if (!selector.containsProtocol(MediaPlayerProtocol.class)) {
-                return false;
-            }
-            for (String protocol : selector.getRequiredProtocols()) {
-                if (!protocol.equals(MediaPlayerProtocol.class.getName())) {
-                    return false;
-                }
-            }
-            return true;
-        }
-    }
-
-    private final class OneStub extends MediaPlayerProtocol.Stub {
-        MediaInfo mMediaInfo;
-
-        public OneStub() {
-            super(mHandler);
-        }
-
-        @Override
-        public void onLoad(MediaInfo mediaInfo, boolean autoplay, long playPosition,
-                Bundle extras) {
-            if (DEBUG) {
-                Log.d(TAG, "Attempting to play " + mediaInfo.getContentId());
-            }
-            // look up the route and send a play command to it
-            mMediaInfo = mediaInfo;
-            Bundle bundle = new Bundle();
-            bundle.putString(RequestUtils.EXTRA_KEY_SOURCE, mediaInfo.getContentId());
-            mRenderer.setContent(bundle);
-        }
-
-        @Override
-        public void onPlay(Bundle extras) {
-            mRenderer.onPlay();
-        }
-
-        @Override
-        public void onPause(Bundle extras) {
-            mRenderer.onPause();
-        }
-    }
-
-    private class RenderListener implements Renderer.Listener {
-
-        @Override
-        public void onError(int type, int extra, Bundle extras, Throwable error) {
-            Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
-            sendStatusUpdate(PlaybackState.STATE_ERROR);
-        }
-
-        @Override
-        public void onStateChanged(int newState) {
-            long position = -1;
-            if (mRenderer != null) {
-                position = mRenderer.getSeekPosition();
-            }
-            int pbState;
-            float rate = 0;
-            String errorMsg = null;
-            switch (newState) {
-                case Renderer.STATE_ENDED:
-                case Renderer.STATE_STOPPED:
-                    pbState = PlaybackState.STATE_STOPPED;
-                    break;
-                case Renderer.STATE_INIT:
-                case Renderer.STATE_PREPARING:
-                    pbState = PlaybackState.STATE_BUFFERING;
-                    break;
-                case Renderer.STATE_ERROR:
-                    pbState = PlaybackState.STATE_ERROR;
-                    break;
-                case Renderer.STATE_PAUSED:
-                    pbState = PlaybackState.STATE_PAUSED;
-                    break;
-                case Renderer.STATE_PLAYING:
-                    pbState = PlaybackState.STATE_PLAYING;
-                    rate = 1;
-                    break;
-                default:
-                    pbState = PlaybackState.STATE_ERROR;
-                    errorMsg = "unknown state";
-                    break;
-            }
-            PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
-            bob.setState(pbState, position, rate, SystemClock.elapsedRealtime());
-            bob.setErrorMessage(errorMsg);
-            mPlaybackState = bob.build();
-
-            sendStatusUpdate(mPlaybackState.getState());
-        }
-
-        @Override
-        public void onBufferingUpdate(int percent) {
-        }
-
-        @Override
-        public void onFocusLost() {
-            Log.d(TAG, "Focus lost, pausing");
-            // Don't update state here, we'll get a separate call to
-            // onStateChanged when it pauses
-            mRenderer.onPause();
-        }
-
-        @Override
-        public void onNextStarted() {
-        }
-
-        private void sendStatusUpdate(int state) {
-            if (mStub != null) {
-                MediaStatus status = new MediaStatus(1, mStub.mMediaInfo);
-                switch (state) {
-                    case PlaybackState.STATE_BUFFERING:
-                    case PlaybackState.STATE_FAST_FORWARDING:
-                    case PlaybackState.STATE_REWINDING:
-                    case PlaybackState.STATE_SKIPPING_TO_NEXT:
-                    case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
-                        status.setPlayerState(MediaStatus.PLAYER_STATE_BUFFERING);
-                        break;
-                    case PlaybackState.STATE_CONNECTING:
-                    case PlaybackState.STATE_STOPPED:
-                        status.setPlayerState(MediaStatus.PLAYER_STATE_IDLE);
-                        break;
-                    case PlaybackState.STATE_PAUSED:
-                        status.setPlayerState(MediaStatus.PLAYER_STATE_PAUSED);
-                        break;
-                    case PlaybackState.STATE_PLAYING:
-                        status.setPlayerState(MediaStatus.PLAYER_STATE_PLAYING);
-                        break;
-                    case PlaybackState.STATE_NONE:
-                    case PlaybackState.STATE_ERROR:
-                    default:
-                        status.setPlayerState(MediaStatus.PLAYER_STATE_UNKNOWN);
-                        break;
-                }
-                mStub.sendStatusUpdatedEvent(status, null);
-            }
-        }
-    }
-}
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 700afa1..4ce5045 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -66,6 +66,8 @@
     libexpat \
     libziparchive-host
 
+aaptCFlags := -DAAPT_VERSION=\"$(BUILD_NUMBER)\"
+
 ifeq ($(HOST_OS),linux)
     aaptHostLdLibs += -lrt -ldl -lpthread
 endif
@@ -91,6 +93,7 @@
 
 LOCAL_CFLAGS += -Wno-format-y2k
 LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
+LOCAL_CFLAGS += $(aaptCFlags)
 ifeq (darwin,$(HOST_OS))
 LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
 endif
@@ -110,7 +113,9 @@
 LOCAL_STATIC_LIBRARIES += \
     libaapt \
     $(aaptHostStaticLibs)
+
 LOCAL_LDLIBS += $(aaptHostLdLibs)
+LOCAL_CFLAGS += $(aaptCFlags)
 
 include $(BUILD_HOST_EXECUTABLE)
 
@@ -128,7 +133,9 @@
 LOCAL_STATIC_LIBRARIES += \
     libaapt \
     $(aaptHostStaticLibs)
+
 LOCAL_LDLIBS += $(aaptHostLdLibs)
+LOCAL_CFLAGS += $(aaptCFlags)
 
 include $(BUILD_HOST_NATIVE_TEST)
 
@@ -159,6 +166,7 @@
     libstlport_static \
     libexpat_static
 
+LOCAL_CFLAGS += $(aaptCFlags)
 LOCAL_CPPFLAGS += -Wno-non-virtual-dtor
 
 include $(BUILD_EXECUTABLE)
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 5d146d6..bdbf47b 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -24,6 +24,10 @@
 
 using namespace android;
 
+#ifndef AAPT_VERSION
+    #define AAPT_VERSION ""
+#endif
+
 /*
  * Show version info.  All the cool kids do it.
  */
@@ -32,7 +36,7 @@
     if (bundle->getFileSpecCount() != 0) {
         printf("(ignoring extra arguments)\n");
     }
-    printf("Android Asset Packaging Tool, v0.2\n");
+    printf("Android Asset Packaging Tool, v0.2-" AAPT_VERSION "\n");
 
     return 0;
 }
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index cf1d4fd..c98808f 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -484,15 +484,6 @@
                 attr.hasErrors = true;
             }
 
-            // Make sure an id is defined for this enum/flag identifier...
-            if (!attr.hasErrors && !outTable->hasBagOrEntry(itemIdent, &id16, &myPackage)) {
-                err = outTable->startBag(SourcePos(in->getPrintableSource(), block.getLineNumber()),
-                                         myPackage, id16, itemIdent, String16(), NULL);
-                if (err != NO_ERROR) {
-                    attr.hasErrors = true;
-                }
-            }
-
             if (!attr.hasErrors) {
                 if (enumOrFlagsComment.size() == 0) {
                     enumOrFlagsComment.append(mayOrMust(attr.type,
@@ -2508,11 +2499,13 @@
         sp<Type> attr = p->getType(String16("attr"), unknown);
 
         // Assign indices...
-        for (ti=0; ti<N; ti++) {
+        const size_t typeCount = p->getOrderedTypes().size();
+        for (size_t ti = 0; ti < typeCount; ti++) {
             sp<Type> t = p->getOrderedTypes().itemAt(ti);
             if (t == NULL) {
                 continue;
             }
+
             err = t->applyPublicEntryOrder();
             if (err != NO_ERROR && firstError == NO_ERROR) {
                 firstError = err;
@@ -2534,7 +2527,7 @@
         }
 
         // Assign resource IDs to keys in bags...
-        for (ti=0; ti<N; ti++) {
+        for (size_t ti = 0; ti < typeCount; ti++) {
             sp<Type> t = p->getOrderedTypes().itemAt(ti);
             if (t == NULL) {
                 continue;
@@ -3296,11 +3289,16 @@
     Item item(sourcePos, false, value, style);
 
     if (mType == TYPE_BAG) {
-        const Item& item(mBag.valueAt(0));
-        sourcePos.error("Resource entry %s is already defined as a bag.\n"
-                        "%s:%d: Originally defined here.\n",
-                        String8(mName).string(),
-                        item.sourcePos.file.string(), item.sourcePos.line);
+        if (mBag.size() == 0) {
+            sourcePos.error("Resource entry %s is already defined as a bag.",
+                    String8(mName).string());
+        } else {
+            const Item& item(mBag.valueAt(0));
+            sourcePos.error("Resource entry %s is already defined as a bag.\n"
+                            "%s:%d: Originally defined here.\n",
+                            String8(mName).string(),
+                            item.sourcePos.file.string(), item.sourcePos.line);
+        }
         return UNKNOWN_ERROR;
     }
     if ( (mType != TYPE_UNKNOWN) && (overwrite == false) ) {
@@ -3374,6 +3372,9 @@
         if (it.isId) {
             if (!table->hasBagOrEntry(key, &id16, &package)) {
                 String16 value("false");
+                NOISY(fprintf(stderr, "Generating %s:id/%s\n",
+                        String8(package).string(),
+                        String8(key).string()));
                 status_t err = table->addEntry(SourcePos(String8("<generated>"), 0), package,
                                                id16, key, value);
                 if (err != NO_ERROR) {
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_battery_100.png b/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_battery_100.png
new file mode 100644
index 0000000..f17189a
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_battery_100.png b/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_battery_100.png
new file mode 100644
index 0000000..2a9757d
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/status_bar.xml b/tools/layoutlib/bridge/resources/bars/status_bar.xml
index 75bfb6e..04571e1 100644
--- a/tools/layoutlib/bridge/resources/bars/status_bar.xml
+++ b/tools/layoutlib/bridge/resources/bars/status_bar.xml
@@ -1,17 +1,27 @@
 <?xml version="1.0" encoding="utf-8"?>
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
-	<TextView
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:layout_weight="1"/>
-	<ImageView
-			android:layout_height="wrap_content"
-			android:layout_width="wrap_content"
-			android:layout_marginTop="1dp"/>
-	<ImageView
-			android:layout_height="wrap_content"
-			android:layout_width="wrap_content"
-			android:layout_marginLeft="3dp"
-			android:layout_marginRight="5dp"
-			android:layout_marginTop="2dp"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"/>
+    <!-- The exact size of the wifi icon is specified in order to scale it properly.
+    Without scaling, it appeared huge. This is currently, 70% of the actual size. -->
+    <ImageView
+            android:layout_height="22.4dp"
+            android:layout_width="20.65dp"
+            android:layout_marginTop="1dp"/>
+    <ImageView
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_marginLeft="3dp"
+            android:layout_marginRight="5dp"
+            android:layout_marginTop="4dp"/>
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp"
+            android:layout_marginRight="5dp"
+            android:gravity="center_vertical"
+            android:textSize="16dp"
+            android:fontFamily="sans-serif-medium"/>
 </merge>
diff --git a/tools/layoutlib/bridge/resources/bars/v18/hdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/v18/hdpi/stat_sys_wifi_signal_4_fully.png
index 931daed..6248cfd 100644
--- a/tools/layoutlib/bridge/resources/bars/v18/hdpi/stat_sys_wifi_signal_4_fully.png
+++ b/tools/layoutlib/bridge/resources/bars/v18/hdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/v18/mdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/v18/mdpi/stat_sys_wifi_signal_4_fully.png
index 6e1ac91..441de0c 100644
--- a/tools/layoutlib/bridge/resources/bars/v18/mdpi/stat_sys_wifi_signal_4_fully.png
+++ b/tools/layoutlib/bridge/resources/bars/v18/mdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/v18/xhdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/v18/xhdpi/stat_sys_wifi_signal_4_fully.png
index 625c61d..459a1a2 100644
--- a/tools/layoutlib/bridge/resources/bars/v18/xhdpi/stat_sys_wifi_signal_4_fully.png
+++ b/tools/layoutlib/bridge/resources/bars/v18/xhdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/v21/hdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/v21/hdpi/stat_sys_wifi_signal_4_fully.png
deleted file mode 100644
index 931daed..0000000
--- a/tools/layoutlib/bridge/resources/bars/v21/hdpi/stat_sys_wifi_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/v21/mdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/v21/mdpi/stat_sys_wifi_signal_4_fully.png
deleted file mode 100644
index 6e1ac91..0000000
--- a/tools/layoutlib/bridge/resources/bars/v21/mdpi/stat_sys_wifi_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/v21/xhdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/v21/xhdpi/stat_sys_wifi_signal_4_fully.png
deleted file mode 100644
index 625c61d..0000000
--- a/tools/layoutlib/bridge/resources/bars/v21/xhdpi/stat_sys_wifi_signal_4_fully.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/v21/xhdpi/stat_sys_wifi_signal_4_fully.xml b/tools/layoutlib/bridge/resources/bars/v21/xhdpi/stat_sys_wifi_signal_4_fully.xml
new file mode 100644
index 0000000..0498b6c
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/v21/xhdpi/stat_sys_wifi_signal_4_fully.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="29.5dp"
+        android:viewportWidth="26.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
+</vector>
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/stat_sys_battery_100.png b/tools/layoutlib/bridge/resources/bars/xhdpi/stat_sys_battery_100.png
new file mode 100644
index 0000000..555bcd9
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index f939678..5b69681 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -91,7 +91,7 @@
         // first count the array size
         int count = 0;
         for (ResourceValue data : mResourceData) {
-            if (data != null) {
+            if (data != null && !RenderResources.REFERENCE_NULL.equals(data.getValue())) {
                 count++;
             }
         }
@@ -103,7 +103,8 @@
         // fill the array with the indices.
         int index = 1;
         for (int i = 0 ; i < mResourceData.length ; i++) {
-            if (mResourceData[i] != null) {
+            if (mResourceData[i] != null
+                    && !RenderResources.REFERENCE_NULL.equals(mResourceData[i].getValue())) {
                 mIndices[index++] = i;
             }
         }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
index 9b814f5..16b54f1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
@@ -20,10 +20,7 @@
 import java.util.Collections;
 import java.util.List;
 
-import static android.os.Build.VERSION_CODES.GINGERBREAD;
-import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
-import static android.os.Build.VERSION_CODES.KITKAT;
+import static android.os.Build.VERSION_CODES.*;
 
 /**
  * Various helper methods to simulate older versions of platform.
@@ -39,13 +36,16 @@
     private static final List<String> sDefaultResourceDir =
             Collections.singletonList(DEFAULT_RESOURCE_DIR);
 
+    private static final int WHITE = 0xFFFFFFFF;
+    private static final int BLACK = 0xFF000000;
+
     public static boolean showOnScreenNavBar(int platformVersion) {
         return platformVersion == 0 || platformVersion >= ICE_CREAM_SANDWICH;
     }
 
     public static int getStatusBarColor(int platformVersion) {
         // return white for froyo and earlier; black otherwise.
-        return platformVersion == 0 || platformVersion >= GINGERBREAD ? 0xFF000000 : 0xFFFFFFFF;
+        return platformVersion == 0 || platformVersion >= GINGERBREAD ? BLACK : WHITE;
     }
 
     public static List<String> getResourceDirs(int platformVersion) {
@@ -70,4 +70,49 @@
 
         return Collections.unmodifiableList(list);
     }
+
+    public static String getTime(int platformVersion) {
+        if (platformVersion == 0) {
+            // TODO: revisit when the version is selected.
+            return "4:57";
+        }
+        if (platformVersion < GINGERBREAD) {
+            return "2:20";
+        }
+        if (platformVersion < ICE_CREAM_SANDWICH) {
+            return "2:30";
+        }
+        if (platformVersion < JELLY_BEAN) {
+            return "4:00";
+        }
+        if (platformVersion < KITKAT) {
+            return "4:30";
+        }
+        if (platformVersion <= KITKAT_WATCH) {
+            return "4:40";
+        }
+        // Should never happen.
+        return "4:04";
+    }
+
+    public static int getTimeColor(int platformVersion) {
+        if (platformVersion == 0 || platformVersion >= KITKAT ||
+                platformVersion > FROYO && platformVersion < HONEYCOMB) {
+            // Gingerbread and KitKat onwards.
+            return WHITE;
+        }
+        // Black for froyo.
+        if (platformVersion < GINGERBREAD) {
+            return BLACK;
+        } else if (platformVersion < KITKAT) {
+            // Honeycomb to JB-mr2: Holo blue light.
+            return 0xff33b5e5;
+        }
+        // Should never happen.
+        return WHITE;
+    }
+
+    public static String getWifiIconType(int platformVersion) {
+        return platformVersion == 0 ? "xml" : "png";
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index bed232ab..13ddf07 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -127,24 +127,25 @@
         }
     }
 
-    protected TextView setText(int index, String stringReference) {
+    protected TextView setText(int index, String string, boolean reference) {
         View child = getChildAt(index);
         if (child instanceof TextView) {
             TextView textView = (TextView) child;
-            setText(textView, stringReference);
+            setText(textView, string, reference);
             return textView;
         }
 
         return null;
     }
 
-    private void setText(TextView textView, String stringReference) {
-        ResourceValue value = getResourceValue(stringReference);
-        if (value != null) {
-            textView.setText(value.getValue());
-        } else {
-            textView.setText(stringReference);
+    private void setText(TextView textView, String string, boolean reference) {
+        if (reference) {
+            ResourceValue value = getResourceValue(string);
+            if (value != null) {
+                string = value.getValue();
+            }
         }
+        textView.setText(string);
     }
 
     protected void setStyle(String themeEntryName) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index 1795db9..c7c62d6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -16,22 +16,38 @@
 
 package com.android.layoutlib.bridge.bars;
 
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.resources.Density;
 
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.view.Gravity;
+import android.view.View;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import java.io.IOException;
+import java.io.InputStream;
+
 public class StatusBar extends CustomBar {
 
+    private final Context mContext;
+    private final int mSimulatedPlatformVersion;
+
     public StatusBar(Context context, Density density, int direction, boolean RtlEnabled,
             int simulatedPlatformVersion) throws XmlPullParserException {
         // FIXME: if direction is RTL but it's not enabled in application manifest, mirror this bar.
         super(context, LinearLayout.HORIZONTAL, "/bars/status_bar.xml", "status_bar.xml",
                 simulatedPlatformVersion);
+        mContext = context;
+        mSimulatedPlatformVersion = simulatedPlatformVersion;
 
         // FIXME: use FILL_H?
         setGravity(Gravity.START | Gravity.TOP | Gravity.RIGHT);
@@ -41,8 +57,44 @@
         // created for them.
         // We do know the order though.
         // 0 is the spacer
-        loadIcon(1, "stat_sys_wifi_signal_4_fully.png", density);
+        loadIcon(1, "stat_sys_wifi_signal_4_fully."
+                        + Config.getWifiIconType(simulatedPlatformVersion), density);
         loadIcon(2, "stat_sys_battery_100.png", density);
+        setText(3, Config.getTime(simulatedPlatformVersion), false)
+                .setTextColor(Config.getTimeColor(simulatedPlatformVersion));
+    }
+
+    @Override
+    protected void loadIcon(int index, String iconName, Density density) {
+        if (!iconName.endsWith(".xml")) {
+            super.loadIcon(index, iconName, density);
+            return;
+        }
+        View child = getChildAt(index);
+        if (child instanceof ImageView) {
+            ImageView imageView = (ImageView) child;
+            // The xml is stored only in xhdpi.
+            IconLoader iconLoader = new IconLoader(iconName, Density.XHIGH,
+                    mSimulatedPlatformVersion, null);
+            InputStream stream = iconLoader.getIcon();
+
+            if (stream != null) {
+                try {
+                    BridgeXmlBlockParser parser = new BridgeXmlBlockParser(
+                            ParserFactory.create(stream, null), (BridgeContext) mContext, true);
+                    Drawable drawable = Drawable.createFromXml(mContext.getResources(), parser);
+                    if (drawable != null) {
+                        imageView.setImageDrawable(drawable);
+                    }
+                } catch (XmlPullParserException e) {
+                    Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to draw wifi icon", e,
+                            null);
+                } catch (IOException e) {
+                    Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to draw wifi icon", e,
+                            null);
+                }
+            }
+        }
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
index ff952bd..10f1383 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
@@ -34,7 +34,7 @@
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
         // We do know the order though.
-        mTextView = setText(0, label);
+        mTextView = setText(0, label, true);
 
         setStyle("windowTitleBackgroundStyle");
     }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 3c37b94..ac2a176 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -21,7 +21,7 @@
 import android.net.IpConfiguration.ProxySettings;
 import android.net.IpConfiguration.IpAssignment;
 import android.net.ProxyInfo;
-import android.net.LinkProperties;
+import android.net.StaticIpConfiguration;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -1096,13 +1096,13 @@
     }
 
     /** @hide */
-    public LinkProperties getLinkProperties() {
-        return mIpConfiguration.linkProperties;
+    public StaticIpConfiguration getStaticIpConfiguration() {
+        return mIpConfiguration.getStaticIpConfiguration();
     }
 
     /** @hide */
-    public void setLinkProperties(LinkProperties linkProperties) {
-        mIpConfiguration.linkProperties = linkProperties;
+    public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) {
+        mIpConfiguration.setStaticIpConfiguration(staticIpConfiguration);
     }
 
     /** @hide */
@@ -1126,9 +1126,19 @@
     }
 
     /** @hide */
+    public ProxyInfo getHttpProxy() {
+        return mIpConfiguration.httpProxy;
+    }
+
+    /** @hide */
+    public void setHttpProxy(ProxyInfo httpProxy) {
+        mIpConfiguration.httpProxy = httpProxy;
+    }
+
+    /** @hide */
     public void setProxy(ProxySettings settings, ProxyInfo proxy) {
         mIpConfiguration.proxySettings = settings;
-        mIpConfiguration.linkProperties.setHttpProxy(proxy);
+        mIpConfiguration.httpProxy = proxy;
     }
 
     /** Implement the Parcelable interface {@hide} */
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index e27bd7e..3d976e7 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1696,6 +1696,7 @@
      *
      * @hide
      */
+    @SystemApi
     public void connect(WifiConfiguration config, ActionListener listener) {
         if (config == null) throw new IllegalArgumentException("config cannot be null");
         validateChannel();
@@ -1718,6 +1719,7 @@
      * initialized again
      * @hide
      */
+    @SystemApi
     public void connect(int networkId, ActionListener listener) {
         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
         validateChannel();
@@ -1742,6 +1744,7 @@
      * initialized again
      * @hide
      */
+    @SystemApi
     public void save(WifiConfiguration config, ActionListener listener) {
         if (config == null) throw new IllegalArgumentException("config cannot be null");
         validateChannel();
@@ -1761,6 +1764,7 @@
      * initialized again
      * @hide
      */
+    @SystemApi
     public void forget(int netId, ActionListener listener) {
         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
         validateChannel();
@@ -1776,6 +1780,7 @@
      * initialized again
      * @hide
      */
+    @SystemApi
     public void disable(int netId, ActionListener listener) {
         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
         validateChannel();