Merge "Fix a typo on TvContract." into lmp-preview-dev
diff --git a/Android.mk b/Android.mk
index 62d5446..8603d99 100644
--- a/Android.mk
+++ b/Android.mk
@@ -78,6 +78,7 @@
 	core/java/android/app/IServiceConnection.aidl \
 	core/java/android/app/IStopUserCallback.aidl \
 	core/java/android/app/task/ITaskCallback.aidl \
+	core/java/android/app/task/ITaskManager.aidl \
 	core/java/android/app/task/ITaskService.aidl \
 	core/java/android/app/IThumbnailRetriever.aidl \
 	core/java/android/app/ITransientNotification.aidl \
@@ -328,6 +329,7 @@
 	telecomm/java/com/android/internal/telecomm/ICallServiceSelectorAdapter.aidl \
 	telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl \
 	telecomm/java/com/android/internal/telecomm/IInCallService.aidl \
+	telecomm/java/com/android/internal/telecomm/ITelecommService.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
diff --git a/api/current.txt b/api/current.txt
index 96e83f7..df908e0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5351,6 +5351,57 @@
 
 package android.app.task {
 
+  public class Task implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getBackoffPolicy();
+    method public android.os.Bundle getExtras();
+    method public long getInitialBackoffMillis();
+    method public long getIntervalMillis();
+    method public long getMaxExecutionDelayMillis();
+    method public long getMinLatencyMillis();
+    method public int getNetworkCapabilities();
+    method public android.content.ComponentName getService();
+    method public int getTaskId();
+    method public boolean isPeriodic();
+    method public boolean isRequireCharging();
+    method public boolean isRequireDeviceIdle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static abstract interface Task.BackoffPolicy {
+    field public static final int EXPONENTIAL = 1; // 0x1
+    field public static final int LINEAR = 0; // 0x0
+  }
+
+  public final class Task.Builder {
+    ctor public Task.Builder(int, android.content.ComponentName);
+    method public android.app.task.Task build();
+    method public android.app.task.Task.Builder setBackoffCriteria(long, int);
+    method public android.app.task.Task.Builder setExtras(android.os.Bundle);
+    method public android.app.task.Task.Builder setMinimumLatency(long);
+    method public android.app.task.Task.Builder setOverrideDeadline(long);
+    method public android.app.task.Task.Builder setPeriodic(long);
+    method public android.app.task.Task.Builder setRequiredNetworkCapabilities(int);
+    method public android.app.task.Task.Builder setRequiresCharging(boolean);
+    method public android.app.task.Task.Builder setRequiresDeviceIdle(boolean);
+  }
+
+  public static abstract interface Task.NetworkType {
+    field public static final int ANY = 0; // 0x0
+    field public static final int UNMETERED = 1; // 0x1
+  }
+
+  public abstract class TaskManager {
+    ctor public TaskManager();
+    method public abstract void cancel(int);
+    method public abstract void cancelAll();
+    method public abstract java.util.List<android.app.task.Task> getAllPendingTasks();
+    method public abstract int schedule(android.app.task.Task);
+    field public static final int RESULT_INVALID_PARAMETERS = -1; // 0xffffffff
+    field public static final int RESULT_OVER_QUOTA = -2; // 0xfffffffe
+  }
+
   public class TaskParams implements android.os.Parcelable {
     method public int describeContents();
     method public android.os.Bundle getExtras();
@@ -6974,6 +7025,7 @@
     field public static final java.lang.String SEARCH_SERVICE = "search";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
+    field public static final java.lang.String TASK_SERVICE = "task";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
     field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
     field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
@@ -7912,55 +7964,6 @@
     method public abstract void onStatusChanged(int);
   }
 
-  public class Task implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getBackoffPolicy();
-    method public android.os.Bundle getExtras();
-    method public long getInitialBackoffMillis();
-    method public long getIntervalMillis();
-    method public long getMaxExecutionDelayMillis();
-    method public long getMinLatencyMillis();
-    method public int getNetworkCapabilities();
-    method public android.content.ComponentName getService();
-    method public int getTaskId();
-    method public boolean isPeriodic();
-    method public boolean isRequireCharging();
-    method public boolean isRequireDeviceIdle();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public static abstract interface Task.BackoffPolicy {
-    field public static final int EXPONENTIAL = 1; // 0x1
-    field public static final int LINEAR = 0; // 0x0
-  }
-
-  public final class Task.Builder {
-    ctor public Task.Builder(int, android.content.ComponentName);
-    method public android.content.Task build();
-    method public android.content.Task.Builder setBackoffCriteria(long, int);
-    method public android.content.Task.Builder setExtras(android.os.Bundle);
-    method public android.content.Task.Builder setMinimumLatency(long);
-    method public android.content.Task.Builder setOverrideDeadline(long);
-    method public android.content.Task.Builder setPeriodic(long);
-    method public android.content.Task.Builder setRequiredNetworkCapabilities(int);
-    method public android.content.Task.Builder setRequiresCharging(boolean);
-    method public android.content.Task.Builder setRequiresDeviceIdle(boolean);
-  }
-
-  public static abstract interface Task.NetworkType {
-    field public static final int ANY = 0; // 0x0
-    field public static final int UNMETERED = 1; // 0x1
-  }
-
-  public abstract class TaskManager {
-    ctor public TaskManager();
-    method public abstract void cancel(int);
-    method public abstract void cancelAll();
-    method public abstract java.util.List<android.content.Task> getAllPendingTasks();
-    method public abstract int schedule(android.content.Task);
-  }
-
   public class UriMatcher {
     ctor public UriMatcher(int);
     method public void addURI(java.lang.String, java.lang.String, int);
@@ -12150,7 +12153,9 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AVAILABLE_SCENE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AWB_AVAILABLE_MODES;
-    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_MAX_REGIONS;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_MAX_REGIONS_AE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_MAX_REGIONS_AF;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_MAX_REGIONS_AWB;
     field public static final android.hardware.camera2.CameraCharacteristics.Key EDGE_AVAILABLE_EDGE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key FLASH_INFO_AVAILABLE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
@@ -12164,11 +12169,12 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_HYPERFOCAL_DISTANCE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_MINIMUM_FOCUS_DISTANCE;
-    field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_SHADING_MAP_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_AVAILABLE_CAPABILITIES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_INPUT_STREAMS;
-    field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_STREAMS;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_PROC;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_PROC_STALLING;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_RAW;
     field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PARTIAL_RESULT_COUNT;
     field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PIPELINE_MAX_DEPTH;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
@@ -12388,6 +12394,7 @@
     field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int NOISE_REDUCTION_MODE_OFF = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5; // 0x5
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 3; // 0x3
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 2; // 0x2
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4; // 0x4
     field public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; // 0x0
@@ -12481,9 +12488,7 @@
     field public static final android.hardware.camera2.CaptureRequest.Key EDGE_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key FLASH_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key HOT_PIXEL_MODE;
-    field public static final android.hardware.camera2.CaptureRequest.Key JPEG_GPS_COORDINATES;
-    field public static final android.hardware.camera2.CaptureRequest.Key JPEG_GPS_PROCESSING_METHOD;
-    field public static final android.hardware.camera2.CaptureRequest.Key JPEG_GPS_TIMESTAMP;
+    field public static final android.hardware.camera2.CaptureRequest.Key JPEG_GPS_LOCATION;
     field public static final android.hardware.camera2.CaptureRequest.Key JPEG_ORIENTATION;
     field public static final android.hardware.camera2.CaptureRequest.Key JPEG_QUALITY;
     field public static final android.hardware.camera2.CaptureRequest.Key JPEG_THUMBNAIL_QUALITY;
@@ -12504,9 +12509,7 @@
     field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_FACE_DETECT_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_HOT_PIXEL_MAP_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_LENS_SHADING_MAP_MODE;
-    field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_CURVE_BLUE;
-    field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_CURVE_GREEN;
-    field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_CURVE_RED;
+    field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_CURVE;
     field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_MODE;
   }
 
@@ -12559,9 +12562,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key FLASH_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key FLASH_STATE;
     field public static final android.hardware.camera2.CaptureResult.Key HOT_PIXEL_MODE;
-    field public static final android.hardware.camera2.CaptureResult.Key JPEG_GPS_COORDINATES;
-    field public static final android.hardware.camera2.CaptureResult.Key JPEG_GPS_PROCESSING_METHOD;
-    field public static final android.hardware.camera2.CaptureResult.Key JPEG_GPS_TIMESTAMP;
+    field public static final android.hardware.camera2.CaptureResult.Key JPEG_GPS_LOCATION;
     field public static final android.hardware.camera2.CaptureResult.Key JPEG_ORIENTATION;
     field public static final android.hardware.camera2.CaptureResult.Key JPEG_QUALITY;
     field public static final android.hardware.camera2.CaptureResult.Key JPEG_THUMBNAIL_QUALITY;
@@ -12590,12 +12591,10 @@
     field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_FACE_DETECT_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_HOT_PIXEL_MAP;
     field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_HOT_PIXEL_MAP_MODE;
-    field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_LENS_SHADING_MAP;
+    field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_LENS_SHADING_CORRECTION_MAP;
     field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_LENS_SHADING_MAP_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_SCENE_FLICKER;
-    field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_CURVE_BLUE;
-    field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_CURVE_GREEN;
-    field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_CURVE_RED;
+    field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_CURVE;
     field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_MODE;
   }
 
@@ -21669,10 +21668,6 @@
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
-    field public static final int CRYPT_TYPE_DEFAULT = 1; // 0x1
-    field public static final int CRYPT_TYPE_PASSWORD = 0; // 0x0
-    field public static final int CRYPT_TYPE_PATTERN = 2; // 0x2
-    field public static final int CRYPT_TYPE_PIN = 3; // 0x3
   }
 
 }
@@ -26348,7 +26343,7 @@
     field public static final int TOUCHABLE_INSETS_CONTENT = 1; // 0x1
     field public static final int TOUCHABLE_INSETS_FRAME = 0; // 0x0
     field public static final int TOUCHABLE_INSETS_REGION = 3; // 0x3
-    field public int contentTopInsets;
+    field public final android.graphics.Rect contentInsets;
     field public int touchableInsets;
     field public final android.graphics.Region touchableRegion;
   }
@@ -27427,306 +27422,6 @@
 
 }
 
-package android.telecomm {
-
-  public final class CallAudioState implements android.os.Parcelable {
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public static int ROUTE_ALL;
-    field public static int ROUTE_BLUETOOTH;
-    field public static int ROUTE_EARPIECE;
-    field public static int ROUTE_SPEAKER;
-    field public static int ROUTE_WIRED_HEADSET;
-    field public static int ROUTE_WIRED_OR_EARPIECE;
-    field public final boolean isMuted;
-    field public final int route;
-    field public final int supportedRouteMask;
-  }
-
-  public class CallCapabilities {
-    ctor public CallCapabilities();
-    field public static final int ADD_CALL = 16; // 0x10
-    field public static final int ALL = 511; // 0x1ff
-    field public static final int CONNECTION_HANDOFF = 256; // 0x100
-    field public static final int GENERIC_CONFERENCE = 128; // 0x80
-    field public static final int HOLD = 1; // 0x1
-    field public static final int MERGE_CALLS = 4; // 0x4
-    field public static final int MUTE = 64; // 0x40
-    field public static final int RESPOND_VIA_TEXT = 32; // 0x20
-    field public static final int SUPPORT_HOLD = 2; // 0x2
-    field public static final int SWAP_CALLS = 8; // 0x8
-  }
-
-  public final class CallInfo implements android.os.Parcelable {
-    ctor public CallInfo(java.lang.String, android.telecomm.CallState, android.net.Uri);
-    method public int describeContents();
-    method public android.telecomm.CallServiceDescriptor getCurrentCallServiceDescriptor();
-    method public android.os.Bundle getExtras();
-    method public android.telecomm.GatewayInfo getGatewayInfo();
-    method public android.net.Uri getHandle();
-    method public java.lang.String getId();
-    method public android.net.Uri getOriginalHandle();
-    method public android.telecomm.CallState getState();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public final class CallNumberPresentation extends java.lang.Enum {
-    method public static android.telecomm.CallNumberPresentation valueOf(java.lang.String);
-    method public static final android.telecomm.CallNumberPresentation[] values();
-    enum_constant public static final android.telecomm.CallNumberPresentation ALLOWED;
-    enum_constant public static final android.telecomm.CallNumberPresentation PAYPHONE;
-    enum_constant public static final android.telecomm.CallNumberPresentation RESTRICTED;
-    enum_constant public static final android.telecomm.CallNumberPresentation UNKNOWN;
-  }
-
-  public abstract class CallService extends android.app.Service {
-    ctor public CallService();
-    method public abstract void abort(java.lang.String);
-    method public abstract void answer(java.lang.String);
-    method public abstract void call(android.telecomm.CallInfo);
-    method public abstract void disconnect(java.lang.String);
-    method protected final android.telecomm.CallServiceAdapter getAdapter();
-    method public final android.os.IBinder getBinder();
-    method public abstract void hold(java.lang.String);
-    method public abstract void isCompatibleWith(android.telecomm.CallInfo);
-    method protected void onAdapterAttached(android.telecomm.CallServiceAdapter);
-    method public abstract void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract void playDtmfTone(java.lang.String, char);
-    method public abstract void reject(java.lang.String);
-    method public abstract void setIncomingCallId(java.lang.String, android.os.Bundle);
-    method public abstract void stopDtmfTone(java.lang.String);
-    method public abstract void unhold(java.lang.String);
-  }
-
-  public final class CallServiceAdapter {
-    method public void handleFailedOutgoingCall(java.lang.String, java.lang.String);
-    method public void handleSuccessfulOutgoingCall(java.lang.String);
-    method public void notifyIncomingCall(android.telecomm.CallInfo);
-    method public void setActive(java.lang.String);
-    method public void setDialing(java.lang.String);
-    method public void setDisconnected(java.lang.String, int, java.lang.String);
-    method public void setIsCompatibleWith(java.lang.String, boolean);
-    method public void setOnHold(java.lang.String);
-    method public void setRinging(java.lang.String);
-  }
-
-  public final class CallServiceDescriptor implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.lang.String getCallServiceId();
-    method public int getNetworkType();
-    method public android.content.ComponentName getServiceComponent();
-    method public static android.telecomm.CallServiceDescriptor.Builder newBuilder(android.content.Context);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public static final int FLAG_MOBILE = 4; // 0x4
-    field public static final int FLAG_PSTN = 2; // 0x2
-    field public static final int FLAG_WIFI = 1; // 0x1
-  }
-
-  public static class CallServiceDescriptor.Builder {
-    method public android.telecomm.CallServiceDescriptor build();
-    method public android.telecomm.CallServiceDescriptor.Builder setCallService(java.lang.Class<? extends android.telecomm.CallService>);
-    method public android.telecomm.CallServiceDescriptor.Builder setNetworkType(int);
-  }
-
-  public final class CallServiceLookupResponse {
-    method public void setCallServiceDescriptors(java.util.List<android.telecomm.CallServiceDescriptor>);
-  }
-
-  public abstract class CallServiceProvider extends android.app.Service {
-    ctor protected CallServiceProvider();
-    method public abstract void lookupCallServices(android.telecomm.CallServiceLookupResponse);
-    method public android.os.IBinder onBind(android.content.Intent);
-  }
-
-  public abstract class CallServiceSelector extends android.app.Service {
-    ctor protected CallServiceSelector();
-    method protected final void cancelOutgoingCall(android.telecomm.CallInfo);
-    method protected final android.telecomm.CallServiceSelectorAdapter getAdapter();
-    method protected final java.util.Collection<android.telecomm.CallInfo> getCalls();
-    method protected void onAdapterAttached(android.telecomm.CallServiceSelectorAdapter);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method protected abstract void select(android.telecomm.CallInfo, java.util.List<android.telecomm.CallServiceDescriptor>);
-  }
-
-  public final class CallServiceSelectorAdapter {
-    method public void cancelOutgoingCall(java.lang.String);
-    method public void setHandoffInfo(java.lang.String, android.net.Uri, android.os.Bundle);
-    method public void setSelectedCallServices(java.lang.String, java.util.List<android.telecomm.CallServiceDescriptor>);
-  }
-
-  public final class CallState extends java.lang.Enum {
-    method public static android.telecomm.CallState valueOf(java.lang.String);
-    method public static final android.telecomm.CallState[] values();
-    enum_constant public static final android.telecomm.CallState ACTIVE;
-    enum_constant public static final android.telecomm.CallState DIALING;
-    enum_constant public static final android.telecomm.CallState DISCONNECTED;
-    enum_constant public static final android.telecomm.CallState NEW;
-    enum_constant public static final android.telecomm.CallState ON_HOLD;
-    enum_constant public static final android.telecomm.CallState POST_DIAL;
-    enum_constant public static final android.telecomm.CallState POST_DIAL_WAIT;
-    enum_constant public static final android.telecomm.CallState RINGING;
-  }
-
-  public abstract class Connection {
-    ctor protected Connection();
-    method public final android.telecomm.CallAudioState getCallAudioState();
-    method public final android.net.Uri getHandle();
-    method protected void onAbort();
-    method protected void onAnswer();
-    method protected void onDisconnect();
-    method protected void onHold();
-    method protected void onPlayDtmfTone(char);
-    method protected void onReject();
-    method protected void onSetAudioState(android.telecomm.CallAudioState);
-    method protected void onSetSignal(android.os.Bundle);
-    method protected void onStopDtmfTone();
-    method protected void onUnhold();
-    method protected void setActive();
-    method public void setAudioState(android.telecomm.CallAudioState);
-    method protected void setDialing();
-    method protected void setDisconnected(int, java.lang.String);
-    method protected void setHandle(android.net.Uri);
-    method protected void setOnHold();
-    method protected void setRinging();
-    method public static java.lang.String stateToString(int);
-  }
-
-  public static abstract interface Connection.Listener {
-    method public abstract void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
-    method public abstract void onDestroyed(android.telecomm.Connection);
-    method public abstract void onDisconnected(android.telecomm.Connection, int, java.lang.String);
-    method public abstract void onHandleChanged(android.telecomm.Connection, android.net.Uri);
-    method public abstract void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
-    method public abstract void onStateChanged(android.telecomm.Connection, int);
-  }
-
-  public static class Connection.ListenerBase implements android.telecomm.Connection.Listener {
-    ctor public Connection.ListenerBase();
-    method public void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
-    method public void onDestroyed(android.telecomm.Connection);
-    method public void onDisconnected(android.telecomm.Connection, int, java.lang.String);
-    method public void onHandleChanged(android.telecomm.Connection, android.net.Uri);
-    method public void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
-    method public void onStateChanged(android.telecomm.Connection, int);
-  }
-
-  public final class Connection.State {
-    field public static final int ACTIVE = 3; // 0x3
-    field public static final int DIALING = 2; // 0x2
-    field public static final int DISCONNECTED = 5; // 0x5
-    field public static final int HOLDING = 4; // 0x4
-    field public static final int NEW = 0; // 0x0
-    field public static final int RINGING = 1; // 0x1
-  }
-
-  public final class ConnectionRequest {
-    ctor public ConnectionRequest(android.net.Uri, android.os.Bundle);
-    method public android.os.Bundle getExtras();
-    method public android.net.Uri getHandle();
-  }
-
-  public abstract class ConnectionService extends android.telecomm.CallService {
-    ctor public ConnectionService();
-    method public final void abort(java.lang.String);
-    method public final void answer(java.lang.String);
-    method public final void call(android.telecomm.CallInfo);
-    method public final void disconnect(java.lang.String);
-    method public final void hold(java.lang.String);
-    method public final void isCompatibleWith(android.telecomm.CallInfo);
-    method public final void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
-    method public void onCreateConnections(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
-    method public void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
-    method public void onFindSubscriptions(android.net.Uri, android.telecomm.Response<android.net.Uri, android.telecomm.Subscription>);
-    method public final void playDtmfTone(java.lang.String, char);
-    method public final void reject(java.lang.String);
-    method public final void setIncomingCallId(java.lang.String, android.os.Bundle);
-    method public final void stopDtmfTone(java.lang.String);
-    method public final void unhold(java.lang.String);
-  }
-
-  public class GatewayInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method public android.net.Uri getGatewayHandle();
-    method public java.lang.String getGatewayProviderPackageName();
-    method public android.net.Uri getOriginalHandle();
-    method public boolean isEmpty();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public final class InCallAdapter {
-    method public void answerCall(java.lang.String);
-    method public void disconnectCall(java.lang.String);
-    method public void handoffCall(java.lang.String);
-    method public void holdCall(java.lang.String);
-    method public void mute(boolean);
-    method public void playDtmfTone(java.lang.String, char);
-    method public void postDialContinue(java.lang.String);
-    method public void rejectCall(java.lang.String);
-    method public void setAudioRoute(int);
-    method public void stopDtmfTone(java.lang.String);
-    method public void unholdCall(java.lang.String);
-  }
-
-  public final class InCallCall implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getCapabilities();
-    method public long getConnectTimeMillis();
-    method public android.telecomm.CallServiceDescriptor getCurrentCallServiceDescriptor();
-    method public int getDisconnectCause();
-    method public android.telecomm.GatewayInfo getGatewayInfo();
-    method public android.net.Uri getHandle();
-    method public android.telecomm.CallServiceDescriptor getHandoffCallServiceDescriptor();
-    method public java.lang.String getId();
-    method public android.telecomm.CallState getState();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public abstract class InCallService extends android.app.Service {
-    ctor protected InCallService();
-    method protected abstract void addCall(android.telecomm.InCallCall);
-    method protected final android.telecomm.InCallAdapter getAdapter();
-    method protected void onAdapterAttached(android.telecomm.InCallAdapter);
-    method protected abstract void onAudioStateChanged(android.telecomm.CallAudioState);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method protected abstract void setPostDial(java.lang.String, java.lang.String);
-    method protected abstract void setPostDialWait(java.lang.String, java.lang.String);
-    method protected abstract void updateCall(android.telecomm.InCallCall);
-  }
-
-  public abstract interface Response {
-    method public abstract void onError(IN, java.lang.String);
-    method public abstract void onResult(IN, OUT...);
-  }
-
-  public class Subscription implements android.os.Parcelable {
-    ctor public Subscription();
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public final class TelecommConstants {
-    ctor public TelecommConstants();
-    field public static final java.lang.String ACTION_CALL_SERVICE;
-    field public static final java.lang.String ACTION_CALL_SERVICE_PROVIDER;
-    field public static final java.lang.String ACTION_CALL_SERVICE_SELECTOR;
-    field public static final java.lang.String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
-    field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
-    field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
-    field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecomm.extra.CALL_DISCONNECT_CAUSE";
-    field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
-    field public static final java.lang.String EXTRA_CALL_SERVICE_DESCRIPTOR = "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
-    field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.intent.extra.INCOMING_CALL_EXTRAS";
-  }
-
-}
-
 package android.telephony {
 
   public final class CellIdentityCdma implements android.os.Parcelable {
@@ -35849,10 +35544,14 @@
   public class ActionMenuView extends android.widget.LinearLayout {
     ctor public ActionMenuView(android.content.Context);
     ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
+    method public void dismissPopupMenus();
     method public android.view.Menu getMenu();
+    method public boolean hideOverflowMenu();
+    method public boolean isOverflowMenuShowing();
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onDetachedFromWindow();
     method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
+    method public boolean showOverflowMenu();
   }
 
   public static class ActionMenuView.LayoutParams extends android.widget.LinearLayout.LayoutParams {
@@ -38030,6 +37729,8 @@
     ctor public Toolbar(android.content.Context, android.util.AttributeSet);
     ctor public Toolbar(android.content.Context, android.util.AttributeSet, int);
     ctor public Toolbar(android.content.Context, android.util.AttributeSet, int, int);
+    method public void collapseActionView();
+    method public void dismissPopupMenus();
     method public int getContentInsetEnd();
     method public int getContentInsetLeft();
     method public int getContentInsetRight();
@@ -38040,7 +37741,10 @@
     method public android.graphics.drawable.Drawable getNavigationIcon();
     method public java.lang.CharSequence getSubtitle();
     method public java.lang.CharSequence getTitle();
+    method public boolean hasExpandedActionView();
+    method public boolean hideOverflowMenu();
     method public void inflateMenu(int);
+    method public boolean isOverflowMenuShowing();
     method protected void onLayout(boolean, int, int, int, int);
     method public void setContentInsetsAbsolute(int, int);
     method public void setContentInsetsRelative(int, int);
@@ -38048,6 +37752,8 @@
     method public void setLogo(android.graphics.drawable.Drawable);
     method public void setLogoDescription(int);
     method public void setLogoDescription(java.lang.CharSequence);
+    method public void setNavigationContentDescription(java.lang.CharSequence);
+    method public void setNavigationContentDescription(int);
     method public void setNavigationDescription(int);
     method public void setNavigationDescription(java.lang.CharSequence);
     method public void setNavigationIcon(int);
@@ -38058,17 +37764,18 @@
     method public void setSubtitle(java.lang.CharSequence);
     method public void setTitle(int);
     method public void setTitle(java.lang.CharSequence);
+    method public boolean showOverflowMenu();
   }
 
-  public static class Toolbar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+  public static class Toolbar.LayoutParams extends android.app.ActionBar.LayoutParams {
     ctor public Toolbar.LayoutParams(android.content.Context, android.util.AttributeSet);
     ctor public Toolbar.LayoutParams(int, int);
     ctor public Toolbar.LayoutParams(int, int, int);
     ctor public Toolbar.LayoutParams(int);
     ctor public Toolbar.LayoutParams(android.widget.Toolbar.LayoutParams);
+    ctor public Toolbar.LayoutParams(android.app.ActionBar.LayoutParams);
     ctor public Toolbar.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
     ctor public Toolbar.LayoutParams(android.view.ViewGroup.LayoutParams);
-    field public int gravity;
   }
 
   public static abstract interface Toolbar.OnMenuItemClickListener {
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 3c3df01..f05f4c7 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -1291,6 +1291,7 @@
 
         public LayoutParams(int width, int height) {
             super(width, height);
+            this.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
         }
 
         public LayoutParams(int width, int height, int gravity) {
@@ -1305,6 +1306,7 @@
 
         public LayoutParams(LayoutParams source) {
             super(source);
+            this.gravity = source.gravity;
         }
 
         public LayoutParams(ViewGroup.LayoutParams source) {
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index d08978bd..5e4ddd0 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -15,14 +15,23 @@
  */
 package android.app;
 
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.ResultReceiver;
 import android.transition.Transition;
 import android.transition.TransitionSet;
 import android.util.ArrayMap;
+import android.util.Pair;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.widget.ImageView;
 
@@ -181,6 +190,11 @@
      */
     public static final int MSG_CANCEL = 106;
 
+    /**
+     * When returning, this is the destination location for the shared element.
+     */
+    public static final int MSG_SHARED_ELEMENT_DESTINATION = 107;
+
     final private Window mWindow;
     final protected ArrayList<String> mAllSharedElementNames;
     final protected ArrayList<View> mSharedElements = new ArrayList<View>();
@@ -334,6 +348,210 @@
 
     protected abstract Transition getViewsTransition();
 
+    private static void setSharedElementState(View view, String name, Bundle transitionArgs,
+            int[] parentLoc) {
+        Bundle sharedElementBundle = transitionArgs.getBundle(name);
+        if (sharedElementBundle == null) {
+            return;
+        }
+
+        if (view instanceof ImageView) {
+            int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1);
+            if (scaleTypeInt >= 0) {
+                ImageView imageView = (ImageView) view;
+                ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt];
+                imageView.setScaleType(scaleType);
+                if (scaleType == ImageView.ScaleType.MATRIX) {
+                    float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX);
+                    Matrix matrix = new Matrix();
+                    matrix.setValues(matrixValues);
+                    imageView.setImageMatrix(matrix);
+                }
+            }
+        }
+
+        float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
+        view.setTranslationZ(z);
+
+        int x = sharedElementBundle.getInt(KEY_SCREEN_X);
+        int y = sharedElementBundle.getInt(KEY_SCREEN_Y);
+        int width = sharedElementBundle.getInt(KEY_WIDTH);
+        int height = sharedElementBundle.getInt(KEY_HEIGHT);
+
+        int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
+        int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
+        view.measure(widthSpec, heightSpec);
+
+        int left = x - parentLoc[0];
+        int top = y - parentLoc[1];
+        int right = left + width;
+        int bottom = top + height;
+        view.layout(left, top, right, bottom);
+    }
+
+    protected ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> setSharedElementState(
+            Bundle sharedElementState, final ArrayList<View> snapshots) {
+        ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageState =
+                new ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>>();
+        if (sharedElementState != null) {
+            int[] tempLoc = new int[2];
+            for (int i = 0; i < mSharedElementNames.size(); i++) {
+                View sharedElement = mSharedElements.get(i);
+                String name = mSharedElementNames.get(i);
+                Pair<ImageView.ScaleType, Matrix> originalState = getOldImageState(sharedElement,
+                        name, sharedElementState);
+                if (originalState != null) {
+                    originalImageState.put((ImageView) sharedElement, originalState);
+                }
+                View parent = (View) sharedElement.getParent();
+                parent.getLocationOnScreen(tempLoc);
+                setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
+            }
+        }
+        mListener.setSharedElementStart(mSharedElementNames, mSharedElements, snapshots);
+
+        getDecor().getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+                        mListener.setSharedElementEnd(mSharedElementNames, mSharedElements,
+                                snapshots);
+                        return true;
+                    }
+                }
+        );
+        return originalImageState;
+    }
+
+    private static Pair<ImageView.ScaleType, Matrix> getOldImageState(View view, String name,
+            Bundle transitionArgs) {
+        if (!(view instanceof ImageView)) {
+            return null;
+        }
+        Bundle bundle = transitionArgs.getBundle(name);
+        if (bundle == null) {
+            return null;
+        }
+        int scaleTypeInt = bundle.getInt(KEY_SCALE_TYPE, -1);
+        if (scaleTypeInt < 0) {
+            return null;
+        }
+
+        ImageView imageView = (ImageView) view;
+        ImageView.ScaleType originalScaleType = imageView.getScaleType();
+
+        Matrix originalMatrix = null;
+        if (originalScaleType == ImageView.ScaleType.MATRIX) {
+            originalMatrix = new Matrix(imageView.getImageMatrix());
+        }
+
+        return Pair.create(originalScaleType, originalMatrix);
+    }
+
+    protected ArrayList<View> createSnapshots(Bundle state, Collection<String> names) {
+        int numSharedElements = names.size();
+        if (numSharedElements == 0) {
+            return null;
+        }
+        ArrayList<View> snapshots = new ArrayList<View>(numSharedElements);
+        Context context = getWindow().getContext();
+        int[] parentLoc = new int[2];
+        getDecor().getLocationOnScreen(parentLoc);
+        for (String name: names) {
+            Bundle sharedElementBundle = state.getBundle(name);
+            if (sharedElementBundle != null) {
+                Bitmap bitmap = sharedElementBundle.getParcelable(KEY_BITMAP);
+                View snapshot = new View(context);
+                Resources resources = getWindow().getContext().getResources();
+                if (bitmap != null) {
+                    snapshot.setBackground(new BitmapDrawable(resources, bitmap));
+                }
+                snapshot.setViewName(name);
+                setSharedElementState(snapshot, name, state, parentLoc);
+                snapshots.add(snapshot);
+            }
+        }
+        return snapshots;
+    }
+
+    protected static void setOriginalImageViewState(
+            ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalState) {
+        for (int i = 0; i < originalState.size(); i++) {
+            ImageView imageView = originalState.keyAt(i);
+            Pair<ImageView.ScaleType, Matrix> state = originalState.valueAt(i);
+            imageView.setScaleType(state.first);
+            imageView.setImageMatrix(state.second);
+        }
+    }
+
+    protected Bundle captureSharedElementState() {
+        Bundle bundle = new Bundle();
+        int[] tempLoc = new int[2];
+        for (int i = 0; i < mSharedElementNames.size(); i++) {
+            View sharedElement = mSharedElements.get(i);
+            String name = mSharedElementNames.get(i);
+            captureSharedElementState(sharedElement, name, bundle, tempLoc);
+        }
+        return bundle;
+    }
+
+    /**
+     * Captures placement information for Views with a shared element name for
+     * Activity Transitions.
+     *
+     * @param view           The View to capture the placement information for.
+     * @param name           The shared element name in the target Activity to apply the placement
+     *                       information for.
+     * @param transitionArgs Bundle to store shared element placement information.
+     * @param tempLoc        A temporary int[2] for capturing the current location of views.
+     */
+    private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
+            int[] tempLoc) {
+        Bundle sharedElementBundle = new Bundle();
+        view.getLocationOnScreen(tempLoc);
+        float scaleX = view.getScaleX();
+        sharedElementBundle.putInt(KEY_SCREEN_X, tempLoc[0]);
+        int width = Math.round(view.getWidth() * scaleX);
+        sharedElementBundle.putInt(KEY_WIDTH, width);
+
+        float scaleY = view.getScaleY();
+        sharedElementBundle.putInt(KEY_SCREEN_Y, tempLoc[1]);
+        int height = Math.round(view.getHeight() * scaleY);
+        sharedElementBundle.putInt(KEY_HEIGHT, height);
+
+        sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
+
+        if (width > 0 && height > 0) {
+            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(bitmap);
+            view.draw(canvas);
+            sharedElementBundle.putParcelable(KEY_BITMAP, bitmap);
+        }
+
+        if (view instanceof ImageView) {
+            ImageView imageView = (ImageView) view;
+            int scaleTypeInt = scaleTypeToInt(imageView.getScaleType());
+            sharedElementBundle.putInt(KEY_SCALE_TYPE, scaleTypeInt);
+            if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) {
+                float[] matrix = new float[9];
+                imageView.getImageMatrix().getValues(matrix);
+                sharedElementBundle.putFloatArray(KEY_IMAGE_MATRIX, matrix);
+            }
+        }
+
+        transitionArgs.putBundle(name, sharedElementBundle);
+    }
+
+    private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
+        for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
+            if (scaleType == SCALE_TYPE_VALUES[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
         private Rect mEpicenter;
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1634d11..ff8688d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -133,10 +133,12 @@
 import android.accounts.AccountManager;
 import android.accounts.IAccountManager;
 import android.app.admin.DevicePolicyManager;
+import android.app.task.ITaskManager;
 import android.app.trust.TrustManager;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.appwidget.IAppWidgetService.Stub;
 import com.android.internal.os.IDropBoxManagerService;
 
 import java.io.File;
@@ -693,6 +695,12 @@
                 public Object createService(ContextImpl ctx) {
                 return new UsageStatsManager(ctx.getOuterContext());
         }});
+
+        registerService(TASK_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(TASK_SERVICE);
+                return new TaskManagerImpl(ITaskManager.Stub.asInterface(b));
+            }});
     }
 
     static ContextImpl getImpl(Context context) {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index bc97852..a8617b8 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -18,11 +18,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
 import android.graphics.Matrix;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
@@ -38,7 +34,6 @@
 import android.widget.ImageView;
 
 import java.util.ArrayList;
-import java.util.Collection;
 
 /**
  * This ActivityTransitionCoordinator is created by the Activity to manage
@@ -56,6 +51,7 @@
     private Handler mHandler;
     private boolean mIsCanceled;
     private ObjectAnimator mBackgroundAnimator;
+    private boolean mIsExitTransitionComplete;
 
     public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
             ArrayList<String> sharedElementNames,
@@ -76,6 +72,8 @@
                 }
             };
             mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
+            Bundle state = captureSharedElementState();
+            mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
         }
     }
 
@@ -98,9 +96,8 @@
                 break;
             case MSG_EXIT_TRANSITION_COMPLETE:
                 if (!mIsCanceled) {
-                    if (!mSharedElementTransitionStarted) {
-                        send(resultCode, resultData);
-                    } else {
+                    mIsExitTransitionComplete = true;
+                    if (mSharedElementTransitionStarted) {
                         onRemoteExitTransitionComplete();
                     }
                 }
@@ -183,6 +180,7 @@
         setViewVisibility(mSharedElements, View.VISIBLE);
         ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageViewState =
                 setSharedElementState(sharedElementState, sharedElementSnapshots);
+        requestLayoutForSharedElements();
 
         boolean startEnterTransition = allowOverlappingTransitions();
         boolean startSharedElementTransition = true;
@@ -200,6 +198,13 @@
         mResultReceiver = null; // all done sending messages.
     }
 
+    private void requestLayoutForSharedElements() {
+        int numSharedElements = mSharedElements.size();
+        for (int i = 0; i < numSharedElements; i++) {
+            mSharedElements.get(i).requestLayout();
+        }
+    }
+
     private Transition beginTransition(boolean startEnterTransition,
             boolean startSharedElementTransition) {
         Transition sharedElementTransition = null;
@@ -213,6 +218,19 @@
         }
 
         Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
+        if (startSharedElementTransition) {
+            if (transition == null) {
+                sharedElementTransitionStarted();
+            } else {
+                transition.addListener(new Transition.TransitionListenerAdapter() {
+                    @Override
+                    public void onTransitionStart(Transition transition) {
+                        transition.removeListener(this);
+                        sharedElementTransitionStarted();
+                    }
+                });
+            }
+        }
         if (transition != null) {
             TransitionManager.beginDelayedTransition(getDecor(), transition);
             if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
@@ -224,6 +242,13 @@
         return transition;
     }
 
+    private void sharedElementTransitionStarted() {
+        mSharedElementTransitionStarted = true;
+        if (mIsExitTransitionComplete) {
+            send(MSG_EXIT_TRANSITION_COMPLETE, null);
+        }
+    }
+
     private void startEnterTransition(Transition transition) {
         setViewVisibility(mTransitioningViews, View.VISIBLE);
         if (!mIsReturning) {
@@ -310,142 +335,4 @@
             startEnterTransition(transition);
         }
     }
-
-    private ArrayList<View> createSnapshots(Bundle state, Collection<String> names) {
-        int numSharedElements = names.size();
-        if (numSharedElements == 0) {
-            return null;
-        }
-        ArrayList<View> snapshots = new ArrayList<View>(numSharedElements);
-        Context context = getWindow().getContext();
-        int[] parentLoc = new int[2];
-        getDecor().getLocationOnScreen(parentLoc);
-        for (String name: names) {
-            Bundle sharedElementBundle = state.getBundle(name);
-            if (sharedElementBundle != null) {
-                Bitmap bitmap = sharedElementBundle.getParcelable(KEY_BITMAP);
-                View snapshot = new View(context);
-                Resources resources = getWindow().getContext().getResources();
-                snapshot.setBackground(new BitmapDrawable(resources, bitmap));
-                snapshot.setViewName(name);
-                setSharedElementState(snapshot, name, state, parentLoc);
-                snapshots.add(snapshot);
-            }
-        }
-        return snapshots;
-    }
-
-    private static void setSharedElementState(View view, String name, Bundle transitionArgs,
-            int[] parentLoc) {
-        Bundle sharedElementBundle = transitionArgs.getBundle(name);
-        if (sharedElementBundle == null) {
-            return;
-        }
-
-        if (view instanceof ImageView) {
-            int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1);
-            if (scaleTypeInt >= 0) {
-                ImageView imageView = (ImageView) view;
-                ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt];
-                imageView.setScaleType(scaleType);
-                if (scaleType == ImageView.ScaleType.MATRIX) {
-                    float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX);
-                    Matrix matrix = new Matrix();
-                    matrix.setValues(matrixValues);
-                    imageView.setImageMatrix(matrix);
-                }
-            }
-        }
-
-        float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
-        view.setTranslationZ(z);
-
-        int x = sharedElementBundle.getInt(KEY_SCREEN_X);
-        int y = sharedElementBundle.getInt(KEY_SCREEN_Y);
-        int width = sharedElementBundle.getInt(KEY_WIDTH);
-        int height = sharedElementBundle.getInt(KEY_HEIGHT);
-
-        int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
-        int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
-        view.measure(widthSpec, heightSpec);
-
-        int left = x - parentLoc[0];
-        int top = y - parentLoc[1];
-        int right = left + width;
-        int bottom = top + height;
-        view.layout(left, top, right, bottom);
-    }
-
-    private ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> setSharedElementState(
-            Bundle sharedElementState, final ArrayList<View> snapshots) {
-        ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageState =
-                new ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>>();
-        if (sharedElementState != null) {
-            int[] tempLoc = new int[2];
-            for (int i = 0; i < mSharedElementNames.size(); i++) {
-                View sharedElement = mSharedElements.get(i);
-                String name = mSharedElementNames.get(i);
-                Pair<ImageView.ScaleType, Matrix> originalState = getOldImageState(sharedElement,
-                        name, sharedElementState);
-                if (originalState != null) {
-                    originalImageState.put((ImageView) sharedElement, originalState);
-                }
-                View parent = (View) sharedElement.getParent();
-                parent.getLocationOnScreen(tempLoc);
-                setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
-                sharedElement.requestLayout();
-            }
-        }
-        mListener.setSharedElementStart(mSharedElementNames, mSharedElements, snapshots);
-
-        getDecor().getViewTreeObserver().addOnPreDrawListener(
-                new ViewTreeObserver.OnPreDrawListener() {
-                    @Override
-                    public boolean onPreDraw() {
-                        getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
-                        mListener.setSharedElementEnd(mSharedElementNames, mSharedElements,
-                                snapshots);
-                        mSharedElementTransitionStarted = true;
-                        return true;
-                    }
-                }
-        );
-        return originalImageState;
-    }
-
-    private static Pair<ImageView.ScaleType, Matrix> getOldImageState(View view, String name,
-            Bundle transitionArgs) {
-        if (!(view instanceof ImageView)) {
-            return null;
-        }
-        Bundle bundle = transitionArgs.getBundle(name);
-        if (bundle == null) {
-            return null;
-        }
-        int scaleTypeInt = bundle.getInt(KEY_SCALE_TYPE, -1);
-        if (scaleTypeInt < 0) {
-            return null;
-        }
-
-        ImageView imageView = (ImageView) view;
-        ImageView.ScaleType originalScaleType = imageView.getScaleType();
-
-        Matrix originalMatrix = null;
-        if (originalScaleType == ImageView.ScaleType.MATRIX) {
-            originalMatrix = new Matrix(imageView.getImageMatrix());
-        }
-
-        return Pair.create(originalScaleType, originalMatrix);
-    }
-
-    private static void setOriginalImageViewState(
-            ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalState) {
-        for (int i = 0; i < originalState.size(); i++) {
-            ImageView imageView = originalState.keyAt(i);
-            Pair<ImageView.ScaleType, Matrix> state = originalState.valueAt(i);
-            imageView.setScaleType(state.first);
-            imageView.setImageMatrix(state.second);
-        }
-    }
-
 }
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 93eb53e..a71d649 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -19,8 +19,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -29,7 +27,7 @@
 import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.view.View;
-import android.widget.ImageView;
+import android.view.ViewTreeObserver;
 
 import java.util.ArrayList;
 
@@ -62,6 +60,10 @@
 
     private boolean mIsHidden;
 
+    private boolean mExitTransitionStarted;
+
+    private Bundle mExitSharedElementBundle;
+
     public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
             ArrayList<String> accepted, ArrayList<String> mapped, boolean isReturning) {
         super(activity.getWindow(), names, accepted, mapped, getListener(activity, isReturning),
@@ -102,15 +104,32 @@
                 setViewVisibility(mSharedElements, View.VISIBLE);
                 mIsHidden = true;
                 break;
+            case MSG_SHARED_ELEMENT_DESTINATION:
+                mExitSharedElementBundle = resultData;
+                if (mExitTransitionStarted) {
+                    startSharedElementExit();
+                }
+                break;
+        }
+    }
+
+    private void startSharedElementExit() {
+        if (!mSharedElements.isEmpty() && getSharedElementTransition() != null) {
+            Transition transition = getSharedElementExitTransition();
+            TransitionManager.beginDelayedTransition(getDecor(), transition);
+            ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
+                    mSharedElementNames);
+            setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
         }
     }
 
     private void hideSharedElements() {
         setViewVisibility(mSharedElements, View.INVISIBLE);
+        finishIfNecessary();
     }
 
     public void startExit() {
-        beginTransition();
+        beginTransitions();
         setViewVisibility(mTransitioningViews, View.INVISIBLE);
     }
 
@@ -140,7 +159,30 @@
                 }
             }
         }, options);
-        startExit();
+        Transition sharedElementTransition = mSharedElements.isEmpty()
+                ? null : getSharedElementTransition();
+        if (sharedElementTransition == null) {
+            sharedElementTransitionComplete();
+        }
+        Transition transition = mergeTransitions(sharedElementTransition, getExitTransition());
+        if (transition == null) {
+            mExitTransitionStarted = true;
+        } else {
+            TransitionManager.beginDelayedTransition(getDecor(), transition);
+            setViewVisibility(mTransitioningViews, View.INVISIBLE);
+            getDecor().getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                @Override
+                public boolean onPreDraw() {
+                    getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+                    mExitTransitionStarted = true;
+                    if (mExitSharedElementBundle != null) {
+                        startSharedElementExit();
+                    }
+                    notifyComplete();
+                    return true;
+                }
+            });
+        }
     }
 
     private void fadeOutBackground() {
@@ -162,24 +204,13 @@
         }
     }
 
-    private void beginTransition() {
-        Transition sharedElementTransition = configureTransition(getSharedElementTransition());
-        Transition viewsTransition = configureTransition(getViewsTransition());
-        viewsTransition = addTargets(viewsTransition, mTransitioningViews);
-        if (sharedElementTransition == null || mSharedElements.isEmpty()) {
-            sharedElementTransitionComplete();
-            sharedElementTransition = null;
-        } else {
-            sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
-                @Override
-                public void onTransitionEnd(Transition transition) {
-                    sharedElementTransitionComplete();
-                }
-            });
+    private Transition getExitTransition() {
+        Transition viewsTransition = null;
+        if (!mTransitioningViews.isEmpty()) {
+            viewsTransition = configureTransition(getViewsTransition());
         }
-        if (viewsTransition == null || mTransitioningViews.isEmpty()) {
+        if (viewsTransition == null) {
             exitTransitionComplete();
-            viewsTransition = null;
         } else {
             viewsTransition.addListener(new Transition.TransitionListenerAdapter() {
                 @Override
@@ -189,13 +220,46 @@
                         setViewVisibility(mTransitioningViews, View.VISIBLE);
                     }
                 }
+
+                @Override
+                public void onTransitionCancel(Transition transition) {
+                    super.onTransitionCancel(transition);
+                }
             });
         }
+        return viewsTransition;
+    }
+
+    private Transition getSharedElementExitTransition() {
+        Transition sharedElementTransition = null;
+        if (!mSharedElements.isEmpty()) {
+            sharedElementTransition = configureTransition(getSharedElementTransition());
+        }
+        if (sharedElementTransition == null) {
+            sharedElementTransitionComplete();
+        } else {
+            sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
+                @Override
+                public void onTransitionEnd(Transition transition) {
+                    sharedElementTransitionComplete();
+                    if (mIsHidden) {
+                        setViewVisibility(mSharedElements, View.VISIBLE);
+                    }
+                }
+            });
+            mSharedElements.get(0).invalidate();
+        }
+        return sharedElementTransition;
+    }
+
+    private void beginTransitions() {
+        Transition sharedElementTransition = getSharedElementExitTransition();
+        Transition viewsTransition = getExitTransition();
 
         Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
-        TransitionManager.beginDelayedTransition(getDecor(), transition);
-        if (viewsTransition == null && sharedElementTransition != null) {
-            mSharedElements.get(0).requestLayout();
+        mExitTransitionStarted = true;
+        if (transition != null) {
+            TransitionManager.beginDelayedTransition(getDecor(), transition);
         }
     }
 
@@ -205,18 +269,12 @@
     }
 
     protected boolean isReadyToNotify() {
-        return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady;
+        return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady
+                && mExitTransitionStarted;
     }
 
     private void sharedElementTransitionComplete() {
-        Bundle bundle = new Bundle();
-        int[] tempLoc = new int[2];
-        for (int i = 0; i < mSharedElementNames.size(); i++) {
-            View sharedElement = mSharedElements.get(i);
-            String name = mSharedElementNames.get(i);
-            captureSharedElementState(sharedElement, name, bundle, tempLoc);
-        }
-        mSharedElementBundle = bundle;
+        mSharedElementBundle = captureSharedElementState();
         notifyComplete();
     }
 
@@ -230,15 +288,23 @@
                 mExitNotified = true;
                 mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
                 mResultReceiver = null; // done talking
-                if (mIsReturning) {
-                    mActivity.finish();
-                    mActivity.overridePendingTransition(0, 0);
-                }
-                mActivity = null;
+                finishIfNecessary();
             }
         }
     }
 
+    private void finishIfNecessary() {
+        if (mIsReturning && mExitNotified && (mSharedElements.isEmpty()
+                || mSharedElements.get(0).getVisibility() == View.INVISIBLE)) {
+            mActivity.finish();
+            mActivity.overridePendingTransition(0, 0);
+            mActivity = null;
+        }
+        if (!mIsReturning && mExitNotified) {
+            mActivity = null; // don't need it anymore
+        }
+    }
+
     @Override
     protected Transition getViewsTransition() {
         if (mIsReturning) {
@@ -255,58 +321,4 @@
             return getWindow().getSharedElementExitTransition();
         }
     }
-
-    /**
-     * Captures placement information for Views with a shared element name for
-     * Activity Transitions.
-     *
-     * @param view           The View to capture the placement information for.
-     * @param name           The shared element name in the target Activity to apply the placement
-     *                       information for.
-     * @param transitionArgs Bundle to store shared element placement information.
-     * @param tempLoc        A temporary int[2] for capturing the current location of views.
-     */
-    private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
-            int[] tempLoc) {
-        Bundle sharedElementBundle = new Bundle();
-        view.getLocationOnScreen(tempLoc);
-        float scaleX = view.getScaleX();
-        sharedElementBundle.putInt(KEY_SCREEN_X, tempLoc[0]);
-        int width = Math.round(view.getWidth() * scaleX);
-        sharedElementBundle.putInt(KEY_WIDTH, width);
-
-        float scaleY = view.getScaleY();
-        sharedElementBundle.putInt(KEY_SCREEN_Y, tempLoc[1]);
-        int height = Math.round(view.getHeight() * scaleY);
-        sharedElementBundle.putInt(KEY_HEIGHT, height);
-
-        sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
-
-        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        view.draw(canvas);
-        sharedElementBundle.putParcelable(KEY_BITMAP, bitmap);
-
-        if (view instanceof ImageView) {
-            ImageView imageView = (ImageView) view;
-            int scaleTypeInt = scaleTypeToInt(imageView.getScaleType());
-            sharedElementBundle.putInt(KEY_SCALE_TYPE, scaleTypeInt);
-            if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) {
-                float[] matrix = new float[9];
-                imageView.getImageMatrix().getValues(matrix);
-                sharedElementBundle.putFloatArray(KEY_IMAGE_MATRIX, matrix);
-            }
-        }
-
-        transitionArgs.putBundle(name, sharedElementBundle);
-    }
-
-    private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
-        for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
-            if (scaleType == SCALE_TYPE_VALUES[i]) {
-                return i;
-            }
-        }
-        return -1;
-    }
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 25f24b1..90aeaae 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3716,7 +3716,7 @@
          * this notification. This action will no longer display separately from the
          * notification's content.
          *
-         * <p>For notifications with multiple pages, child pages can also have content action's
+         * <p>For notifications with multiple pages, child pages can also have content actions
          * set, although the list of available actions comes from the main notification and not
          * from the child page's notification.
          *
@@ -3731,16 +3731,18 @@
         }
 
         /**
-         * Get the action index from this notification's actions to be clickable with the
-         * content of this notification. This action will no longer display separately
+         * Get the index of the notification action, if any, that was specified as being clickable
+         * with the content of this notification. This action will no longer display separately
          * from the notification's content.
          *
-         * <p>For notifications with multiple pages, child pages can also have content action's
+         * <p>For notifications with multiple pages, child pages can also have content actions
          * set, although the list of available actions comes from the main notification and not
          * from the child page's notification.
          *
          * <p>If wearable specific actions were added to the main notification, this index will
          * apply to that list, otherwise it will apply to the regular actions list.
+         *
+         * @return the action index or {@link #UNSET_ACTION_INDEX} if no action was selected.
          */
         public int getContentAction() {
             return mContentActionIndex;
diff --git a/core/java/android/app/TaskManagerImpl.java b/core/java/android/app/TaskManagerImpl.java
new file mode 100644
index 0000000..f42839e
--- /dev/null
+++ b/core/java/android/app/TaskManagerImpl.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+// in android.app so ContextImpl has package access
+package android.app;
+
+import android.app.task.ITaskManager;
+import android.app.task.Task;
+import android.app.task.TaskManager;
+
+import java.util.List;
+
+
+/**
+ * Concrete implementation of the TaskManager interface
+ * @hide 
+ */
+public class TaskManagerImpl extends TaskManager {
+    ITaskManager mBinder;
+
+    /* package */ TaskManagerImpl(ITaskManager binder) {
+        mBinder = binder;
+    }
+
+    @Override
+    public int schedule(Task task) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public void cancel(int taskId) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void cancelAll() {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public List<Task> getAllPendingTasks() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}
diff --git a/core/java/android/app/task/ITaskManager.aidl b/core/java/android/app/task/ITaskManager.aidl
new file mode 100644
index 0000000..b56c78a
--- /dev/null
+++ b/core/java/android/app/task/ITaskManager.aidl
@@ -0,0 +1,30 @@
+/**
+ * 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.app.task;
+
+import android.app.task.Task;
+
+ /**
+  * IPC interface that supports the app-facing {@link #TaskManager} api.
+  * {@hide}
+  */
+interface ITaskManager {
+    int schedule(in Task task);
+    void cancel(int taskId);
+    void cancelAll();
+    List<Task> getAllPendingTasks();
+}
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/app/task/Task.aidl
new file mode 100644
index 0000000..1f25439
--- /dev/null
+++ b/core/java/android/app/task/Task.aidl
@@ -0,0 +1,20 @@
+/**
+ * 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.app.task;
+
+parcelable Task;
+ 
\ No newline at end of file
diff --git a/core/java/android/content/Task.java b/core/java/android/app/task/Task.java
similarity index 96%
rename from core/java/android/content/Task.java
rename to core/java/android/app/task/Task.java
index 407880f..dd184a5 100644
--- a/core/java/android/content/Task.java
+++ b/core/java/android/app/task/Task.java
@@ -14,15 +14,15 @@
  * limitations under the License
  */
 
-package android.content;
+package android.app.task;
 
-import android.app.task.TaskService;
+import android.content.ComponentName;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
- * Container of data passed to the {@link android.content.TaskManager} fully encapsulating the
+ * Container of data passed to the {@link android.app.task.TaskManager} fully encapsulating the
  * parameters required to schedule work against the calling application. These are constructed
  * using the {@link Task.Builder}.
  */
@@ -92,7 +92,7 @@
     }
 
     /**
-     * See {@link android.content.Task.NetworkType} for a description of this value.
+     * See {@link android.app.task.Task.NetworkType} for a description of this value.
      */
     public int getNetworkCapabilities() {
         return networkCapabilities;
@@ -139,7 +139,7 @@
     }
 
     /**
-     * See {@link android.content.Task.BackoffPolicy} for an explanation of the values this field
+     * See {@link android.app.task.Task.BackoffPolicy} for an explanation of the values this field
      * can take. This defaults to exponential.
      */
     public int getBackoffPolicy() {
@@ -255,7 +255,7 @@
 
         /**
          * Set some description of the kind of network capabilities you would like to have. This
-         * will be a parameter defined in {@link android.content.Task.NetworkType}.
+         * will be a parameter defined in {@link android.app.task.Task.NetworkType}.
          * Not calling this function means the network is not necessary.
          * Bear in mind that calling this function defines network as a strict requirement for your
          * task if the network requested is not available your task will never run. See
@@ -314,7 +314,7 @@
          * Specify that this task should be delayed by the provided amount of time.
          * Because it doesn't make sense setting this property on a periodic task, doing so will
          * throw an {@link java.lang.IllegalArgumentException} when
-         * {@link android.content.Task.Builder#build()} is called.
+         * {@link android.app.task.Task.Builder#build()} is called.
          * @param minLatencyMillis Milliseconds before which this task will not be considered for
          *                         execution.
          */
@@ -328,7 +328,7 @@
          * deadline even if other requirements are not met. Because it doesn't make sense setting
          * this property on a periodic task, doing so will throw an
          * {@link java.lang.IllegalArgumentException} when
-         * {@link android.content.Task.Builder#build()} is called.
+         * {@link android.app.task.Task.Builder#build()} is called.
          */
         public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
             mMaxExecutionDelayMillis = maxExecutionDelayMillis;
diff --git a/core/java/android/content/TaskManager.java b/core/java/android/app/task/TaskManager.java
similarity index 75%
rename from core/java/android/content/TaskManager.java
rename to core/java/android/app/task/TaskManager.java
index d28d78a..0fbe37d 100644
--- a/core/java/android/content/TaskManager.java
+++ b/core/java/android/app/task/TaskManager.java
@@ -14,14 +14,19 @@
  * limitations under the License
  */
 
-package android.content;
+package android.app.task;
 
 import java.util.List;
 
+import android.content.Context;
+
 /**
  * Class for scheduling various types of tasks with the scheduling framework on the device.
  *
- * Get an instance of this class through {@link Context#getSystemService(String)}.
+ * <p>You do not
+ * instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService
+ * Context.getSystemService(Context.TASK_SERVICE)}.
  */
 public abstract class TaskManager {
     /*
@@ -29,18 +34,20 @@
      * if the run-time for your task is too short, or perhaps the system can't resolve the
      * requisite {@link TaskService} in your package.
      */
-    static final int RESULT_INVALID_PARAMETERS = -1;
+    public static final int RESULT_INVALID_PARAMETERS = -1;
+
     /**
      * Returned from {@link #schedule(Task)} if this application has made too many requests for
      * work over too short a time.
      */
     // TODO: Determine if this is necessary.
-    static final int RESULT_OVER_QUOTA = -2;
+    public static final int RESULT_OVER_QUOTA = -2;
 
-    /*
-     * @param task The task you wish scheduled. See {@link Task#TaskBuilder} for more detail on
-     * the sorts of tasks you can schedule.
-     * @return If >0, this int corresponds to the taskId of the successfully scheduled task.
+    /**
+     * @param task The task you wish scheduled. See
+     * {@link android.app.task.Task.Builder Task.Builder} for more detail on the sorts of tasks
+     * you can schedule.
+     * @return If >0, this int returns the taskId of the successfully scheduled task.
      * Otherwise you have to compare the return value to the error codes defined in this class.
      */
     public abstract int schedule(Task task);
diff --git a/core/java/android/app/task/TaskParams.java b/core/java/android/app/task/TaskParams.java
index 0351082..dacb3480 100644
--- a/core/java/android/app/task/TaskParams.java
+++ b/core/java/android/app/task/TaskParams.java
@@ -47,7 +47,7 @@
 
     /**
      * @return The extras you passed in when constructing this task with
-     * {@link android.content.Task.Builder#setExtras(android.os.Bundle)}. This will
+     * {@link android.app.task.Task.Builder#setExtras(android.os.Bundle)}. This will
      * never be null. If you did not set any extras this will be an empty bundle.
      */
     public Bundle getExtras() {
diff --git a/core/java/android/app/task/TaskService.java b/core/java/android/app/task/TaskService.java
index ab1a565..8ce4484 100644
--- a/core/java/android/app/task/TaskService.java
+++ b/core/java/android/app/task/TaskService.java
@@ -28,7 +28,7 @@
 import com.android.internal.annotations.GuardedBy;
 
 /**
- * <p>Entry point for the callback from the {@link android.content.TaskManager}.</p>
+ * <p>Entry point for the callback from the {@link android.app.task.TaskManager}.</p>
  * <p>This is the base class that handles asynchronous requests that were previously scheduled. You
  * are responsible for overriding {@link TaskService#onStartTask(TaskParams)}, which is where
  * you will implement your task logic.</p>
@@ -215,9 +215,9 @@
      *
      * <p>This will happen if the requirements specified at schedule time are no longer met. For
      * example you may have requested WiFi with
-     * {@link android.content.Task.Builder#setRequiredNetworkCapabilities(int)}, yet while your
+     * {@link android.app.task.Task.Builder#setRequiredNetworkCapabilities(int)}, yet while your
      * task was executing the user toggled WiFi. Another example is if you had specified
-     * {@link android.content.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
+     * {@link android.app.task.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
      * idle maintenance window. You are solely responsible for the behaviour of your application
      * upon receipt of this message; your app will likely start to misbehave if you ignore it. One
      * immediate repercussion is that the system will cease holding a wakelock for you.</p>
@@ -237,7 +237,7 @@
      *     You can specify post-execution behaviour to the scheduler here with
      *     <code>needsReschedule </code>. This will apply a back-off timer to your task based on
      *     the default, or what was set with
-     *     {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The original
+     *     {@link android.app.task.Task.Builder#setBackoffCriteria(long, int)}. The original
      *     requirements are always honoured even for a backed-off task. Note that a task running in
      *     idle mode will not be backed-off. Instead what will happen is the task will be re-added
      *     to the queue and re-executed within a future idle maintenance window.
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index d3e9089..e5bf7d0 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -317,9 +317,9 @@
     public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
 
     /**
-     * Sent to providers after AppWidget state related to the provider has been restored from
-     * backup. The intent contains information about how to translate AppWidget ids from the
-     * restored data to their new equivalents.
+     * Sent to an {@link AppWidgetProvider} after AppWidget state related to that provider has
+     * been restored from backup. The intent contains information about how to translate AppWidget
+     * ids from the restored data to their new equivalents.
      *
      * <p>The intent will contain the following extras:
      *
@@ -343,7 +343,7 @@
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      *
-     * @see {@link #ACTION_APPWIDGET_HOST_RESTORED} for the corresponding host broadcast
+     * @see #ACTION_APPWIDGET_HOST_RESTORED
      */
     public static final String ACTION_APPWIDGET_RESTORED
             = "android.appwidget.action.APPWIDGET_RESTORED";
@@ -352,7 +352,7 @@
      * Sent to widget hosts after AppWidget state related to the host has been restored from
      * backup. The intent contains information about how to translate AppWidget ids from the
      * restored data to their new equivalents.  If an application maintains multiple separate
-     * widget hosts instances, it will receive this broadcast separately for each one.
+     * widget host instances, it will receive this broadcast separately for each one.
      *
      * <p>The intent will contain the following extras:
      *
@@ -380,7 +380,7 @@
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      *
-     * @see {@link #ACTION_APPWIDGET_RESTORED} for the corresponding provider broadcast
+     * @see #ACTION_APPWIDGET_RESTORED
      */
     public static final String ACTION_APPWIDGET_HOST_RESTORED
             = "android.appwidget.action.APPWIDGET_HOST_RESTORED";
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6ae006c..b0673b5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2023,6 +2023,7 @@
             PRINT_SERVICE,
             MEDIA_SESSION_SERVICE,
             BATTERY_SERVICE,
+            TASK_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -2079,6 +2080,8 @@
      * <dd> A {@link android.app.DownloadManager} for requesting HTTP downloads
      * <dt> {@link #BATTERY_SERVICE} ("batterymanager")
      * <dd> A {@link android.os.BatteryManager} for managing battery state
+     * <dt> {@link #TASK_SERVICE} ("taskmanager")
+     * <dd>  A {@link android.app.task.TaskManager} for managing scheduled tasks
      * </dl>
      *
      * <p>Note:  System services obtained via this API may be closely associated with
@@ -2134,6 +2137,8 @@
      * @see android.app.DownloadManager
      * @see #BATTERY_SERVICE
      * @see android.os.BatteryManager
+     * @see #TASK_SERVICE
+     * @see android.app.task.TaskManager
      */
     public abstract Object getSystemService(@ServiceName @NonNull String name);
 
@@ -2728,6 +2733,15 @@
     public static final String USAGE_STATS_SERVICE = "usagestats";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a {@link
+     * android.app.task.TaskManager} instance for managing occasional
+     * background tasks.
+     * @see #getSystemService
+     * @see android.app.task.TaskManager
+     */
+    public static final String TASK_SERVICE = "task";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index c08424a..cea68d2 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -296,8 +296,8 @@
      * valid anti-banding modes that the application may request
      * for this camera device; they must include AUTO.</p>
      */
-    public static final Key<byte[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES =
-            new Key<byte[]>("android.control.aeAvailableAntibandingModes", byte[].class);
+    public static final Key<int[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES =
+            new Key<int[]>("android.control.aeAvailableAntibandingModes", int[].class);
 
     /**
      * <p>The set of auto-exposure modes that are supported by this
@@ -315,15 +315,15 @@
      *
      * @see CaptureRequest#CONTROL_AE_MODE
      */
-    public static final Key<byte[]> CONTROL_AE_AVAILABLE_MODES =
-            new Key<byte[]>("android.control.aeAvailableModes", byte[].class);
+    public static final Key<int[]> CONTROL_AE_AVAILABLE_MODES =
+            new Key<int[]>("android.control.aeAvailableModes", int[].class);
 
     /**
      * <p>List of frame rate ranges supported by the
      * AE algorithm/hardware</p>
      */
-    public static final Key<int[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES =
-            new Key<int[]>("android.control.aeAvailableTargetFpsRanges", int[].class);
+    public static final Key<android.util.Range<Integer>[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES =
+            new Key<android.util.Range<Integer>[]>("android.control.aeAvailableTargetFpsRanges", new TypeReference<android.util.Range<Integer>[]>() {{ }});
 
     /**
      * <p>Maximum and minimum exposure compensation
@@ -332,8 +332,8 @@
      *
      * @see CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP
      */
-    public static final Key<int[]> CONTROL_AE_COMPENSATION_RANGE =
-            new Key<int[]>("android.control.aeCompensationRange", int[].class);
+    public static final Key<android.util.Range<Integer>> CONTROL_AE_COMPENSATION_RANGE =
+            new Key<android.util.Range<Integer>>("android.control.aeCompensationRange", new TypeReference<android.util.Range<Integer>>() {{ }});
 
     /**
      * <p>Smallest step by which exposure compensation
@@ -355,8 +355,8 @@
      * @see CaptureRequest#CONTROL_AF_MODE
      * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
      */
-    public static final Key<byte[]> CONTROL_AF_AVAILABLE_MODES =
-            new Key<byte[]>("android.control.afAvailableModes", byte[].class);
+    public static final Key<int[]> CONTROL_AF_AVAILABLE_MODES =
+            new Key<int[]>("android.control.afAvailableModes", int[].class);
 
     /**
      * <p>List containing the subset of color effects
@@ -374,8 +374,8 @@
      * @see CaptureRequest#CONTROL_EFFECT_MODE
      * @see CaptureRequest#CONTROL_MODE
      */
-    public static final Key<byte[]> CONTROL_AVAILABLE_EFFECTS =
-            new Key<byte[]>("android.control.availableEffects", byte[].class);
+    public static final Key<int[]> CONTROL_AVAILABLE_EFFECTS =
+            new Key<int[]>("android.control.availableEffects", int[].class);
 
     /**
      * <p>List containing a subset of scene modes
@@ -388,15 +388,15 @@
      *
      * @see CaptureRequest#CONTROL_SCENE_MODE
      */
-    public static final Key<byte[]> CONTROL_AVAILABLE_SCENE_MODES =
-            new Key<byte[]>("android.control.availableSceneModes", byte[].class);
+    public static final Key<int[]> CONTROL_AVAILABLE_SCENE_MODES =
+            new Key<int[]>("android.control.availableSceneModes", int[].class);
 
     /**
      * <p>List of video stabilization modes that can
      * be supported</p>
      */
-    public static final Key<byte[]> CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES =
-            new Key<byte[]>("android.control.availableVideoStabilizationModes", byte[].class);
+    public static final Key<int[]> CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES =
+            new Key<int[]>("android.control.availableVideoStabilizationModes", int[].class);
 
     /**
      * <p>The set of auto-white-balance modes ({@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode})
@@ -414,8 +414,8 @@
      * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
      * @see CaptureRequest#CONTROL_AWB_MODE
      */
-    public static final Key<byte[]> CONTROL_AWB_AVAILABLE_MODES =
-            new Key<byte[]>("android.control.awbAvailableModes", byte[].class);
+    public static final Key<int[]> CONTROL_AWB_AVAILABLE_MODES =
+            new Key<int[]>("android.control.awbAvailableModes", int[].class);
 
     /**
      * <p>List of the maximum number of regions that can be used for metering in
@@ -427,19 +427,53 @@
      * @see CaptureRequest#CONTROL_AE_REGIONS
      * @see CaptureRequest#CONTROL_AF_REGIONS
      * @see CaptureRequest#CONTROL_AWB_REGIONS
+     * @hide
      */
     public static final Key<int[]> CONTROL_MAX_REGIONS =
             new Key<int[]>("android.control.maxRegions", int[].class);
 
     /**
+     * <p>List of the maximum number of regions that can be used for metering in
+     * auto-exposure (AE);
+     * this corresponds to the the maximum number of elements in
+     * {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_REGIONS
+     */
+    public static final Key<Integer> CONTROL_MAX_REGIONS_AE =
+            new Key<Integer>("android.control.maxRegionsAe", int.class);
+
+    /**
+     * <p>List of the maximum number of regions that can be used for metering in
+     * auto-white balance (AWB);
+     * this corresponds to the the maximum number of elements in
+     * {@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}.</p>
+     *
+     * @see CaptureRequest#CONTROL_AWB_REGIONS
+     */
+    public static final Key<Integer> CONTROL_MAX_REGIONS_AWB =
+            new Key<Integer>("android.control.maxRegionsAwb", int.class);
+
+    /**
+     * <p>List of the maximum number of regions that can be used for metering in
+     * auto-focus (AF);
+     * this corresponds to the the maximum number of elements in
+     * {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}.</p>
+     *
+     * @see CaptureRequest#CONTROL_AF_REGIONS
+     */
+    public static final Key<Integer> CONTROL_MAX_REGIONS_AF =
+            new Key<Integer>("android.control.maxRegionsAf", int.class);
+
+    /**
      * <p>The set of edge enhancement modes supported by this camera device.</p>
      * <p>This tag lists the valid modes for {@link CaptureRequest#EDGE_MODE android.edge.mode}.</p>
      * <p>Full-capability camera devices must always support OFF and FAST.</p>
      *
      * @see CaptureRequest#EDGE_MODE
      */
-    public static final Key<byte[]> EDGE_AVAILABLE_EDGE_MODES =
-            new Key<byte[]>("android.edge.availableEdgeModes", byte[].class);
+    public static final Key<int[]> EDGE_AVAILABLE_EDGE_MODES =
+            new Key<int[]>("android.edge.availableEdgeModes", int[].class);
 
     /**
      * <p>Whether this camera device has a
@@ -458,8 +492,8 @@
      *
      * @see CaptureRequest#HOT_PIXEL_MODE
      */
-    public static final Key<byte[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES =
-            new Key<byte[]>("android.hotPixel.availableHotPixelModes", byte[].class);
+    public static final Key<int[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES =
+            new Key<int[]>("android.hotPixel.availableHotPixelModes", int[].class);
 
     /**
      * <p>Supported resolutions for the JPEG thumbnail</p>
@@ -526,8 +560,8 @@
      *
      * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
      */
-    public static final Key<byte[]> LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION =
-            new Key<byte[]>("android.lens.info.availableOpticalStabilization", byte[].class);
+    public static final Key<int[]> LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION =
+            new Key<int[]>("android.lens.info.availableOpticalStabilization", int[].class);
 
     /**
      * <p>Optional. Hyperfocal distance for this lens.</p>
@@ -553,6 +587,7 @@
      * <p>Dimensions of lens shading map.</p>
      * <p>The map should be on the order of 30-40 rows and columns, and
      * must be smaller than 64x64.</p>
+     * @hide
      */
     public static final Key<android.util.Size> LENS_INFO_SHADING_MAP_SIZE =
             new Key<android.util.Size>("android.lens.info.shadingMapSize", android.util.Size.class);
@@ -591,8 +626,8 @@
      *
      * @see CaptureRequest#NOISE_REDUCTION_MODE
      */
-    public static final Key<byte[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES =
-            new Key<byte[]>("android.noiseReduction.availableNoiseReductionModes", byte[].class);
+    public static final Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES =
+            new Key<int[]>("android.noiseReduction.availableNoiseReductionModes", int[].class);
 
     /**
      * <p>If set to 1, the HAL will always split result
@@ -621,7 +656,7 @@
      * number is 3, and max JPEG stream number is 2, then this tuple should be <code>(1, 3, 2)</code>.</p>
      * <p>This lists the upper bound of the number of output streams supported by
      * the camera device. Using more streams simultaneously may require more hardware and
-     * CPU resources that will consume more power. The image format for a output stream can
+     * CPU resources that will consume more power. The image format for an output stream can
      * be any supported format provided by android.scaler.availableStreamConfigurations.
      * The formats defined in android.scaler.availableStreamConfigurations can be catergorized
      * into the 3 stream types as below:</p>
@@ -632,11 +667,79 @@
      * <li>Processed (but not-stalling): any non-RAW format without a stall duration.
      * Typically ImageFormat#YUV_420_888, ImageFormat#NV21, ImageFormat#YV12.</li>
      * </ul>
+     * @hide
      */
     public static final Key<int[]> REQUEST_MAX_NUM_OUTPUT_STREAMS =
             new Key<int[]>("android.request.maxNumOutputStreams", int[].class);
 
     /**
+     * <p>The maximum numbers of different types of output streams
+     * that can be configured and used simultaneously by a camera device
+     * for any <code>RAW</code> formats.</p>
+     * <p>This value contains the max number of output simultaneous
+     * streams from the raw sensor.</p>
+     * <p>This lists the upper bound of the number of output streams supported by
+     * the camera device. Using more streams simultaneously may require more hardware and
+     * CPU resources that will consume more power. The image format for this kind of an output stream can
+     * be any <code>RAW</code> and supported format provided by {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}.</p>
+     * <p>In particular, a <code>RAW</code> format is typically one of:</p>
+     * <ul>
+     * <li>ImageFormat#RAW_SENSOR</li>
+     * <li>Opaque <code>RAW</code></li>
+     * </ul>
+     *
+     * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
+     */
+    public static final Key<Integer> REQUEST_MAX_NUM_OUTPUT_RAW =
+            new Key<Integer>("android.request.maxNumOutputRaw", int.class);
+
+    /**
+     * <p>The maximum numbers of different types of output streams
+     * that can be configured and used simultaneously by a camera device
+     * for any processed (but not-stalling) formats.</p>
+     * <p>This value contains the max number of output simultaneous
+     * streams for any processed (but not-stalling) formats.</p>
+     * <p>This lists the upper bound of the number of output streams supported by
+     * the camera device. Using more streams simultaneously may require more hardware and
+     * CPU resources that will consume more power. The image format for this kind of an output stream can
+     * be any non-<code>RAW</code> and supported format provided by {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}.</p>
+     * <p>Processed (but not-stalling) is defined as any non-RAW format without a stall duration.
+     * Typically:</p>
+     * <ul>
+     * <li>ImageFormat#YUV_420_888</li>
+     * <li>ImageFormat#NV21</li>
+     * <li>ImageFormat#YV12</li>
+     * <li>Implementation-defined formats, i.e. StreamConfiguration#isOutputSupportedFor(Class)</li>
+     * </ul>
+     * <p>For full guarantees, query StreamConfigurationMap#getOutputStallDuration with
+     * a processed format -- it will return 0 for a non-stalling stream.</p>
+     *
+     * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
+     */
+    public static final Key<Integer> REQUEST_MAX_NUM_OUTPUT_PROC =
+            new Key<Integer>("android.request.maxNumOutputProc", int.class);
+
+    /**
+     * <p>The maximum numbers of different types of output streams
+     * that can be configured and used simultaneously by a camera device
+     * for any processed (and stalling) formats.</p>
+     * <p>This value contains the max number of output simultaneous
+     * streams for any processed (but not-stalling) formats.</p>
+     * <p>This lists the upper bound of the number of output streams supported by
+     * the camera device. Using more streams simultaneously may require more hardware and
+     * CPU resources that will consume more power. The image format for this kind of an output stream can
+     * be any non-<code>RAW</code> and supported format provided by {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}.</p>
+     * <p>A processed and stalling format is defined as any non-RAW format with a stallDurations &gt; 0.
+     * Typically only the <code>JPEG</code> format (ImageFormat#JPEG)</p>
+     * <p>For full guarantees, query StreamConfigurationMap#getOutputStallDuration with
+     * a processed format -- it will return a non-0 value for a stalling stream.</p>
+     *
+     * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
+     */
+    public static final Key<Integer> REQUEST_MAX_NUM_OUTPUT_PROC_STALLING =
+            new Key<Integer>("android.request.maxNumOutputProcStalling", int.class);
+
+    /**
      * <p>The maximum numbers of any type of input streams
      * that can be configured and used simultaneously by a camera device.</p>
      * <p>When set to 0, it means no input stream is supported.</p>
@@ -707,7 +810,6 @@
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} <code>==</code> FULL devices:</p>
      * <ul>
      * <li>MANUAL_SENSOR</li>
-     * <li>ZSL</li>
      * </ul>
      * <p>Other capabilities may be available on either FULL or LIMITED
      * devices, but the app. should query this field to be sure.</p>
@@ -716,7 +818,7 @@
      * @see #REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
      * @see #REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR
-     * @see #REQUEST_AVAILABLE_CAPABILITIES_GCAM
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING
      * @see #REQUEST_AVAILABLE_CAPABILITIES_ZSL
      * @see #REQUEST_AVAILABLE_CAPABILITIES_DNG
      */
@@ -750,7 +852,7 @@
      * value.</p>
      * <p>The following keys may return <code>null</code> unless they are enabled:</p>
      * <ul>
-     * <li>{@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} (non-null iff {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} == ON)</li>
+     * <li>android.statistics.lensShadingMap (non-null iff {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} == ON)</li>
      * </ul>
      * <p>(Those sometimes-null keys should nevertheless be listed here
      * if they are available.)</p>
@@ -761,7 +863,6 @@
      * <p>TODO: This should be used by #getAvailableCaptureResultKeys.</p>
      *
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
-     * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
      * @hide
      */
@@ -1229,8 +1330,8 @@
     /**
      * <p>Range of valid sensitivities</p>
      */
-    public static final Key<int[]> SENSOR_INFO_SENSITIVITY_RANGE =
-            new Key<int[]>("android.sensor.info.sensitivityRange", int[].class);
+    public static final Key<android.util.Range<Integer>> SENSOR_INFO_SENSITIVITY_RANGE =
+            new Key<android.util.Range<Integer>>("android.sensor.info.sensitivityRange", new TypeReference<android.util.Range<Integer>>() {{ }});
 
     /**
      * <p>Arrangement of color filters on sensor;
@@ -1251,8 +1352,8 @@
      *
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      */
-    public static final Key<long[]> SENSOR_INFO_EXPOSURE_TIME_RANGE =
-            new Key<long[]>("android.sensor.info.exposureTimeRange", long[].class);
+    public static final Key<android.util.Range<Long>> SENSOR_INFO_EXPOSURE_TIME_RANGE =
+            new Key<android.util.Range<Long>>("android.sensor.info.exposureTimeRange", new TypeReference<android.util.Range<Long>>() {{ }});
 
     /**
      * <p>Maximum possible frame duration (minimum frame
@@ -1276,8 +1377,8 @@
      * array</p>
      * <p>Needed for FOV calculation for old API</p>
      */
-    public static final Key<float[]> SENSOR_INFO_PHYSICAL_SIZE =
-            new Key<float[]>("android.sensor.info.physicalSize", float[].class);
+    public static final Key<android.util.SizeF> SENSOR_INFO_PHYSICAL_SIZE =
+            new Key<android.util.SizeF>("android.sensor.info.physicalSize", android.util.SizeF.class);
 
     /**
      * <p>Dimensions of full pixel array, possibly
@@ -1383,8 +1484,8 @@
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
      */
-    public static final Key<Rational[]> SENSOR_CALIBRATION_TRANSFORM1 =
-            new Key<Rational[]>("android.sensor.calibrationTransform1", Rational[].class);
+    public static final Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_CALIBRATION_TRANSFORM1 =
+            new Key<android.hardware.camera2.params.ColorSpaceTransform>("android.sensor.calibrationTransform1", android.hardware.camera2.params.ColorSpaceTransform.class);
 
     /**
      * <p>A per-device calibration transform matrix that maps from the
@@ -1404,8 +1505,8 @@
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
      */
-    public static final Key<Rational[]> SENSOR_CALIBRATION_TRANSFORM2 =
-            new Key<Rational[]>("android.sensor.calibrationTransform2", Rational[].class);
+    public static final Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_CALIBRATION_TRANSFORM2 =
+            new Key<android.hardware.camera2.params.ColorSpaceTransform>("android.sensor.calibrationTransform2", android.hardware.camera2.params.ColorSpaceTransform.class);
 
     /**
      * <p>A matrix that transforms color values from CIE XYZ color space to
@@ -1426,8 +1527,8 @@
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
      */
-    public static final Key<Rational[]> SENSOR_COLOR_TRANSFORM1 =
-            new Key<Rational[]>("android.sensor.colorTransform1", Rational[].class);
+    public static final Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_COLOR_TRANSFORM1 =
+            new Key<android.hardware.camera2.params.ColorSpaceTransform>("android.sensor.colorTransform1", android.hardware.camera2.params.ColorSpaceTransform.class);
 
     /**
      * <p>A matrix that transforms color values from CIE XYZ color space to
@@ -1450,8 +1551,8 @@
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
      */
-    public static final Key<Rational[]> SENSOR_COLOR_TRANSFORM2 =
-            new Key<Rational[]>("android.sensor.colorTransform2", Rational[].class);
+    public static final Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_COLOR_TRANSFORM2 =
+            new Key<android.hardware.camera2.params.ColorSpaceTransform>("android.sensor.colorTransform2", android.hardware.camera2.params.ColorSpaceTransform.class);
 
     /**
      * <p>A matrix that transforms white balanced camera colors from the reference
@@ -1470,8 +1571,8 @@
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
      */
-    public static final Key<Rational[]> SENSOR_FORWARD_MATRIX1 =
-            new Key<Rational[]>("android.sensor.forwardMatrix1", Rational[].class);
+    public static final Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_FORWARD_MATRIX1 =
+            new Key<android.hardware.camera2.params.ColorSpaceTransform>("android.sensor.forwardMatrix1", android.hardware.camera2.params.ColorSpaceTransform.class);
 
     /**
      * <p>A matrix that transforms white balanced camera colors from the reference
@@ -1492,8 +1593,8 @@
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
      */
-    public static final Key<Rational[]> SENSOR_FORWARD_MATRIX2 =
-            new Key<Rational[]>("android.sensor.forwardMatrix2", Rational[].class);
+    public static final Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_FORWARD_MATRIX2 =
+            new Key<android.hardware.camera2.params.ColorSpaceTransform>("android.sensor.forwardMatrix2", android.hardware.camera2.params.ColorSpaceTransform.class);
 
     /**
      * <p>A fixed black level offset for each of the color filter arrangement
@@ -1560,8 +1661,8 @@
      * android.statistics.faceIds and
      * android.statistics.faceLandmarks outputs.</p>
      */
-    public static final Key<byte[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES =
-            new Key<byte[]>("android.statistics.info.availableFaceDetectModes", byte[].class);
+    public static final Key<int[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES =
+            new Key<int[]>("android.statistics.info.availableFaceDetectModes", int[].class);
 
     /**
      * <p>Maximum number of simultaneously detectable
@@ -1584,19 +1685,16 @@
 
     /**
      * <p>Maximum number of supported points in the
-     * tonemap curve that can be used for {@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed}, or
-     * {@link CaptureRequest#TONEMAP_CURVE_GREEN android.tonemap.curveGreen}, or {@link CaptureRequest#TONEMAP_CURVE_BLUE android.tonemap.curveBlue}.</p>
+     * tonemap curve that can be used for {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}.</p>
      * <p>If the actual number of points provided by the application (in
-     * android.tonemap.curve*)  is less than max, the camera device will
+     * {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}*)  is less than max, the camera device will
      * resample the curve to its internal representation, using linear
      * interpolation.</p>
      * <p>The output curves in the result metadata may have a different number
      * of points than the input curves, and will represent the actual
      * hardware curves used as closely as possible when linearly interpolated.</p>
      *
-     * @see CaptureRequest#TONEMAP_CURVE_BLUE
-     * @see CaptureRequest#TONEMAP_CURVE_GREEN
-     * @see CaptureRequest#TONEMAP_CURVE_RED
+     * @see CaptureRequest#TONEMAP_CURVE
      */
     public static final Key<Integer> TONEMAP_MAX_CURVE_POINTS =
             new Key<Integer>("android.tonemap.maxCurvePoints", int.class);
@@ -1609,8 +1707,8 @@
      *
      * @see CaptureRequest#TONEMAP_MODE
      */
-    public static final Key<byte[]> TONEMAP_AVAILABLE_TONE_MAP_MODES =
-            new Key<byte[]>("android.tonemap.availableToneMapModes", byte[].class);
+    public static final Key<int[]> TONEMAP_AVAILABLE_TONE_MAP_MODES =
+            new Key<int[]>("android.tonemap.availableToneMapModes", int[].class);
 
     /**
      * <p>A list of camera LEDs that are available on this system.</p>
@@ -1626,15 +1724,16 @@
      * <p>A FULL device has the most support possible and will enable the
      * widest range of use cases such as:</p>
      * <ul>
-     * <li>30 FPS at maximum resolution (== sensor resolution)</li>
-     * <li>Per frame control</li>
-     * <li>Manual sensor control</li>
-     * <li>Zero Shutter Lag (ZSL)</li>
+     * <li>30fps at maximum resolution (== sensor resolution) is preferred, more than 20fps is required.</li>
+     * <li>Per frame control ({@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} <code>==</code> PER_FRAME_CONTROL)</li>
+     * <li>Manual sensor control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_SENSOR)</li>
+     * <li>Manual post-processing control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_POST_PROCESSING)</li>
      * </ul>
      * <p>A LIMITED device may have some or none of the above characteristics.
      * To find out more refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
      *
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @see CameraCharacteristics#SYNC_MAX_LATENCY
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
      */
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 03b342c..83db056 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -220,6 +220,7 @@
     private CameraDevice openCameraDeviceUserAsync(String cameraId,
             CameraDevice.StateListener listener, Handler handler)
             throws CameraAccessException {
+        CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
         CameraDevice device = null;
         try {
 
@@ -231,7 +232,8 @@
                         new android.hardware.camera2.impl.CameraDevice(
                                 cameraId,
                                 listener,
-                                handler);
+                                handler,
+                                characteristics);
 
                 BinderHolder holder = new BinderHolder();
 
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 4cde601..b3e165e 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -236,9 +236,17 @@
 
     /**
      * <p>The camera device can be manually controlled (3A algorithms such
-     * as auto exposure, and auto focus can be
-     * bypassed), this includes but is not limited to:</p>
+     * as auto exposure, and auto focus can be bypassed).
+     * The camera device supports basic manual control of the sensor image
+     * acquisition related stages. This means the following controls are
+     * guaranteed to be supported:</p>
      * <ul>
+     * <li>Manual frame duration control<ul>
+     * <li>{@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}</li>
+     * <li>{@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}</li>
+     * </ul>
+     * </li>
      * <li>Manual exposure control<ul>
      * <li>{@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</li>
      * <li>{@link CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE android.sensor.info.exposureTimeRange}</li>
@@ -265,10 +273,15 @@
      * <p>If any of the above 3A algorithms are enabled, then the camera
      * device will accurately report the values applied by 3A in the
      * result.</p>
+     * <p>A given camera device may also support additional manual sensor controls,
+     * but this capability only covers the above list of controls.</p>
      *
      * @see CaptureRequest#BLACK_LEVEL_LOCK
+     * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
      * @see CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE
+     * @see CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION
      * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE
      * @see CaptureRequest#SENSOR_SENSITIVITY
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
@@ -276,12 +289,12 @@
     public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 2;
 
     /**
-     * <p>TODO: This should be @hide</p>
+     * <p>The camera device post-processing stages can be manually controlled.
+     * The camera device supports basic manual control of the image post-processing
+     * stages. This means the following controls are guaranteed to be supported:</p>
      * <ul>
      * <li>Manual tonemap control<ul>
-     * <li>{@link CaptureRequest#TONEMAP_CURVE_BLUE android.tonemap.curveBlue}</li>
-     * <li>{@link CaptureRequest#TONEMAP_CURVE_GREEN android.tonemap.curveGreen}</li>
-     * <li>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed}</li>
+     * <li>{@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}</li>
      * <li>{@link CaptureRequest#TONEMAP_MODE android.tonemap.mode}</li>
      * <li>{@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</li>
      * </ul>
@@ -292,8 +305,8 @@
      * </ul>
      * </li>
      * <li>Lens shading map information<ul>
-     * <li>{@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap}</li>
-     * <li>{@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize}</li>
+     * <li>android.statistics.lensShadingMap</li>
+     * <li>android.lens.info.shadingMapSize</li>
      * </ul>
      * </li>
      * </ul>
@@ -301,19 +314,17 @@
      * will accurately report the values applied by AWB in the result.</p>
      * <p>The camera device will also support everything in MANUAL_SENSOR
      * except manual lens control and manual flash control.</p>
+     * <p>A given camera device may also support additional post-processing
+     * controls, but this capability only covers the above list of controls.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_GAINS
      * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
-     * @see CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE
-     * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
-     * @see CaptureRequest#TONEMAP_CURVE_BLUE
-     * @see CaptureRequest#TONEMAP_CURVE_GREEN
-     * @see CaptureRequest#TONEMAP_CURVE_RED
+     * @see CaptureRequest#TONEMAP_CURVE
      * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS
      * @see CaptureRequest#TONEMAP_MODE
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      */
-    public static final int REQUEST_AVAILABLE_CAPABILITIES_GCAM = 3;
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 3;
 
     /**
      * <p>The camera device supports the Zero Shutter Lag use case.</p>
@@ -1548,17 +1559,14 @@
 
     /**
      * <p>Use the tone mapping curve specified in
-     * the android.tonemap.curve* entries.</p>
+     * the {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}* entries.</p>
      * <p>All color enhancement and tonemapping must be disabled, except
      * for applying the tonemapping curve specified by
-     * {@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed}, {@link CaptureRequest#TONEMAP_CURVE_BLUE android.tonemap.curveBlue}, or
-     * {@link CaptureRequest#TONEMAP_CURVE_GREEN android.tonemap.curveGreen}.</p>
+     * {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}.</p>
      * <p>Must not slow down frame rate relative to raw
      * sensor output.</p>
      *
-     * @see CaptureRequest#TONEMAP_CURVE_BLUE
-     * @see CaptureRequest#TONEMAP_CURVE_GREEN
-     * @see CaptureRequest#TONEMAP_CURVE_RED
+     * @see CaptureRequest#TONEMAP_CURVE
      * @see CaptureRequest#TONEMAP_MODE
      */
     public static final int TONEMAP_MODE_CONTRAST_CURVE = 0;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index a4aa296..6aa24e6 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -537,30 +537,24 @@
      *
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      */
-    public static final Key<Rational[]> COLOR_CORRECTION_TRANSFORM =
-            new Key<Rational[]>("android.colorCorrection.transform", Rational[].class);
+    public static final Key<android.hardware.camera2.params.ColorSpaceTransform> COLOR_CORRECTION_TRANSFORM =
+            new Key<android.hardware.camera2.params.ColorSpaceTransform>("android.colorCorrection.transform", android.hardware.camera2.params.ColorSpaceTransform.class);
 
     /**
      * <p>Gains applying to Bayer raw color channels for
      * white-balance.</p>
-     * <p>The 4-channel white-balance gains are defined in
-     * the order of <code>[R G_even G_odd B]</code>, where <code>G_even</code> is the gain
-     * for green pixels on even rows of the output, and <code>G_odd</code>
-     * is the gain for green pixels on the odd rows. if a HAL
-     * does not support a separate gain for even/odd green channels,
-     * it should use the <code>G_even</code> value, and write <code>G_odd</code> equal to
-     * <code>G_even</code> in the output result metadata.</p>
-     * <p>This array is either set by the camera device when the request
-     * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
-     * directly by the application in the request when the
-     * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is TRANSFORM_MATRIX.</p>
-     * <p>The output should be the gains actually applied by the camera device to
-     * the current frame.</p>
+     * <p>These per-channel gains are either set by the camera device
+     * when the request {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not
+     * TRANSFORM_MATRIX, or directly by the application in the
+     * request when the {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is
+     * TRANSFORM_MATRIX.</p>
+     * <p>The gains in the result metadata are the gains actually
+     * applied by the camera device to the current frame.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      */
-    public static final Key<float[]> COLOR_CORRECTION_GAINS =
-            new Key<float[]>("android.colorCorrection.gains", float[].class);
+    public static final Key<android.hardware.camera2.params.RggbChannelVector> COLOR_CORRECTION_GAINS =
+            new Key<android.hardware.camera2.params.RggbChannelVector>("android.colorCorrection.gains", android.hardware.camera2.params.RggbChannelVector.class);
 
     /**
      * <p>The desired setting for the camera device's auto-exposure
@@ -693,9 +687,6 @@
     /**
      * <p>List of areas to use for
      * metering.</p>
-     * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
-     * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -711,8 +702,8 @@
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
-    public static final Key<int[]> CONTROL_AE_REGIONS =
-            new Key<int[]>("android.control.aeRegions", int[].class);
+    public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AE_REGIONS =
+            new Key<android.hardware.camera2.params.MeteringRectangle[]>("android.control.aeRegions", android.hardware.camera2.params.MeteringRectangle[].class);
 
     /**
      * <p>Range over which fps can be adjusted to
@@ -722,8 +713,8 @@
      *
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      */
-    public static final Key<int[]> CONTROL_AE_TARGET_FPS_RANGE =
-            new Key<int[]>("android.control.aeTargetFpsRange", int[].class);
+    public static final Key<android.util.Range<Integer>> CONTROL_AE_TARGET_FPS_RANGE =
+            new Key<android.util.Range<Integer>>("android.control.aeTargetFpsRange", new TypeReference<android.util.Range<Integer>>() {{ }});
 
     /**
      * <p>Whether the camera device will trigger a precapture
@@ -768,26 +759,23 @@
     /**
      * <p>List of areas to use for focus
      * estimation.</p>
-     * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
-     * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
      * bottom-right pixel in the active pixel array. The weight
      * should be nonnegative.</p>
-     * <p>If all regions have 0 weight, then no specific focus area
-     * needs to be used by the camera device. If the focusing region is
-     * outside the the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture
-     * result metadata, the camera device will ignore the sections outside
-     * the region and output the used sections in the result metadata.</p>
+     * <p>If all regions have 0 weight, then no specific metering area
+     * needs to be used by the camera device. If the metering region is
+     * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
+     * the camera device will ignore the sections outside the region and output the
+     * used sections in the result metadata.</p>
      *
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
-    public static final Key<int[]> CONTROL_AF_REGIONS =
-            new Key<int[]>("android.control.afRegions", int[].class);
+    public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS =
+            new Key<android.hardware.camera2.params.MeteringRectangle[]>("android.control.afRegions", android.hardware.camera2.params.MeteringRectangle[].class);
 
     /**
      * <p>Whether the camera device will trigger autofocus for this request.</p>
@@ -854,27 +842,23 @@
     /**
      * <p>List of areas to use for illuminant
      * estimation.</p>
-     * <p>Only used in AUTO mode.</p>
-     * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
-     * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
      * bottom-right pixel in the active pixel array. The weight
      * should be nonnegative.</p>
-     * <p>If all regions have 0 weight, then no specific auto-white balance (AWB) area
-     * needs to be used by the camera device. If the AWB region is
-     * outside the the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
+     * <p>If all regions have 0 weight, then no specific metering area
+     * needs to be used by the camera device. If the metering region is
+     * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
      * the camera device will ignore the sections outside the region and output the
      * used sections in the result metadata.</p>
      *
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
-    public static final Key<int[]> CONTROL_AWB_REGIONS =
-            new Key<int[]>("android.control.awbRegions", int[].class);
+    public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS =
+            new Key<android.hardware.camera2.params.MeteringRectangle[]>("android.control.awbRegions", android.hardware.camera2.params.MeteringRectangle[].class);
 
     /**
      * <p>Information to the camera device 3A (auto-exposure,
@@ -1068,8 +1052,15 @@
             new Key<Integer>("android.hotPixel.mode", int.class);
 
     /**
+     * <p>A location object to use when generating image GPS metadata.</p>
+     */
+    public static final Key<android.location.Location> JPEG_GPS_LOCATION =
+            new Key<android.location.Location>("android.jpeg.gpsLocation", android.location.Location.class);
+
+    /**
      * <p>GPS coordinates to include in output JPEG
      * EXIF</p>
+     * @hide
      */
     public static final Key<double[]> JPEG_GPS_COORDINATES =
             new Key<double[]>("android.jpeg.gpsCoordinates", double[].class);
@@ -1077,6 +1068,7 @@
     /**
      * <p>32 characters describing GPS algorithm to
      * include in EXIF</p>
+     * @hide
      */
     public static final Key<String> JPEG_GPS_PROCESSING_METHOD =
             new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
@@ -1084,6 +1076,7 @@
     /**
      * <p>Time GPS fix was made to include in
      * EXIF</p>
+     * @hide
      */
     public static final Key<Long> JPEG_GPS_TIMESTAMP =
             new Key<Long>("android.jpeg.gpsTimestamp", long.class);
@@ -1116,6 +1109,12 @@
      * but the captured JPEG will still be a valid image.</p>
      * <p>When a jpeg image capture is issued, the thumbnail size selected should have
      * the same aspect ratio as the jpeg image.</p>
+     * <p>If the thumbnail image aspect ratio differs from the JPEG primary image aspect
+     * ratio, the camera device creates the thumbnail by cropping it from the primary image.
+     * For example, if the primary image has 4:3 aspect ratio, the thumbnail image has
+     * 16:9 aspect ratio, the primary image will be cropped vertically (letterbox) to
+     * generate the thumbnail image. The thumbnail image will always have a smaller Field
+     * Of View (FOV) than the primary image when aspect ratios differ.</p>
      */
     public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
             new Key<android.util.Size>("android.jpeg.thumbnailSize", android.util.Size.class);
@@ -1432,8 +1431,8 @@
      * <p>When set to OFF mode, no lens shading correction will be applied by the
      * camera device, and an identity lens shading map data will be provided
      * if <code>{@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} == ON</code>. For example, for lens
-     * shading map with size specified as <code>{@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize} = [ 4, 3 ]</code>,
-     * the output {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} for this case will be an identity map
+     * shading map with size specified as <code>android.lens.info.shadingMapSize = [ 4, 3 ]</code>,
+     * the output android.statistics.lensShadingMap for this case will be an identity map
      * shown below:</p>
      * <pre><code>[ 1.0, 1.0, 1.0, 1.0,  1.0, 1.0, 1.0, 1.0,
      * 1.0, 1.0, 1.0, 1.0,  1.0, 1.0, 1.0, 1.0,
@@ -1445,8 +1444,8 @@
      * <p>When set to other modes, lens shading correction will be applied by the
      * camera device. Applications can request lens shading map data by setting
      * {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} to ON, and then the camera device will provide
-     * lens shading map data in {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap}, with size specified
-     * by {@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize}; the returned shading map data will be the one
+     * lens shading map data in android.statistics.lensShadingMap, with size specified
+     * by android.lens.info.shadingMapSize; the returned shading map data will be the one
      * applied by the camera device for this capture request.</p>
      * <p>The shading map data may depend on the AE and AWB statistics, therefore the reliability
      * of the map data may be affected by the AE and AWB algorithms. When AE and AWB are in
@@ -1456,8 +1455,6 @@
      *
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AWB_MODE
-     * @see CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE
-     * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
      * @see #SHADING_MODE_OFF
      * @see #SHADING_MODE_FAST
@@ -1498,10 +1495,8 @@
      * <p>Whether the camera device will output the lens
      * shading map in output result metadata.</p>
      * <p>When set to ON,
-     * {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} must be provided in
+     * android.statistics.lensShadingMap must be provided in
      * the output result metadata.</p>
-     *
-     * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
      */
@@ -1512,10 +1507,10 @@
      * <p>Tonemapping / contrast / gamma curve for the blue
      * channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
      * CONTRAST_CURVE.</p>
-     * <p>See {@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} for more details.</p>
+     * <p>See android.tonemap.curveRed for more details.</p>
      *
-     * @see CaptureRequest#TONEMAP_CURVE_RED
      * @see CaptureRequest#TONEMAP_MODE
+     * @hide
      */
     public static final Key<float[]> TONEMAP_CURVE_BLUE =
             new Key<float[]>("android.tonemap.curveBlue", float[].class);
@@ -1524,10 +1519,10 @@
      * <p>Tonemapping / contrast / gamma curve for the green
      * channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
      * CONTRAST_CURVE.</p>
-     * <p>See {@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} for more details.</p>
+     * <p>See android.tonemap.curveRed for more details.</p>
      *
-     * @see CaptureRequest#TONEMAP_CURVE_RED
      * @see CaptureRequest#TONEMAP_MODE
+     * @hide
      */
     public static final Key<float[]> TONEMAP_CURVE_GREEN =
             new Key<float[]>("android.tonemap.curveGreen", float[].class);
@@ -1537,7 +1532,7 @@
      * channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
      * CONTRAST_CURVE.</p>
      * <p>Each channel's curve is defined by an array of control points:</p>
-     * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} =
+     * <pre><code>android.tonemap.curveRed =
      * [ P0in, P0out, P1in, P1out, P2in, P2out, P3in, P3out, ..., PNin, PNout ]
      * 2 &lt;= N &lt;= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
      * <p>These are sorted in order of increasing <code>Pin</code>; it is always
@@ -1553,15 +1548,15 @@
      * only specify the red channel and the precision is limited to 4
      * digits, for conciseness.</p>
      * <p>Linear mapping:</p>
-     * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} = [ 0, 0, 1.0, 1.0 ]
+     * <pre><code>android.tonemap.curveRed = [ 0, 0, 1.0, 1.0 ]
      * </code></pre>
      * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
      * <p>Invert mapping:</p>
-     * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} = [ 0, 1.0, 1.0, 0 ]
+     * <pre><code>android.tonemap.curveRed = [ 0, 1.0, 1.0, 0 ]
      * </code></pre>
      * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
      * <p>Gamma 1/2.2 mapping, with 16 control points:</p>
-     * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} = [
+     * <pre><code>android.tonemap.curveRed = [
      * 0.0000, 0.0000, 0.0667, 0.2920, 0.1333, 0.4002, 0.2000, 0.4812,
      * 0.2667, 0.5484, 0.3333, 0.6069, 0.4000, 0.6594, 0.4667, 0.7072,
      * 0.5333, 0.7515, 0.6000, 0.7928, 0.6667, 0.8317, 0.7333, 0.8685,
@@ -1569,7 +1564,7 @@
      * </code></pre>
      * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
      * <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
-     * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} = [
+     * <pre><code>android.tonemap.curveRed = [
      * 0.0000, 0.0000, 0.0667, 0.2864, 0.1333, 0.4007, 0.2000, 0.4845,
      * 0.2667, 0.5532, 0.3333, 0.6125, 0.4000, 0.6652, 0.4667, 0.7130,
      * 0.5333, 0.7569, 0.6000, 0.7977, 0.6667, 0.8360, 0.7333, 0.8721,
@@ -1577,14 +1572,67 @@
      * </code></pre>
      * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
      *
-     * @see CaptureRequest#TONEMAP_CURVE_RED
      * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS
      * @see CaptureRequest#TONEMAP_MODE
+     * @hide
      */
     public static final Key<float[]> TONEMAP_CURVE_RED =
             new Key<float[]>("android.tonemap.curveRed", float[].class);
 
     /**
+     * <p>Tonemapping / contrast / gamma curve to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode}
+     * is CONTRAST_CURVE.</p>
+     * <p>The tonemapCurve consist of three curves for each of red, green, and blue
+     * channels respectively. The following example uses the red channel as an
+     * example. The same logic applies to green and blue channel.
+     * Each channel's curve is defined by an array of control points:</p>
+     * <pre><code>curveRed =
+     * [ P0(in, out), P1(in, out), P2(in, out), P3(in, out), ..., PN(in, out) ]
+     * 2 &lt;= N &lt;= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
+     * <p>These are sorted in order of increasing <code>Pin</code>; it is always
+     * guaranteed that input values 0.0 and 1.0 are included in the list to
+     * define a complete mapping. For input values between control points,
+     * the camera device must linearly interpolate between the control
+     * points.</p>
+     * <p>Each curve can have an independent number of points, and the number
+     * of points can be less than max (that is, the request doesn't have to
+     * always provide a curve with number of points equivalent to
+     * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}).</p>
+     * <p>A few examples, and their corresponding graphical mappings; these
+     * only specify the red channel and the precision is limited to 4
+     * digits, for conciseness.</p>
+     * <p>Linear mapping:</p>
+     * <pre><code>curveRed = [ (0, 0), (1.0, 1.0) ]
+     * </code></pre>
+     * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
+     * <p>Invert mapping:</p>
+     * <pre><code>curveRed = [ (0, 1.0), (1.0, 0) ]
+     * </code></pre>
+     * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
+     * <p>Gamma 1/2.2 mapping, with 16 control points:</p>
+     * <pre><code>curveRed = [
+     * (0.0000, 0.0000), (0.0667, 0.2920), (0.1333, 0.4002), (0.2000, 0.4812),
+     * (0.2667, 0.5484), (0.3333, 0.6069), (0.4000, 0.6594), (0.4667, 0.7072),
+     * (0.5333, 0.7515), (0.6000, 0.7928), (0.6667, 0.8317), (0.7333, 0.8685),
+     * (0.8000, 0.9035), (0.8667, 0.9370), (0.9333, 0.9691), (1.0000, 1.0000) ]
+     * </code></pre>
+     * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
+     * <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
+     * <pre><code>curveRed = [
+     * (0.0000, 0.0000), (0.0667, 0.2864), (0.1333, 0.4007), (0.2000, 0.4845),
+     * (0.2667, 0.5532), (0.3333, 0.6125), (0.4000, 0.6652), (0.4667, 0.7130),
+     * (0.5333, 0.7569), (0.6000, 0.7977), (0.6667, 0.8360), (0.7333, 0.8721),
+     * (0.8000, 0.9063), (0.8667, 0.9389), (0.9333, 0.9701), (1.0000, 1.0000) ]
+     * </code></pre>
+     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     *
+     * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    public static final Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE =
+            new Key<android.hardware.camera2.params.TonemapCurve>("android.tonemap.curve", android.hardware.camera2.params.TonemapCurve.class);
+
+    /**
      * <p>High-level global contrast/gamma/tonemapping control.</p>
      * <p>When switching to an application-defined contrast curve by setting
      * {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} to CONTRAST_CURVE, the curve is defined
@@ -1600,8 +1648,7 @@
      * <p>This must be set to a valid mode in
      * {@link CameraCharacteristics#TONEMAP_AVAILABLE_TONE_MAP_MODES android.tonemap.availableToneMapModes}.</p>
      * <p>When using either FAST or HIGH_QUALITY, the camera device will
-     * emit its own tonemap curve in {@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed},
-     * {@link CaptureRequest#TONEMAP_CURVE_GREEN android.tonemap.curveGreen}, and {@link CaptureRequest#TONEMAP_CURVE_BLUE android.tonemap.curveBlue}.
+     * emit its own tonemap curve in {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}.
      * These values are always available, and as close as possible to the
      * actually used nonlinear/nonglobal transforms.</p>
      * <p>If a request is sent with CONTRAST_CURVE with the camera device's
@@ -1609,9 +1656,7 @@
      * roughly the same.</p>
      *
      * @see CameraCharacteristics#TONEMAP_AVAILABLE_TONE_MAP_MODES
-     * @see CaptureRequest#TONEMAP_CURVE_BLUE
-     * @see CaptureRequest#TONEMAP_CURVE_GREEN
-     * @see CaptureRequest#TONEMAP_CURVE_RED
+     * @see CaptureRequest#TONEMAP_CURVE
      * @see CaptureRequest#TONEMAP_MODE
      * @see #TONEMAP_MODE_CONTRAST_CURVE
      * @see #TONEMAP_MODE_FAST
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 9aa56cf..42020eb 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -383,30 +383,24 @@
      *
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      */
-    public static final Key<Rational[]> COLOR_CORRECTION_TRANSFORM =
-            new Key<Rational[]>("android.colorCorrection.transform", Rational[].class);
+    public static final Key<android.hardware.camera2.params.ColorSpaceTransform> COLOR_CORRECTION_TRANSFORM =
+            new Key<android.hardware.camera2.params.ColorSpaceTransform>("android.colorCorrection.transform", android.hardware.camera2.params.ColorSpaceTransform.class);
 
     /**
      * <p>Gains applying to Bayer raw color channels for
      * white-balance.</p>
-     * <p>The 4-channel white-balance gains are defined in
-     * the order of <code>[R G_even G_odd B]</code>, where <code>G_even</code> is the gain
-     * for green pixels on even rows of the output, and <code>G_odd</code>
-     * is the gain for green pixels on the odd rows. if a HAL
-     * does not support a separate gain for even/odd green channels,
-     * it should use the <code>G_even</code> value, and write <code>G_odd</code> equal to
-     * <code>G_even</code> in the output result metadata.</p>
-     * <p>This array is either set by the camera device when the request
-     * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
-     * directly by the application in the request when the
-     * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is TRANSFORM_MATRIX.</p>
-     * <p>The output should be the gains actually applied by the camera device to
-     * the current frame.</p>
+     * <p>These per-channel gains are either set by the camera device
+     * when the request {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not
+     * TRANSFORM_MATRIX, or directly by the application in the
+     * request when the {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is
+     * TRANSFORM_MATRIX.</p>
+     * <p>The gains in the result metadata are the gains actually
+     * applied by the camera device to the current frame.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      */
-    public static final Key<float[]> COLOR_CORRECTION_GAINS =
-            new Key<float[]>("android.colorCorrection.gains", float[].class);
+    public static final Key<android.hardware.camera2.params.RggbChannelVector> COLOR_CORRECTION_GAINS =
+            new Key<android.hardware.camera2.params.RggbChannelVector>("android.colorCorrection.gains", android.hardware.camera2.params.RggbChannelVector.class);
 
     /**
      * <p>The desired setting for the camera device's auto-exposure
@@ -539,9 +533,6 @@
     /**
      * <p>List of areas to use for
      * metering.</p>
-     * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
-     * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -557,8 +548,8 @@
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
-    public static final Key<int[]> CONTROL_AE_REGIONS =
-            new Key<int[]>("android.control.aeRegions", int[].class);
+    public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AE_REGIONS =
+            new Key<android.hardware.camera2.params.MeteringRectangle[]>("android.control.aeRegions", android.hardware.camera2.params.MeteringRectangle[].class);
 
     /**
      * <p>Range over which fps can be adjusted to
@@ -568,8 +559,8 @@
      *
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      */
-    public static final Key<int[]> CONTROL_AE_TARGET_FPS_RANGE =
-            new Key<int[]>("android.control.aeTargetFpsRange", int[].class);
+    public static final Key<android.util.Range<Integer>> CONTROL_AE_TARGET_FPS_RANGE =
+            new Key<android.util.Range<Integer>>("android.control.aeTargetFpsRange", new TypeReference<android.util.Range<Integer>>() {{ }});
 
     /**
      * <p>Whether the camera device will trigger a precapture
@@ -812,26 +803,23 @@
     /**
      * <p>List of areas to use for focus
      * estimation.</p>
-     * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
-     * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
      * bottom-right pixel in the active pixel array. The weight
      * should be nonnegative.</p>
-     * <p>If all regions have 0 weight, then no specific focus area
-     * needs to be used by the camera device. If the focusing region is
-     * outside the the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture
-     * result metadata, the camera device will ignore the sections outside
-     * the region and output the used sections in the result metadata.</p>
+     * <p>If all regions have 0 weight, then no specific metering area
+     * needs to be used by the camera device. If the metering region is
+     * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
+     * the camera device will ignore the sections outside the region and output the
+     * used sections in the result metadata.</p>
      *
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
-    public static final Key<int[]> CONTROL_AF_REGIONS =
-            new Key<int[]>("android.control.afRegions", int[].class);
+    public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS =
+            new Key<android.hardware.camera2.params.MeteringRectangle[]>("android.control.afRegions", android.hardware.camera2.params.MeteringRectangle[].class);
 
     /**
      * <p>Whether the camera device will trigger autofocus for this request.</p>
@@ -1295,27 +1283,23 @@
     /**
      * <p>List of areas to use for illuminant
      * estimation.</p>
-     * <p>Only used in AUTO mode.</p>
-     * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
-     * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
      * bottom-right pixel in the active pixel array. The weight
      * should be nonnegative.</p>
-     * <p>If all regions have 0 weight, then no specific auto-white balance (AWB) area
-     * needs to be used by the camera device. If the AWB region is
-     * outside the the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
+     * <p>If all regions have 0 weight, then no specific metering area
+     * needs to be used by the camera device. If the metering region is
+     * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
      * the camera device will ignore the sections outside the region and output the
      * used sections in the result metadata.</p>
      *
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
-    public static final Key<int[]> CONTROL_AWB_REGIONS =
-            new Key<int[]>("android.control.awbRegions", int[].class);
+    public static final Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS =
+            new Key<android.hardware.camera2.params.MeteringRectangle[]>("android.control.awbRegions", android.hardware.camera2.params.MeteringRectangle[].class);
 
     /**
      * <p>Information to the camera device 3A (auto-exposure,
@@ -1656,8 +1640,15 @@
             new Key<Integer>("android.hotPixel.mode", int.class);
 
     /**
+     * <p>A location object to use when generating image GPS metadata.</p>
+     */
+    public static final Key<android.location.Location> JPEG_GPS_LOCATION =
+            new Key<android.location.Location>("android.jpeg.gpsLocation", android.location.Location.class);
+
+    /**
      * <p>GPS coordinates to include in output JPEG
      * EXIF</p>
+     * @hide
      */
     public static final Key<double[]> JPEG_GPS_COORDINATES =
             new Key<double[]>("android.jpeg.gpsCoordinates", double[].class);
@@ -1665,6 +1656,7 @@
     /**
      * <p>32 characters describing GPS algorithm to
      * include in EXIF</p>
+     * @hide
      */
     public static final Key<String> JPEG_GPS_PROCESSING_METHOD =
             new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
@@ -1672,6 +1664,7 @@
     /**
      * <p>Time GPS fix was made to include in
      * EXIF</p>
+     * @hide
      */
     public static final Key<Long> JPEG_GPS_TIMESTAMP =
             new Key<Long>("android.jpeg.gpsTimestamp", long.class);
@@ -1704,6 +1697,12 @@
      * but the captured JPEG will still be a valid image.</p>
      * <p>When a jpeg image capture is issued, the thumbnail size selected should have
      * the same aspect ratio as the jpeg image.</p>
+     * <p>If the thumbnail image aspect ratio differs from the JPEG primary image aspect
+     * ratio, the camera device creates the thumbnail by cropping it from the primary image.
+     * For example, if the primary image has 4:3 aspect ratio, the thumbnail image has
+     * 16:9 aspect ratio, the primary image will be cropped vertically (letterbox) to
+     * generate the thumbnail image. The thumbnail image will always have a smaller Field
+     * Of View (FOV) than the primary image when aspect ratios differ.</p>
      */
     public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
             new Key<android.util.Size>("android.jpeg.thumbnailSize", android.util.Size.class);
@@ -1793,8 +1792,8 @@
      * <p>If variable focus not supported, can still report
      * fixed depth of field range</p>
      */
-    public static final Key<float[]> LENS_FOCUS_RANGE =
-            new Key<float[]>("android.lens.focusRange", float[].class);
+    public static final Key<android.util.Range<Float>> LENS_FOCUS_RANGE =
+            new Key<android.util.Range<Float>>("android.lens.focusRange", new TypeReference<android.util.Range<Float>>() {{ }});
 
     /**
      * <p>Sets whether the camera device uses optical image stabilization (OIS)
@@ -2161,8 +2160,8 @@
      * <p>When set to OFF mode, no lens shading correction will be applied by the
      * camera device, and an identity lens shading map data will be provided
      * if <code>{@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} == ON</code>. For example, for lens
-     * shading map with size specified as <code>{@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize} = [ 4, 3 ]</code>,
-     * the output {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} for this case will be an identity map
+     * shading map with size specified as <code>android.lens.info.shadingMapSize = [ 4, 3 ]</code>,
+     * the output android.statistics.lensShadingMap for this case will be an identity map
      * shown below:</p>
      * <pre><code>[ 1.0, 1.0, 1.0, 1.0,  1.0, 1.0, 1.0, 1.0,
      * 1.0, 1.0, 1.0, 1.0,  1.0, 1.0, 1.0, 1.0,
@@ -2174,8 +2173,8 @@
      * <p>When set to other modes, lens shading correction will be applied by the
      * camera device. Applications can request lens shading map data by setting
      * {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} to ON, and then the camera device will provide
-     * lens shading map data in {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap}, with size specified
-     * by {@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize}; the returned shading map data will be the one
+     * lens shading map data in android.statistics.lensShadingMap, with size specified
+     * by android.lens.info.shadingMapSize; the returned shading map data will be the one
      * applied by the camera device for this capture request.</p>
      * <p>The shading map data may depend on the AE and AWB statistics, therefore the reliability
      * of the map data may be affected by the AE and AWB algorithms. When AE and AWB are in
@@ -2185,8 +2184,6 @@
      *
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AWB_MODE
-     * @see CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE
-     * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
      * @see #SHADING_MODE_OFF
      * @see #SHADING_MODE_FAST
@@ -2276,13 +2273,12 @@
      * The map is assumed to be bilinearly interpolated between the sample points.</p>
      * <p>The channel order is [R, Geven, Godd, B], where Geven is the green
      * channel for the even rows of a Bayer pattern, and Godd is the odd rows.
-     * The shading map is stored in a fully interleaved format, and its size
-     * is provided in the camera static metadata by {@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize}.</p>
+     * The shading map is stored in a fully interleaved format.</p>
      * <p>The shading map should have on the order of 30-40 rows and columns,
      * and must be smaller than 64x64.</p>
      * <p>As an example, given a very small map defined as:</p>
-     * <pre><code>{@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize} = [ 4, 3 ]
-     * {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} =
+     * <pre><code>width,height = [ 4, 3 ]
+     * values =
      * [ 1.3, 1.2, 1.15, 1.2,  1.2, 1.2, 1.15, 1.2,
      * 1.1, 1.2, 1.2, 1.2,  1.3, 1.2, 1.3, 1.3,
      * 1.2, 1.2, 1.25, 1.1,  1.1, 1.1, 1.1, 1.0,
@@ -2301,8 +2297,54 @@
      * <p><img alt="Image of a uniform white wall (inverse shading map)" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_MODE
-     * @see CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE
-     * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
+     */
+    public static final Key<android.hardware.camera2.params.LensShadingMap> STATISTICS_LENS_SHADING_CORRECTION_MAP =
+            new Key<android.hardware.camera2.params.LensShadingMap>("android.statistics.lensShadingCorrectionMap", android.hardware.camera2.params.LensShadingMap.class);
+
+    /**
+     * <p>The shading map is a low-resolution floating-point map
+     * that lists the coefficients used to correct for vignetting, for each
+     * Bayer color channel.</p>
+     * <p>The least shaded section of the image should have a gain factor
+     * of 1; all other sections should have gains above 1.</p>
+     * <p>When {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} = TRANSFORM_MATRIX, the map
+     * must take into account the colorCorrection settings.</p>
+     * <p>The shading map is for the entire active pixel array, and is not
+     * affected by the crop region specified in the request. Each shading map
+     * entry is the value of the shading compensation map over a specific
+     * pixel on the sensor.  Specifically, with a (N x M) resolution shading
+     * map, and an active pixel array size (W x H), shading map entry
+     * (x,y) ϵ (0 ... N-1, 0 ... M-1) is the value of the shading map at
+     * pixel ( ((W-1)/(N-1)) * x, ((H-1)/(M-1)) * y) for the four color channels.
+     * The map is assumed to be bilinearly interpolated between the sample points.</p>
+     * <p>The channel order is [R, Geven, Godd, B], where Geven is the green
+     * channel for the even rows of a Bayer pattern, and Godd is the odd rows.
+     * The shading map is stored in a fully interleaved format, and its size
+     * is provided in the camera static metadata by android.lens.info.shadingMapSize.</p>
+     * <p>The shading map should have on the order of 30-40 rows and columns,
+     * and must be smaller than 64x64.</p>
+     * <p>As an example, given a very small map defined as:</p>
+     * <pre><code>android.lens.info.shadingMapSize = [ 4, 3 ]
+     * android.statistics.lensShadingMap =
+     * [ 1.3, 1.2, 1.15, 1.2,  1.2, 1.2, 1.15, 1.2,
+     * 1.1, 1.2, 1.2, 1.2,  1.3, 1.2, 1.3, 1.3,
+     * 1.2, 1.2, 1.25, 1.1,  1.1, 1.1, 1.1, 1.0,
+     * 1.0, 1.0, 1.0, 1.0,  1.2, 1.3, 1.25, 1.2,
+     * 1.3, 1.2, 1.2, 1.3,   1.2, 1.15, 1.1, 1.2,
+     * 1.2, 1.1, 1.0, 1.2,  1.3, 1.15, 1.2, 1.3 ]
+     * </code></pre>
+     * <p>The low-resolution scaling map images for each channel are
+     * (displayed using nearest-neighbor interpolation):</p>
+     * <p><img alt="Red lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png" />
+     * <img alt="Green (even rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png" />
+     * <img alt="Green (odd rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
+     * <img alt="Blue lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
+     * <p>As a visualization only, inverting the full-color map to recover an
+     * image of a gray wall (using bicubic interpolation for visual quality) as captured by the sensor gives:</p>
+     * <p><img alt="Image of a uniform white wall (inverse shading map)" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
+     *
+     * @see CaptureRequest#COLOR_CORRECTION_MODE
+     * @hide
      */
     public static final Key<float[]> STATISTICS_LENS_SHADING_MAP =
             new Key<float[]>("android.statistics.lensShadingMap", float[].class);
@@ -2402,17 +2444,15 @@
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
      */
-    public static final Key<int[]> STATISTICS_HOT_PIXEL_MAP =
-            new Key<int[]>("android.statistics.hotPixelMap", int[].class);
+    public static final Key<android.graphics.Point[]> STATISTICS_HOT_PIXEL_MAP =
+            new Key<android.graphics.Point[]>("android.statistics.hotPixelMap", android.graphics.Point[].class);
 
     /**
      * <p>Whether the camera device will output the lens
      * shading map in output result metadata.</p>
      * <p>When set to ON,
-     * {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} must be provided in
+     * android.statistics.lensShadingMap must be provided in
      * the output result metadata.</p>
-     *
-     * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
      */
@@ -2423,10 +2463,10 @@
      * <p>Tonemapping / contrast / gamma curve for the blue
      * channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
      * CONTRAST_CURVE.</p>
-     * <p>See {@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} for more details.</p>
+     * <p>See android.tonemap.curveRed for more details.</p>
      *
-     * @see CaptureRequest#TONEMAP_CURVE_RED
      * @see CaptureRequest#TONEMAP_MODE
+     * @hide
      */
     public static final Key<float[]> TONEMAP_CURVE_BLUE =
             new Key<float[]>("android.tonemap.curveBlue", float[].class);
@@ -2435,10 +2475,10 @@
      * <p>Tonemapping / contrast / gamma curve for the green
      * channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
      * CONTRAST_CURVE.</p>
-     * <p>See {@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} for more details.</p>
+     * <p>See android.tonemap.curveRed for more details.</p>
      *
-     * @see CaptureRequest#TONEMAP_CURVE_RED
      * @see CaptureRequest#TONEMAP_MODE
+     * @hide
      */
     public static final Key<float[]> TONEMAP_CURVE_GREEN =
             new Key<float[]>("android.tonemap.curveGreen", float[].class);
@@ -2448,7 +2488,7 @@
      * channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
      * CONTRAST_CURVE.</p>
      * <p>Each channel's curve is defined by an array of control points:</p>
-     * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} =
+     * <pre><code>android.tonemap.curveRed =
      * [ P0in, P0out, P1in, P1out, P2in, P2out, P3in, P3out, ..., PNin, PNout ]
      * 2 &lt;= N &lt;= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
      * <p>These are sorted in order of increasing <code>Pin</code>; it is always
@@ -2464,15 +2504,15 @@
      * only specify the red channel and the precision is limited to 4
      * digits, for conciseness.</p>
      * <p>Linear mapping:</p>
-     * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} = [ 0, 0, 1.0, 1.0 ]
+     * <pre><code>android.tonemap.curveRed = [ 0, 0, 1.0, 1.0 ]
      * </code></pre>
      * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
      * <p>Invert mapping:</p>
-     * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} = [ 0, 1.0, 1.0, 0 ]
+     * <pre><code>android.tonemap.curveRed = [ 0, 1.0, 1.0, 0 ]
      * </code></pre>
      * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
      * <p>Gamma 1/2.2 mapping, with 16 control points:</p>
-     * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} = [
+     * <pre><code>android.tonemap.curveRed = [
      * 0.0000, 0.0000, 0.0667, 0.2920, 0.1333, 0.4002, 0.2000, 0.4812,
      * 0.2667, 0.5484, 0.3333, 0.6069, 0.4000, 0.6594, 0.4667, 0.7072,
      * 0.5333, 0.7515, 0.6000, 0.7928, 0.6667, 0.8317, 0.7333, 0.8685,
@@ -2480,7 +2520,7 @@
      * </code></pre>
      * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
      * <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
-     * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} = [
+     * <pre><code>android.tonemap.curveRed = [
      * 0.0000, 0.0000, 0.0667, 0.2864, 0.1333, 0.4007, 0.2000, 0.4845,
      * 0.2667, 0.5532, 0.3333, 0.6125, 0.4000, 0.6652, 0.4667, 0.7130,
      * 0.5333, 0.7569, 0.6000, 0.7977, 0.6667, 0.8360, 0.7333, 0.8721,
@@ -2488,14 +2528,67 @@
      * </code></pre>
      * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
      *
-     * @see CaptureRequest#TONEMAP_CURVE_RED
      * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS
      * @see CaptureRequest#TONEMAP_MODE
+     * @hide
      */
     public static final Key<float[]> TONEMAP_CURVE_RED =
             new Key<float[]>("android.tonemap.curveRed", float[].class);
 
     /**
+     * <p>Tonemapping / contrast / gamma curve to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode}
+     * is CONTRAST_CURVE.</p>
+     * <p>The tonemapCurve consist of three curves for each of red, green, and blue
+     * channels respectively. The following example uses the red channel as an
+     * example. The same logic applies to green and blue channel.
+     * Each channel's curve is defined by an array of control points:</p>
+     * <pre><code>curveRed =
+     * [ P0(in, out), P1(in, out), P2(in, out), P3(in, out), ..., PN(in, out) ]
+     * 2 &lt;= N &lt;= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
+     * <p>These are sorted in order of increasing <code>Pin</code>; it is always
+     * guaranteed that input values 0.0 and 1.0 are included in the list to
+     * define a complete mapping. For input values between control points,
+     * the camera device must linearly interpolate between the control
+     * points.</p>
+     * <p>Each curve can have an independent number of points, and the number
+     * of points can be less than max (that is, the request doesn't have to
+     * always provide a curve with number of points equivalent to
+     * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}).</p>
+     * <p>A few examples, and their corresponding graphical mappings; these
+     * only specify the red channel and the precision is limited to 4
+     * digits, for conciseness.</p>
+     * <p>Linear mapping:</p>
+     * <pre><code>curveRed = [ (0, 0), (1.0, 1.0) ]
+     * </code></pre>
+     * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
+     * <p>Invert mapping:</p>
+     * <pre><code>curveRed = [ (0, 1.0), (1.0, 0) ]
+     * </code></pre>
+     * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
+     * <p>Gamma 1/2.2 mapping, with 16 control points:</p>
+     * <pre><code>curveRed = [
+     * (0.0000, 0.0000), (0.0667, 0.2920), (0.1333, 0.4002), (0.2000, 0.4812),
+     * (0.2667, 0.5484), (0.3333, 0.6069), (0.4000, 0.6594), (0.4667, 0.7072),
+     * (0.5333, 0.7515), (0.6000, 0.7928), (0.6667, 0.8317), (0.7333, 0.8685),
+     * (0.8000, 0.9035), (0.8667, 0.9370), (0.9333, 0.9691), (1.0000, 1.0000) ]
+     * </code></pre>
+     * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
+     * <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
+     * <pre><code>curveRed = [
+     * (0.0000, 0.0000), (0.0667, 0.2864), (0.1333, 0.4007), (0.2000, 0.4845),
+     * (0.2667, 0.5532), (0.3333, 0.6125), (0.4000, 0.6652), (0.4667, 0.7130),
+     * (0.5333, 0.7569), (0.6000, 0.7977), (0.6667, 0.8360), (0.7333, 0.8721),
+     * (0.8000, 0.9063), (0.8667, 0.9389), (0.9333, 0.9701), (1.0000, 1.0000) ]
+     * </code></pre>
+     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     *
+     * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    public static final Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE =
+            new Key<android.hardware.camera2.params.TonemapCurve>("android.tonemap.curve", android.hardware.camera2.params.TonemapCurve.class);
+
+    /**
      * <p>High-level global contrast/gamma/tonemapping control.</p>
      * <p>When switching to an application-defined contrast curve by setting
      * {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} to CONTRAST_CURVE, the curve is defined
@@ -2511,8 +2604,7 @@
      * <p>This must be set to a valid mode in
      * {@link CameraCharacteristics#TONEMAP_AVAILABLE_TONE_MAP_MODES android.tonemap.availableToneMapModes}.</p>
      * <p>When using either FAST or HIGH_QUALITY, the camera device will
-     * emit its own tonemap curve in {@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed},
-     * {@link CaptureRequest#TONEMAP_CURVE_GREEN android.tonemap.curveGreen}, and {@link CaptureRequest#TONEMAP_CURVE_BLUE android.tonemap.curveBlue}.
+     * emit its own tonemap curve in {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}.
      * These values are always available, and as close as possible to the
      * actually used nonlinear/nonglobal transforms.</p>
      * <p>If a request is sent with CONTRAST_CURVE with the camera device's
@@ -2520,9 +2612,7 @@
      * roughly the same.</p>
      *
      * @see CameraCharacteristics#TONEMAP_AVAILABLE_TONE_MAP_MODES
-     * @see CaptureRequest#TONEMAP_CURVE_BLUE
-     * @see CaptureRequest#TONEMAP_CURVE_GREEN
-     * @see CaptureRequest#TONEMAP_CURVE_RED
+     * @see CaptureRequest#TONEMAP_CURVE
      * @see CaptureRequest#TONEMAP_MODE
      * @see #TONEMAP_MODE_CONTRAST_CURVE
      * @see #TONEMAP_MODE_FAST
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 7b24976..9a4c531 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -20,6 +20,8 @@
 
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.ICameraDeviceCallbacks;
@@ -73,6 +75,7 @@
     private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
 
     private final String mCameraId;
+    private final CameraCharacteristics mCharacteristics;
 
     /**
      * A list tracking request and its expected last frame.
@@ -151,13 +154,15 @@
         }
     };
 
-    public CameraDevice(String cameraId, StateListener listener, Handler handler) {
+    public CameraDevice(String cameraId, StateListener listener, Handler handler,
+                        CameraCharacteristics characteristics) {
         if (cameraId == null || listener == null || handler == null) {
             throw new IllegalArgumentException("Null argument given");
         }
         mCameraId = cameraId;
         mDeviceListener = listener;
         mDeviceHandler = handler;
+        mCharacteristics = characteristics;
 
         final int MAX_TAG_LEN = 23;
         String tag = String.format("CameraDevice-JV-%s", mCameraId);
@@ -851,11 +856,18 @@
         @Override
         public void onResultReceived(CameraMetadataNative result,
                 CaptureResultExtras resultExtras) throws RemoteException {
+
             int requestId = resultExtras.getRequestId();
             if (DEBUG) {
                 Log.v(TAG, "Received result frame " + resultExtras.getFrameNumber() + " for id "
                         + requestId);
             }
+
+
+            // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
+            result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
+                    getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
+
             final CaptureListenerHolder holder;
             synchronized (mLock) {
                 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
@@ -965,4 +977,8 @@
             return (mRemoteDevice == null);
         }
     }
+
+    private CameraCharacteristics getCharacteristics() {
+        return mCharacteristics;
+    }
 }
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index ab2c49a..dc0c652 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -43,13 +43,19 @@
 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableString;
 import android.hardware.camera2.params.Face;
+import android.hardware.camera2.params.LensShadingMap;
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
+import android.hardware.camera2.params.TonemapCurve;
 import android.hardware.camera2.utils.TypeReference;
+import android.location.Location;
+import android.location.LocationManager;
 import android.os.Parcelable;
 import android.os.Parcel;
 import android.util.Log;
+import android.util.Pair;
+import android.util.Size;
 
 import com.android.internal.util.Preconditions;
 
@@ -57,6 +63,7 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
+import java.util.HashMap;
 
 /**
  * Implementation of camera metadata marshal/unmarshal across Binder to
@@ -209,6 +216,37 @@
     // this should be in sync with HAL_PIXEL_FORMAT_BLOB defined in graphics.h
     public static final int NATIVE_JPEG_FORMAT = 0x21;
 
+    private static final String CELLID_PROCESS = "CELLID";
+    private static final String GPS_PROCESS = "GPS";
+
+    private static String translateLocationProviderToProcess(final String provider) {
+        if (provider == null) {
+            return null;
+        }
+        switch(provider) {
+            case LocationManager.GPS_PROVIDER:
+                return GPS_PROCESS;
+            case LocationManager.NETWORK_PROVIDER:
+                return CELLID_PROCESS;
+            default:
+                return null;
+        }
+    }
+
+    private static String translateProcessToLocationProvider(final String process) {
+        if (process == null) {
+            return null;
+        }
+        switch(process) {
+            case GPS_PROCESS:
+                return LocationManager.GPS_PROVIDER;
+            case CELLID_PROCESS:
+                return LocationManager.NETWORK_PROVIDER;
+            default:
+                return null;
+        }
+    }
+
     public CameraMetadataNative() {
         super();
         mMetadataPtr = nativeAllocate();
@@ -297,9 +335,9 @@
     public <T> T get(Key<T> key) {
         Preconditions.checkNotNull(key, "key must not be null");
 
-        T value = getOverride(key);
-        if (value != null) {
-            return value;
+        Pair<T, Boolean> override = getOverride(key);
+        if (override.second) {
+            return override.first;
         }
 
         return getBase(key);
@@ -409,23 +447,44 @@
         ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
         return marshaler.unmarshal(buffer);
     }
-
     // Need overwrite some metadata that has different definitions between native
     // and managed sides.
     @SuppressWarnings("unchecked")
-    private <T> T getOverride(Key<T> key) {
+    private <T> Pair<T, Boolean> getOverride(Key<T> key) {
+        T value = null;
+        boolean override = true;
+
         if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_FORMATS)) {
-            return (T) getAvailableFormats();
+            value = (T) getAvailableFormats();
         } else if (key.equals(CaptureResult.STATISTICS_FACES)) {
-            return (T) getFaces();
+            value = (T) getFaces();
         } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
-            return (T) getFaceRectangles();
+            value = (T) getFaceRectangles();
         } else if (key.equals(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)) {
-            return (T) getStreamConfigurationMap();
+            value = (T) getStreamConfigurationMap();
+        } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) {
+            value = (T) getMaxRegions(key);
+        } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) {
+            value = (T) getMaxRegions(key);
+        } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) {
+            value = (T) getMaxRegions(key);
+        } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) {
+            value = (T) getMaxNumOutputs(key);
+        } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) {
+            value = (T) getMaxNumOutputs(key);
+        } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) {
+            value = (T) getMaxNumOutputs(key);
+        } else if (key.equals(CaptureRequest.TONEMAP_CURVE)) {
+            value = (T) getTonemapCurve();
+        } else if (key.equals(CaptureResult.JPEG_GPS_LOCATION)) {
+            value = (T) getGpsLocation();
+        } else if (key.equals(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP)) {
+            value = (T) getLensShadingMap();
+        } else {
+            override = false;
         }
 
-        // For other keys, get() falls back to getBase()
-        return null;
+        return Pair.create(value, override);
     }
 
     private int[] getAvailableFormats() {
@@ -541,6 +600,62 @@
         return fixedFaceRectangles;
     }
 
+    private LensShadingMap getLensShadingMap() {
+        float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP);
+        if (lsmArray == null) {
+            Log.w(TAG, "getLensShadingMap - Lens shading map was null.");
+            return null;
+        }
+        Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
+        LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth());
+        return map;
+    }
+
+    private Location getGpsLocation() {
+        String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
+        Location l = new Location(translateProcessToLocationProvider(processingMethod));
+
+        double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
+        Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP);
+
+        if (timeStamp != null) {
+            l.setTime(timeStamp);
+        } else {
+            Log.w(TAG, "getGpsLocation - No timestamp for GPS location.");
+        }
+
+        if (coords != null) {
+            l.setLatitude(coords[0]);
+            l.setLongitude(coords[1]);
+            l.setAltitude(coords[2]);
+        } else {
+            Log.w(TAG, "getGpsLocation - No coordinates for GPS location");
+        }
+
+        return l;
+    }
+
+    private boolean setGpsLocation(Location l) {
+        if (l == null) {
+            return false;
+        }
+
+        double[] coords = { l.getLatitude(), l.getLongitude(), l.getAltitude() };
+        String processMethod = translateLocationProviderToProcess(l.getProvider());
+        long timestamp = l.getTime();
+
+        set(CaptureRequest.JPEG_GPS_TIMESTAMP, timestamp);
+        set(CaptureRequest.JPEG_GPS_COORDINATES, coords);
+
+        if (processMethod == null) {
+            Log.w(TAG, "setGpsLocation - No process method, Location is not from a GPS or NETWORK" +
+                    "provider");
+        } else {
+            setBase(CaptureRequest.JPEG_GPS_PROCESSING_METHOD, processMethod);
+        }
+        return true;
+    }
+
     private StreamConfigurationMap getStreamConfigurationMap() {
         StreamConfiguration[] configurations = getBase(
                 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
@@ -552,6 +667,63 @@
         return new StreamConfigurationMap(configurations, minFrameDurations, stallDurations);
     }
 
+    private <T> Integer getMaxRegions(Key<T> key) {
+        final int AE = 0;
+        final int AWB = 1;
+        final int AF = 2;
+
+        // The order of the elements is: (AE, AWB, AF)
+        int[] maxRegions = getBase(CameraCharacteristics.CONTROL_MAX_REGIONS);
+
+        if (maxRegions == null) {
+            return null;
+        }
+
+        if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) {
+            return maxRegions[AE];
+        } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) {
+            return maxRegions[AWB];
+        } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) {
+            return maxRegions[AF];
+        } else {
+            throw new AssertionError("Invalid key " + key);
+        }
+    }
+
+    private <T> Integer getMaxNumOutputs(Key<T> key) {
+        final int RAW = 0;
+        final int PROC = 1;
+        final int PROC_STALLING = 2;
+
+        // The order of the elements is: (raw, proc+nonstalling, proc+stalling)
+        int[] maxNumOutputs = getBase(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS);
+
+        if (maxNumOutputs == null) {
+            return null;
+        }
+
+        if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) {
+            return maxNumOutputs[RAW];
+        } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) {
+            return maxNumOutputs[PROC];
+        } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) {
+            return maxNumOutputs[PROC_STALLING];
+        } else {
+            throw new AssertionError("Invalid key " + key);
+        }
+    }
+
+    private <T> TonemapCurve getTonemapCurve() {
+        float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED);
+        float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN);
+        float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE);
+        if (red == null || green == null || blue == null) {
+            return null;
+        }
+        TonemapCurve tc = new TonemapCurve(red, green, blue);
+        return tc;
+    }
+
     private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
         setBase(key.getNativeKey(), value);
     }
@@ -591,8 +763,11 @@
             return setAvailableFormats((int[]) value);
         } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
             return setFaceRectangles((Rect[]) value);
+        } else if (key.equals(CaptureRequest.TONEMAP_CURVE)) {
+            return setTonemapCurve((TonemapCurve) value);
+        } else if (key.equals(CaptureResult.JPEG_GPS_LOCATION)) {
+            return setGpsLocation((Location) value);
         }
-
         // For other keys, set() falls back to setBase().
         return false;
     }
@@ -646,6 +821,24 @@
         return true;
     }
 
+    private <T> boolean setTonemapCurve(TonemapCurve tc) {
+        if (tc == null) {
+            return false;
+        }
+
+        float[][] curve = new float[3][];
+        for (int i = TonemapCurve.CHANNEL_RED; i <= TonemapCurve.CHANNEL_BLUE; i++) {
+            int pointCount = tc.getPointCount(i);
+            curve[i] = new float[pointCount * TonemapCurve.POINT_SIZE];
+            tc.copyColorCurve(i, curve[i], 0);
+        }
+        setBase(CaptureRequest.TONEMAP_CURVE_RED, curve[0]);
+        setBase(CaptureRequest.TONEMAP_CURVE_GREEN, curve[1]);
+        setBase(CaptureRequest.TONEMAP_CURVE_BLUE, curve[2]);
+
+        return true;
+    }
+
     private long mMetadataPtr; // native CameraMetadata*
 
     private native long nativeAllocate();
diff --git a/core/java/android/hardware/camera2/params/ColorSpaceTransform.java b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
index fa8c8ea..b4289db2 100644
--- a/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
@@ -139,8 +139,8 @@
             throw new IllegalArgumentException("row out of range");
         }
 
-        int numerator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_NUMERATOR];
-        int denominator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_DENOMINATOR];
+        int numerator = mElements[(row * COLUMNS + column) * RATIONAL_SIZE + OFFSET_NUMERATOR];
+        int denominator = mElements[(row * COLUMNS + column) * RATIONAL_SIZE + OFFSET_DENOMINATOR];
 
         return new Rational(numerator, denominator);
     }
@@ -162,7 +162,7 @@
     public void copyElements(Rational[] destination, int offset) {
         checkArgumentNonnegative(offset, "offset must not be negative");
         checkNotNull(destination, "destination must not be null");
-        if (destination.length + offset < COUNT) {
+        if (destination.length - offset < COUNT) {
             throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
         }
 
@@ -197,7 +197,7 @@
     public void copyElements(int[] destination, int offset) {
         checkArgumentNonnegative(offset, "offset must not be negative");
         checkNotNull(destination, "destination must not be null");
-        if (destination.length + offset < COUNT_INT) {
+        if (destination.length - offset < COUNT_INT) {
             throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
         }
 
diff --git a/core/java/android/hardware/camera2/params/LensShadingMap.java b/core/java/android/hardware/camera2/params/LensShadingMap.java
index b328f578..9bbc33a 100644
--- a/core/java/android/hardware/camera2/params/LensShadingMap.java
+++ b/core/java/android/hardware/camera2/params/LensShadingMap.java
@@ -28,7 +28,7 @@
 /**
  * Immutable class for describing a {@code 4 x N x M} lens shading map of floats.
  *
- * @see CameraCharacteristics#LENS_SHADING_MAP
+ * @see CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP
  */
 public final class LensShadingMap {
 
@@ -62,12 +62,12 @@
     public LensShadingMap(final float[] elements, final int rows, final int columns) {
 
         mRows = checkArgumentPositive(rows, "rows must be positive");
-        mColumns = checkArgumentPositive(rows, "columns must be positive");
+        mColumns = checkArgumentPositive(columns, "columns must be positive");
         mElements = checkNotNull(elements, "elements must not be null");
 
         if (elements.length != getGainFactorCount()) {
             throw new IllegalArgumentException("elements must be " + getGainFactorCount() +
-                    " length");
+                    " length, received " + elements.length);
         }
 
         // Every element must be finite and >= 1.0f
@@ -242,4 +242,4 @@
     private final int mRows;
     private final int mColumns;
     private final float[] mElements;
-};
+}
diff --git a/core/java/android/hardware/camera2/params/MeteringRectangle.java b/core/java/android/hardware/camera2/params/MeteringRectangle.java
index a26c57d..a7a3b59 100644
--- a/core/java/android/hardware/camera2/params/MeteringRectangle.java
+++ b/core/java/android/hardware/camera2/params/MeteringRectangle.java
@@ -57,7 +57,7 @@
      * @param height height >= 0
      * @param meteringWeight weight >= 0
      *
-     * @throws IllegalArgumentException if any of the parameters were non-negative
+     * @throws IllegalArgumentException if any of the parameters were negative
      */
     public MeteringRectangle(int x, int y, int width, int height, int meteringWeight) {
         mX = checkArgumentNonnegative(x, "x must be nonnegative");
@@ -74,7 +74,7 @@
      * @param dimensions a non-{@code null} {@link android.util.Size Size} with width, height >= 0
      * @param meteringWeight weight >= 0
      *
-     * @throws IllegalArgumentException if any of the parameters were non-negative
+     * @throws IllegalArgumentException if any of the parameters were negative
      * @throws NullPointerException if any of the arguments were null
      */
     public MeteringRectangle(Point xy, Size dimensions, int meteringWeight) {
@@ -94,7 +94,7 @@
      * @param rect a non-{@code null} rectangle with all x,y,w,h dimensions >= 0
      * @param meteringWeight weight >= 0
      *
-     * @throws IllegalArgumentException if any of the parameters were non-negative
+     * @throws IllegalArgumentException if any of the parameters were negative
      * @throws NullPointerException if any of the arguments were null
      */
     public MeteringRectangle(Rect rect, int meteringWeight) {
@@ -210,7 +210,7 @@
                 && mY == other.mY
                 && mWidth == other.mWidth
                 && mHeight == other.mHeight
-                && mWidth == other.mWidth);
+                && mWeight == other.mWeight);
     }
 
     /**
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 4bccaf1..3417de1 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -39,6 +39,7 @@
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
+import android.view.Gravity;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -679,7 +680,7 @@
         mInflater = (LayoutInflater)getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
-                false);
+                WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
         if (mHardwareAccelerated) {
             mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
         }
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index a9bace1..38a65c5 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -37,6 +37,8 @@
     final Callback mCallback;
     final KeyEvent.Callback mKeyEventCallback;
     final KeyEvent.DispatcherState mDispatcherState;
+    final int mWindowType;
+    final int mGravity;
     final boolean mTakesFocus;
     private final Rect mBounds = new Rect();
 
@@ -64,12 +66,14 @@
      */
     public SoftInputWindow(Context context, String name, int theme, Callback callback,
             KeyEvent.Callback keyEventCallback, KeyEvent.DispatcherState dispatcherState,
-            boolean takesFocus) {
+            int windowType, int gravity, boolean takesFocus) {
         super(context, theme);
         mName = name;
         mCallback = callback;
         mKeyEventCallback = keyEventCallback;
         mDispatcherState = dispatcherState;
+        mWindowType = windowType;
+        mGravity = gravity;
         mTakesFocus = takesFocus;
         initDockWindow();
     }
@@ -97,47 +101,6 @@
     }
 
     /**
-     * Get the size of the DockWindow.
-     * 
-     * @return If the DockWindow sticks to the top or bottom of the screen, the
-     *         return value is the height of the DockWindow, and its width is
-     *         equal to the width of the screen; If the DockWindow sticks to the
-     *         left or right of the screen, the return value is the width of the
-     *         DockWindow, and its height is equal to the height of the screen.
-     */
-    public int getSize() {
-        WindowManager.LayoutParams lp = getWindow().getAttributes();
-
-        if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) {
-            return lp.height;
-        } else {
-            return lp.width;
-        }
-    }
-
-    /**
-     * Set the size of the DockWindow.
-     * 
-     * @param size If the DockWindow sticks to the top or bottom of the screen,
-     *        <var>size</var> is the height of the DockWindow, and its width is
-     *        equal to the width of the screen; If the DockWindow sticks to the
-     *        left or right of the screen, <var>size</var> is the width of the
-     *        DockWindow, and its height is equal to the height of the screen.
-     */
-    public void setSize(int size) {
-        WindowManager.LayoutParams lp = getWindow().getAttributes();
-
-        if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) {
-            lp.width = -1;
-            lp.height = size;
-        } else {
-            lp.width = size;
-            lp.height = -1;
-        }
-        getWindow().setAttributes(lp);
-    }
-
-    /**
      * Set which boundary of the screen the DockWindow sticks to.
      * 
      * @param gravity The boundary of the screen to stick. See {#link
@@ -147,18 +110,18 @@
      */
     public void setGravity(int gravity) {
         WindowManager.LayoutParams lp = getWindow().getAttributes();
-
-        boolean oldIsVertical = (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM);
-
         lp.gravity = gravity;
+        updateWidthHeight(lp);
+        getWindow().setAttributes(lp);
+    }
 
-        boolean newIsVertical = (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM);
-
-        if (oldIsVertical != newIsVertical) {
-            int tmp = lp.width;
-            lp.width = lp.height;
-            lp.height = tmp;
-            getWindow().setAttributes(lp);
+    private void updateWidthHeight(WindowManager.LayoutParams lp) {
+        if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) {
+            lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+        } else {
+            lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
+            lp.height = WindowManager.LayoutParams.MATCH_PARENT;
         }
     }
 
@@ -201,14 +164,11 @@
     private void initDockWindow() {
         WindowManager.LayoutParams lp = getWindow().getAttributes();
 
-        lp.type = WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+        lp.type = mWindowType;
         lp.setTitle(mName);
 
-        lp.gravity = Gravity.BOTTOM;
-        lp.width = -1;
-        // Let the input method window's orientation follow sensor based rotation
-        // Turn this off for now, it is very problematic.
-        //lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
+        lp.gravity = mGravity;
+        updateWidthHeight(lp);
 
         getWindow().setAttributes(lp);
 
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index e0d69e3..e489e05 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -16,10 +16,13 @@
 
 package android.net;
 
+import android.net.NetworkUtils;
 import android.os.Parcelable;
 import android.os.Parcel;
 
+import java.io.IOException;
 import java.net.InetAddress;
+import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.net.UnknownHostException;
 import javax.net.SocketFactory;
@@ -38,6 +41,8 @@
      */
     public final int netId;
 
+    private NetworkBoundSocketFactory mNetworkBoundSocketFactory = null;
+
     /**
      * @hide
      */
@@ -79,6 +84,59 @@
     }
 
     /**
+     * A {@code SocketFactory} that produces {@code Socket}'s bound to this network.
+     */
+    private class NetworkBoundSocketFactory extends SocketFactory {
+        private final int mNetId;
+
+        public NetworkBoundSocketFactory(int netId) {
+            super();
+            mNetId = netId;
+        }
+
+        @Override
+        public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
+            Socket socket = createSocket();
+            socket.bind(new InetSocketAddress(localHost, localPort));
+            socket.connect(new InetSocketAddress(host, port));
+            return socket;
+        }
+
+        @Override
+        public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
+                int localPort) throws IOException {
+            Socket socket = createSocket();
+            socket.bind(new InetSocketAddress(localAddress, localPort));
+            socket.connect(new InetSocketAddress(address, port));
+            return socket;
+        }
+
+        @Override
+        public Socket createSocket(InetAddress host, int port) throws IOException {
+            Socket socket = createSocket();
+            socket.connect(new InetSocketAddress(host, port));
+            return socket;
+        }
+
+        @Override
+        public Socket createSocket(String host, int port) throws IOException {
+            Socket socket = createSocket();
+            socket.connect(new InetSocketAddress(host, port));
+            return socket;
+        }
+
+        @Override
+        public Socket createSocket() throws IOException {
+            Socket socket = new Socket();
+            // Query a property of the underlying socket to ensure the underlying
+            // socket exists so a file descriptor is available to bind to a network.
+            socket.getReuseAddress();
+            NetworkUtils.bindSocketToNetwork(socket.getFileDescriptor$().getInt$(), mNetId);
+            return socket;
+        }
+    }
+
+    /**
      * Returns a {@link SocketFactory} bound to this network.  Any {@link Socket} created by
      * this factory will have its traffic sent over this {@code Network}.  Note that if this
      * {@code Network} ever disconnects, this factory and any {@link Socket} it produced in the
@@ -88,7 +146,10 @@
      *         {@code Network}.
      */
     public SocketFactory socketFactory() {
-        return null;
+        if (mNetworkBoundSocketFactory == null) {
+            mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId);
+        }
+        return mNetworkBoundSocketFactory;
     }
 
     /**
@@ -99,6 +160,29 @@
      * doesn't accidentally use sockets it thinks are still bound to a particular {@code Network}.
      */
     public void bindProcess() {
+        NetworkUtils.bindProcessToNetwork(netId);
+    }
+
+    /**
+     * Binds host resolutions performed by this process to this network.  {@link #bindProcess}
+     * takes precedence over this setting.
+     *
+     * @hide
+     * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
+     */
+    public void bindProcessForHostResolution() {
+        NetworkUtils.bindProcessToNetworkForHostResolution(netId);
+    }
+
+    /**
+     * Clears any process specific {@link Network} binding for host resolution.  This does
+     * not clear bindings enacted via {@link #bindProcess}.
+     *
+     * @hide
+     * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
+     */
+    public void unbindProcessForHostResolution() {
+        NetworkUtils.unbindProcessToNetworkForHostResolution();
     }
 
     /**
@@ -107,7 +191,7 @@
      * @return {@code Network} to which this process is bound.
      */
     public static Network getProcessBoundNetwork() {
-        return null;
+        return new Network(NetworkUtils.getNetworkBoundToProcess());
     }
 
     /**
@@ -115,6 +199,7 @@
      * {@link Network#bindProcess}.
      */
     public static void unbindProcess() {
+        NetworkUtils.unbindProcessToNetwork();
     }
 
     // implement the Parcelable interface
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index c2b06a2..1c18ba5 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -257,31 +257,43 @@
     }
 
     /**
-     * called to go through our list of requests and see if we're
-     * good enough to try connecting.
+     * Called to go through our list of requests and see if we're
+     * good enough to try connecting, or if we have gotten worse and
+     * need to disconnect.
      *
-     * Only does connects - we disconnect when requested via
+     * Once we are registered, does nothing: we disconnect when requested via
      * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection
      * between modules (bearer or ConnectivityService dies) or more commonly
      * when the NetworkInfo reports to ConnectivityService it is disconnected.
      */
     private void evalScores() {
-        if (mConnectionRequested) {
-            if (VDBG) log("evalScores - already trying - size=" + mNetworkRequests.size());
-            // already trying
-            return;
-        }
-        if (VDBG) log("evalScores!");
-        for (int i=0; i < mNetworkRequests.size(); i++) {
-            int score = mNetworkRequests.valueAt(i).score;
-            if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore);
-            if (score < mNetworkScore) {
-                // have a request that has a lower scored network servicing it
-                // (or no network) than we could provide, so lets connect!
-                mConnectionRequested = true;
-                connect();
+        synchronized(mLockObj) {
+            if (mRegistered) {
+                if (VDBG) log("evalScores - already connected - size=" + mNetworkRequests.size());
+                // already trying
                 return;
             }
+            if (VDBG) log("evalScores!");
+            for (int i=0; i < mNetworkRequests.size(); i++) {
+                int score = mNetworkRequests.valueAt(i).score;
+                if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore);
+                if (score < mNetworkScore) {
+                    // have a request that has a lower scored network servicing it
+                    // (or no network) than we could provide, so let's connect!
+                    mConnectionRequested = true;
+                    connect();
+                    return;
+                }
+            }
+            // Our score is not high enough to satisfy any current request.
+            // This can happen if our score goes down after a connection is
+            // requested but before we actually connect. In this case, disconnect
+            // rather than continue trying - there's no point connecting if we know
+            // we'll just be torn down as soon as we do.
+            if (mConnectionRequested) {
+                mConnectionRequested = false;
+                disconnect();
+            }
         }
     }
 
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index b24d396..edb3286 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -109,6 +109,50 @@
     public native static void markSocket(int socketfd, int mark);
 
     /**
+     * Binds the current process to the network designated by {@code netId}.  All sockets created
+     * in the future (and not explicitly bound via a bound {@link SocketFactory} (see
+     * {@link Network#socketFactory}) will be bound to this network.  Note that if this
+     * {@code Network} ever disconnects all sockets created in this way will cease to work.  This
+     * is by design so an application doesn't accidentally use sockets it thinks are still bound to
+     * a particular {@code Network}.
+     */
+    public native static void bindProcessToNetwork(int netId);
+
+    /**
+     * Clear any process specific {@code Network} binding.  This reverts a call to
+     * {@link #bindProcessToNetwork}.
+     */
+    public native static void unbindProcessToNetwork();
+
+    /**
+     * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if
+     * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}.
+     */
+    public native static int getNetworkBoundToProcess();
+
+    /**
+     * Binds host resolutions performed by this process to the network designated by {@code netId}.
+     * {@link #bindProcessToNetwork} takes precedence over this setting.
+     *
+     * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
+     */
+    public native static void bindProcessToNetworkForHostResolution(int netId);
+
+    /**
+     * Clears any process specific {@link Network} binding for host resolution.  This does
+     * not clear bindings enacted via {@link #bindProcessToNetwork}.
+     *
+     * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
+     */
+    public native static void unbindProcessToNetworkForHostResolution();
+
+    /**
+     * Explicitly binds {@code socketfd} to the network designated by {@code netId}.  This
+     * overrides any binding via {@link #bindProcessToNetwork}.
+     */
+    public native static void bindSocketToNetwork(int socketfd, int netId);
+
+    /**
      * Convert a IPv4 address from an integer to an InetAddress.
      * @param hostAddress an int corresponding to the IPv4 address in network byte order
      */
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 4963991..68b91cb 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -58,24 +58,6 @@
  * argument of {@link android.content.Context#STORAGE_SERVICE}.
  */
 public class StorageManager {
-
-    /// Consts to match the password types in cryptfs.h
-    /** Master key is encrypted with a password.
-     */
-    public static final int CRYPT_TYPE_PASSWORD = 0;
-
-    /** Master key is encrypted with the default password.
-     */
-    public static final int CRYPT_TYPE_DEFAULT = 1;
-
-    /** Master key is encrypted with a pattern.
-     */
-    public static final int CRYPT_TYPE_PATTERN = 2;
-
-    /** Master key is encrypted with a pin.
-     */
-    public static final int CRYPT_TYPE_PIN = 3;
-
     private static final String TAG = "StorageManager";
 
     private final ContentResolver mResolver;
@@ -663,4 +645,14 @@
         return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
                 DEFAULT_FULL_THRESHOLD_BYTES);
     }
+
+    /// Consts to match the password types in cryptfs.h
+    /** @hide */
+    public static final int CRYPT_TYPE_PASSWORD = 0;
+    /** @hide */
+    public static final int CRYPT_TYPE_DEFAULT = 1;
+    /** @hide */
+    public static final int CRYPT_TYPE_PATTERN = 2;
+    /** @hide */
+    public static final int CRYPT_TYPE_PIN = 3;
 }
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index a83544d..cd357b7 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.graphics.Rect;
 import android.graphics.Region;
 import android.inputmethodservice.SoftInputWindow;
 import android.os.Binder;
@@ -32,6 +33,7 @@
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -262,14 +264,14 @@
      */
     public static final class Insets {
         /**
-         * This is the top part of the UI that is the main content.  It is
+         * This is the part of the UI that is the main content.  It is
          * used to determine the basic space needed, to resize/pan the
          * application behind.  It is assumed that this inset does not
          * change very much, since any change will cause a full resize/pan
          * of the application behind.  This value is relative to the top edge
          * of the input method window.
          */
-        public int contentTopInsets;
+        public final Rect contentInsets = new Rect();
 
         /**
          * This is the region of the UI that is touchable.  It is used when
@@ -311,7 +313,8 @@
             new ViewTreeObserver.OnComputeInternalInsetsListener() {
         public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
             onComputeInsets(mTmpInsets);
-            info.contentInsets.top = info.visibleInsets.top = mTmpInsets.contentTopInsets;
+            info.contentInsets.set(mTmpInsets.contentInsets);
+            info.visibleInsets.set(mTmpInsets.contentInsets);
             info.touchableRegion.set(mTmpInsets.touchableRegion);
             info.setTouchableInsets(mTmpInsets.touchableInsets);
         }
@@ -428,6 +431,8 @@
             throw new IllegalStateException("Can't call before onCreate()");
         }
         try {
+            intent.migrateExtraStreamToClipData();
+            intent.prepareToLeaveProcess();
             int res = mSystemService.startVoiceActivity(mToken, intent,
                     intent.resolveType(mContext.getContentResolver()));
             Instrumentation.checkStartActivityResult(res, intent);
@@ -460,7 +465,8 @@
         mInflater = (LayoutInflater)mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
-                mCallbacks, this, mDispatcherState, true);
+                mCallbacks, this, mDispatcherState,
+                WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.TOP, true);
         mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
         initViews();
         mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
@@ -517,7 +523,10 @@
         int[] loc = mTmpLocation;
         View decor = getWindow().getWindow().getDecorView();
         decor.getLocationInWindow(loc);
-        outInsets.contentTopInsets = loc[1];
+        outInsets.contentInsets.top = 0;
+        outInsets.contentInsets.left = 0;
+        outInsets.contentInsets.right = 0;
+        outInsets.contentInsets.bottom = 0;
         outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME;
         outInsets.touchableRegion.setEmpty();
     }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7d13399..af16185 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -79,7 +79,7 @@
     void removeWindowToken(IBinder token);
     void addAppToken(int addPos, IApplicationToken token, int groupId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
-            int configChanges);
+            int configChanges, boolean voiceInteraction);
     void setAppGroupId(IBinder token, int groupId);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
@@ -120,6 +120,7 @@
     boolean isKeyguardSecure();
     boolean inKeyguardRestrictedInputMode();
     void dismissKeyguard();
+    void keyguardGoingAway();
 
     void closeSystemDialogs(String reason);
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b821a3e..0f40ee7 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -456,6 +456,10 @@
     // views during a transition when they otherwise would have become gone/invisible
     private ArrayList<View> mVisibilityChangingChildren;
 
+    // Temporary holder of presorted children, only used for
+    // input/software draw dispatch for correctly Z ordering.
+    private ArrayList<View> mPreSortedChildren;
+
     // Indicates how many of this container's child subtrees contain transient state
     @ViewDebug.ExportedProperty(category = "layout")
     private int mChildCountWithTransientState = 0;
@@ -1499,13 +1503,15 @@
             final float y = event.getY();
             final int childrenCount = mChildrenCount;
             if (childrenCount != 0) {
-                final boolean customChildOrder = isChildrenDrawingOrderEnabled();
+                final ArrayList<View> preorderedList = buildOrderedChildList();
+                final boolean customOrder = preorderedList == null
+                        && isChildrenDrawingOrderEnabled();
                 final View[] children = mChildren;
                 HoverTarget lastHoverTarget = null;
                 for (int i = childrenCount - 1; i >= 0; i--) {
-                    final int childIndex = customChildOrder
-                            ? getChildDrawingOrder(childrenCount, i) : i;
-                    final View child = children[childIndex];
+                    int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
+                    final View child = (preorderedList == null)
+                            ? children[childIndex] : preorderedList.get(childIndex);
                     if (!canViewReceivePointerEvents(child)
                             || !isTransformedTouchPointInView(x, y, child, null)) {
                         continue;
@@ -1572,6 +1578,7 @@
                         break;
                     }
                 }
+                if (preorderedList != null) preorderedList.clear();
             }
         }
 
@@ -1778,23 +1785,28 @@
         // Send the event to the child under the pointer.
         final int childrenCount = mChildrenCount;
         if (childrenCount != 0) {
-            final View[] children = mChildren;
             final float x = event.getX();
             final float y = event.getY();
 
-            final boolean customOrder = isChildrenDrawingOrderEnabled();
+            final ArrayList<View> preorderedList = buildOrderedChildList();
+            final boolean customOrder = preorderedList == null
+                    && isChildrenDrawingOrderEnabled();
+            final View[] children = mChildren;
             for (int i = childrenCount - 1; i >= 0; i--) {
-                final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
-                final View child = children[childIndex];
+                int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
+                final View child = (preorderedList == null)
+                        ? children[childIndex] : preorderedList.get(childIndex);
                 if (!canViewReceivePointerEvents(child)
                         || !isTransformedTouchPointInView(x, y, child, null)) {
                     continue;
                 }
 
                 if (dispatchTransformedGenericPointerEvent(event, child)) {
+                    if (preorderedList != null) preorderedList.clear();
                     return true;
                 }
             }
+            if (preorderedList != null) preorderedList.clear();
         }
 
         // No child handled the event.  Send it to this view group.
@@ -1910,13 +1922,15 @@
                         final float y = ev.getY(actionIndex);
                         // Find a child that can receive the event.
                         // Scan children from front to back.
+                        final ArrayList<View> preorderedList = buildOrderedChildList();
+                        final boolean customOrder = preorderedList == null
+                                && isChildrenDrawingOrderEnabled();
                         final View[] children = mChildren;
-
-                        final boolean customOrder = isChildrenDrawingOrderEnabled();
                         for (int i = childrenCount - 1; i >= 0; i--) {
-                            final int childIndex = customOrder ?
-                                    getChildDrawingOrder(childrenCount, i) : i;
-                            final View child = children[childIndex];
+                            final int childIndex = customOrder
+                                    ? getChildDrawingOrder(childrenCount, i) : i;
+                            final View child = (preorderedList == null)
+                                    ? children[childIndex] : preorderedList.get(childIndex);
                             if (!canViewReceivePointerEvents(child)
                                     || !isTransformedTouchPointInView(x, y, child, null)) {
                                 continue;
@@ -1934,7 +1948,17 @@
                             if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                                 // Child wants to receive touch within its bounds.
                                 mLastTouchDownTime = ev.getDownTime();
-                                mLastTouchDownIndex = childIndex;
+                                if (preorderedList != null) {
+                                    // childIndex points into presorted list, find original index
+                                    for (int j = 0; j < childrenCount; j++) {
+                                        if (children[childIndex] == mChildren[j]) {
+                                            mLastTouchDownIndex = j;
+                                            break;
+                                        }
+                                    }
+                                } else {
+                                    mLastTouchDownIndex = childIndex;
+                                }
                                 mLastTouchDownX = ev.getX();
                                 mLastTouchDownY = ev.getY();
                                 newTouchTarget = addTouchTarget(child, idBitsToAssign);
@@ -1942,6 +1966,7 @@
                                 break;
                             }
                         }
+                        if (preorderedList != null) preorderedList.clear();
                     }
 
                     if (newTouchTarget == null && mFirstTouchTarget != null) {
@@ -2928,7 +2953,7 @@
      */
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        final int count = mChildrenCount;
+        final int childrenCount = mChildrenCount;
         final View[] children = mChildren;
         int flags = mGroupFlags;
 
@@ -2936,15 +2961,15 @@
             final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
 
             final boolean buildCache = !isHardwareAccelerated();
-            for (int i = 0; i < count; i++) {
+            for (int i = 0; i < childrenCount; i++) {
                 final View child = children[i];
                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
                     final LayoutParams params = child.getLayoutParams();
-                    attachLayoutAnimationParameters(child, params, i, count);
+                    attachLayoutAnimationParameters(child, params, i, childrenCount);
                     bindLayoutAnimation(child);
                     if (cache) {
                         child.setDrawingCacheEnabled(true);
-                        if (buildCache) {                        
+                        if (buildCache) {
                             child.buildDrawingCache(true);
                         }
                     }
@@ -2997,21 +3022,22 @@
         boolean more = false;
         final long drawingTime = getDrawingTime();
 
-        if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
-            for (int i = 0; i < count; i++) {
-                final View child = children[i];
-                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
-                    more |= drawChild(canvas, child, drawingTime);
-                }
-            }
-        } else {
-            for (int i = 0; i < count; i++) {
-                final View child = children[getChildDrawingOrder(count, i)];
-                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
-                    more |= drawChild(canvas, child, drawingTime);
-                }
+
+        // Only use the preordered list if not HW accelerated, since the HW pipeline will do the
+        // draw reordering internally
+        final ArrayList<View> preorderedList = canvas.isHardwareAccelerated()
+                ? null : buildOrderedChildList();
+        final boolean customOrder = preorderedList == null
+                && isChildrenDrawingOrderEnabled();
+        for (int i = 0; i < childrenCount; i++) {
+            int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
+            final View child = (preorderedList == null)
+                    ? children[childIndex] : preorderedList.get(childIndex);
+            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
+                more |= drawChild(canvas, child, drawingTime);
             }
         }
+        if (preorderedList != null) preorderedList.clear();
 
         // Draw any disappearing views that have animations
         if (mDisappearingChildren != null) {
@@ -3096,6 +3122,47 @@
         return i;
     }
 
+    private boolean hasChildWithZ() {
+        for (int i = 0; i < mChildrenCount; i++) {
+            if (mChildren[i].getZ() != 0) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
+     * sorted first by Z, then by child drawing order (if applicable).
+     *
+     * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
+     * children.
+     */
+    private ArrayList<View> buildOrderedChildList() {
+        final int count = mChildrenCount;
+        if (count <= 1 || !hasChildWithZ()) return null;
+
+        if (mPreSortedChildren == null) {
+            mPreSortedChildren = new ArrayList<View>(count);
+        } else {
+            mPreSortedChildren.ensureCapacity(count);
+        }
+
+        final boolean useCustomOrder = isChildrenDrawingOrderEnabled();
+        for (int i = 0; i < mChildrenCount; i++) {
+            // add next child (in child order) to end of list
+            int childIndex = useCustomOrder ? getChildDrawingOrder(mChildrenCount, i) : i;
+            View nextChild = mChildren[childIndex];
+            float currentZ = nextChild.getZ();
+
+            // insert ahead of any Views with greater Z
+            int insertIndex = i;
+            while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
+                insertIndex--;
+            }
+            mPreSortedChildren.add(insertIndex, nextChild);
+        }
+        return mPreSortedChildren;
+    }
+
     private void notifyAnimationListener() {
         mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
         mGroupFlags |= FLAG_ANIMATION_DONE;
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 3104862..af1de78 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -253,9 +253,10 @@
     ViewPropertyAnimator(View view) {
         mView = view;
         view.ensureTransformationInfo();
-        if (view.getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.L) {
-            mRTBackend = new ViewPropertyAnimatorRT(view);
-        }
+        // TODO: Disabled because of b/15287046
+        //if (view.getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.L) {
+        //    mRTBackend = new ViewPropertyAnimatorRT(view);
+        //}
     }
 
     /**
@@ -1142,7 +1143,8 @@
                 // Shouldn't happen, but just to play it safe
                 return;
             }
-            boolean useRenderNodeProperties = mView.mRenderNode != null;
+
+            boolean hardwareAccelerated = mView.isHardwareAccelerated();
 
             // alpha requires slightly different treatment than the other (transform) properties.
             // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
@@ -1150,13 +1152,13 @@
             // We track what kinds of properties are set, and how alpha is handled when it is
             // set, and perform the invalidation steps appropriately.
             boolean alphaHandled = false;
-            if (!useRenderNodeProperties) {
+            if (!hardwareAccelerated) {
                 mView.invalidateParentCaches();
             }
             float fraction = animation.getAnimatedFraction();
             int propertyMask = propertyBundle.mPropertyMask;
             if ((propertyMask & TRANSFORM_MASK) != 0) {
-                mView.invalidateViewProperty(false, false);
+                mView.invalidateViewProperty(hardwareAccelerated, false);
             }
             ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
             if (valueList != null) {
@@ -1172,7 +1174,7 @@
                 }
             }
             if ((propertyMask & TRANSFORM_MASK) != 0) {
-                if (!useRenderNodeProperties) {
+                if (!hardwareAccelerated) {
                     mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
                 }
             }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 031ad80..4eecc6a 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -218,7 +218,8 @@
             @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR_PANEL, to = "TYPE_NAVIGATION_BAR_PANEL"),
             @ViewDebug.IntToString(from = TYPE_DISPLAY_OVERLAY, to = "TYPE_DISPLAY_OVERLAY"),
             @ViewDebug.IntToString(from = TYPE_MAGNIFICATION_OVERLAY, to = "TYPE_MAGNIFICATION_OVERLAY"),
-            @ViewDebug.IntToString(from = TYPE_PRIVATE_PRESENTATION, to = "TYPE_PRIVATE_PRESENTATION")
+            @ViewDebug.IntToString(from = TYPE_PRIVATE_PRESENTATION, to = "TYPE_PRIVATE_PRESENTATION"),
+            @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION, to = "TYPE_VOICE_INTERACTION"),
         })
         public int type;
     
@@ -541,6 +542,12 @@
         public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;
 
         /**
+         * Window type: Windows in the voice interaction layer.
+         * @hide
+         */
+        public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 1bb20c9..d45d686 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -274,6 +274,11 @@
         public IApplicationToken getAppToken();
 
         /**
+         * Return true if this window is participating in voice interaction.
+         */
+        public boolean isVoiceInteraction();
+
+        /**
          * Return true if, at any point, the application token associated with 
          * this window has actually displayed any windows.  This is most useful 
          * with the "starting up" window to determine if any windows were 
@@ -603,8 +608,15 @@
      * Return whether the given window should forcibly hide everything
      * behind it.  Typically returns true for the keyguard.
      */
-    public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs);
-    
+    public boolean doesForceHide(WindowManager.LayoutParams attrs);
+
+
+    /**
+     * Return whether the given window can become one that passes doesForceHide() test.
+     * Typically returns true for the StatusBar.
+     */
+    public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs);
+
     /**
      * Determine if a window that is behind one that is force hiding
      * (as determined by {@link #doesForceHide}) should actually be hidden.
@@ -613,7 +625,7 @@
      * will conflict with what you set.
      */
     public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs);
-    
+
     /**
      * Called when the system would like to show a UI to indicate that an
      * application is starting.  You can use this to add a
@@ -1144,12 +1156,6 @@
     public void setLastInputMethodWindowLw(WindowState ime, WindowState target);
 
     /**
-     * Show the recents task list app.
-     * @hide
-     */
-    public void showRecentApps();
-
-    /**
      * @return The current height of the input method window.
      */
     public int getInputMethodWindowVisibleHeightLw();
@@ -1190,4 +1196,9 @@
      * @return True if the window is a top level one.
      */
     public boolean isTopLevelWindow(int windowType);
+
+    /**
+     * Notifies the keyguard to start fading out.
+     */
+    public void startKeyguardExitAnimation(long fadeoutDuration);
 }
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 51759c5..1fddf3e 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -544,6 +544,7 @@
 
     public void setMenuView(ActionMenuView menuView) {
         mMenuView = menuView;
+        menuView.initialize(mMenu);
     }
 
     private static class SavedState implements Parcelable {
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 3975edf..a9a5eae 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -69,6 +69,7 @@
     /** @hide */
     public void setPresenter(ActionMenuPresenter presenter) {
         mPresenter = presenter;
+        mPresenter.setMenuView(this);
     }
 
     @Override
@@ -488,7 +489,7 @@
     @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mPresenter.dismissPopupMenus();
+        dismissPopupMenus();
     }
 
     /** @hide */
@@ -578,6 +579,56 @@
     }
 
     /**
+     * Returns the current menu or null if one has not yet been configured.
+     * @hide Internal use only for action bar integration
+     */
+    public MenuBuilder peekMenu() {
+        return mMenu;
+    }
+
+    /**
+     * Show the overflow items from the associated menu.
+     *
+     * @return true if the menu was able to be shown, false otherwise
+     */
+    public boolean showOverflowMenu() {
+        return mPresenter != null && mPresenter.showOverflowMenu();
+    }
+
+    /**
+     * Hide the overflow items from the associated menu.
+     *
+     * @return true if the menu was able to be hidden, false otherwise
+     */
+    public boolean hideOverflowMenu() {
+        return mPresenter != null && mPresenter.hideOverflowMenu();
+    }
+
+    /**
+     * Check whether the overflow menu is currently showing. This may not reflect
+     * a pending show operation in progress.
+     *
+     * @return true if the overflow menu is currently showing
+     */
+    public boolean isOverflowMenuShowing() {
+        return mPresenter != null && mPresenter.isOverflowMenuShowing();
+    }
+
+    /** @hide */
+    public boolean isOverflowMenuShowPending() {
+        return mPresenter != null && mPresenter.isOverflowMenuShowPending();
+    }
+
+    /**
+     * Dismiss any popups associated with this menu view.
+     */
+    public void dismissPopupMenus() {
+        if (mPresenter != null) {
+            mPresenter.dismissPopupMenus();
+        }
+    }
+
+    /**
      * @hide Private LinearLayout (superclass) API. Un-hide if LinearLayout API is made public.
      */
     @Override
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index f903346..5033bee 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -18,13 +18,17 @@
 package android.widget;
 
 import android.annotation.NonNull;
+import android.app.ActionBar;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.Layout;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Log;
+import android.view.CollapsibleActionView;
 import android.view.Gravity;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -32,7 +36,15 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
+import android.view.Window;
 import com.android.internal.R;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuItemImpl;
+import com.android.internal.view.menu.MenuPresenter;
+import com.android.internal.view.menu.MenuView;
+import com.android.internal.view.menu.SubMenuBuilder;
+import com.android.internal.widget.DecorToolbar;
+import com.android.internal.widget.ToolbarWidgetWrapper;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -80,14 +92,25 @@
  * layout is discouraged on API 21 devices and newer.</p>
  */
 public class Toolbar extends ViewGroup {
+    private static final String TAG = "Toolbar";
+
     private ActionMenuView mMenuView;
     private TextView mTitleTextView;
     private TextView mSubtitleTextView;
     private ImageButton mNavButtonView;
     private ImageView mLogoView;
 
+    private Drawable mCollapseIcon;
+    private ImageButton mCollapseButtonView;
+    View mExpandedActionView;
+
     private int mTitleTextAppearance;
     private int mSubtitleTextAppearance;
+    private int mNavButtonStyle;
+
+    private int mButtonGravity;
+
+    private int mMaxButtonHeight;
 
     private int mTitleMarginStart;
     private int mTitleMarginEnd;
@@ -117,6 +140,10 @@
                 }
             };
 
+    private ToolbarWidgetWrapper mWrapper;
+    private ActionMenuPresenter mOuterActionMenuPresenter;
+    private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
+
     public Toolbar(Context context) {
         this(context, null);
     }
@@ -137,7 +164,9 @@
 
         mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
         mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
+        mNavButtonStyle = a.getResourceId(R.styleable.Toolbar_navigationButtonStyle, 0);
         mGravity = a.getInteger(R.styleable.Toolbar_gravity, mGravity);
+        mButtonGravity = a.getInteger(R.styleable.Toolbar_buttonGravity, Gravity.TOP);
         mTitleMarginStart = mTitleMarginEnd = mTitleMarginTop = mTitleMarginBottom =
                 a.getDimensionPixelOffset(R.styleable.Toolbar_titleMargins, 0);
 
@@ -162,6 +191,8 @@
             mTitleMarginBottom = marginBottom;
         }
 
+        mMaxButtonHeight = a.getDimensionPixelSize(R.styleable.Toolbar_maxButtonHeight, -1);
+
         final int contentInsetStart =
                 a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetStart,
                         RtlSpacingHelper.UNDEFINED);
@@ -180,6 +211,8 @@
             mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
         }
 
+        mCollapseIcon = a.getDrawable(R.styleable.Toolbar_collapseIcon);
+
         final CharSequence title = a.getText(R.styleable.Toolbar_title);
         if (!TextUtils.isEmpty(title)) {
             setTitle(title);
@@ -211,6 +244,110 @@
         setLogo(getContext().getDrawable(resId));
     }
 
+    /** @hide */
+    public boolean canShowOverflowMenu() {
+        return getVisibility() == VISIBLE && mMenuView != null && mMenuView.isOverflowReserved();
+    }
+
+    /**
+     * Check whether the overflow menu is currently showing. This may not reflect
+     * a pending show operation in progress.
+     *
+     * @return true if the overflow menu is currently showing
+     */
+    public boolean isOverflowMenuShowing() {
+        return mMenuView != null && mMenuView.isOverflowMenuShowing();
+    }
+
+    /** @hide */
+    public boolean isOverflowMenuShowPending() {
+        return mMenuView != null && mMenuView.isOverflowMenuShowPending();
+    }
+
+    /**
+     * Show the overflow items from the associated menu.
+     *
+     * @return true if the menu was able to be shown, false otherwise
+     */
+    public boolean showOverflowMenu() {
+        return mMenuView != null && mMenuView.showOverflowMenu();
+    }
+
+    /**
+     * Hide the overflow items from the associated menu.
+     *
+     * @return true if the menu was able to be hidden, false otherwise
+     */
+    public boolean hideOverflowMenu() {
+        return mMenuView != null && mMenuView.hideOverflowMenu();
+    }
+
+    /** @hide */
+    public void setMenu(MenuBuilder menu, ActionMenuPresenter outerPresenter) {
+        if (menu == null && mMenuView == null) {
+            return;
+        }
+
+        ensureMenuView();
+        final MenuBuilder oldMenu = mMenuView.peekMenu();
+        if (oldMenu == menu) {
+            return;
+        }
+
+        if (oldMenu != null) {
+            oldMenu.removeMenuPresenter(mOuterActionMenuPresenter);
+            oldMenu.removeMenuPresenter(mExpandedMenuPresenter);
+        }
+
+        final Context context = getContext();
+
+        if (mExpandedMenuPresenter == null) {
+            mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();
+        }
+
+        outerPresenter.setExpandedActionViewsExclusive(true);
+        if (menu != null) {
+            menu.addMenuPresenter(outerPresenter);
+            menu.addMenuPresenter(mExpandedMenuPresenter);
+        } else {
+            outerPresenter.initForMenu(context, null);
+            mExpandedMenuPresenter.initForMenu(context, null);
+            outerPresenter.updateMenuView(true);
+            mExpandedMenuPresenter.updateMenuView(true);
+        }
+        mMenuView.setPresenter(outerPresenter);
+        mOuterActionMenuPresenter = outerPresenter;
+    }
+
+    /**
+     * Dismiss all currently showing popup menus, including overflow or submenus.
+     */
+    public void dismissPopupMenus() {
+        if (mMenuView != null) {
+            mMenuView.dismissPopupMenus();
+        }
+    }
+
+    /** @hide */
+    public boolean isTitleTruncated() {
+        if (mTitleTextView == null) {
+            return false;
+        }
+
+        final Layout titleLayout = mTitleTextView.getLayout();
+        if (titleLayout == null) {
+            return false;
+        }
+
+        final int lineCount = titleLayout.getLineCount();
+        for (int i = 0; i < lineCount; i++) {
+            if (titleLayout.getEllipsisCount(i) > 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Set a logo drawable.
      *
@@ -222,9 +359,7 @@
      */
     public void setLogo(Drawable drawable) {
         if (drawable != null) {
-            if (mLogoView == null) {
-                mLogoView = new ImageView(getContext());
-            }
+            ensureLogoView();
             if (mLogoView.getParent() == null) {
                 addSystemView(mLogoView);
             }
@@ -268,8 +403,8 @@
      * @param description Description to set
      */
     public void setLogoDescription(CharSequence description) {
-        if (!TextUtils.isEmpty(description) && mLogoView == null) {
-            mLogoView = new ImageView(getContext());
+        if (!TextUtils.isEmpty(description)) {
+            ensureLogoView();
         }
         if (mLogoView != null) {
             mLogoView.setContentDescription(description);
@@ -285,10 +420,48 @@
         return mLogoView != null ? mLogoView.getContentDescription() : null;
     }
 
+    private void ensureLogoView() {
+        if (mLogoView == null) {
+            mLogoView = new ImageView(getContext());
+        }
+    }
+
     /**
-     * Return the current title displayed in the toolbar.
+     * Check whether this Toolbar is currently hosting an expanded action view.
      *
-     * @return The current title
+     * <p>An action view may be expanded either directly from the
+     * {@link android.view.MenuItem MenuItem} it belongs to or by user action. If the Toolbar
+     * has an expanded action view it can be collapsed using the {@link #collapseActionView()}
+     * method.</p>
+     *
+     * @return true if the Toolbar has an expanded action view
+     */
+    public boolean hasExpandedActionView() {
+        return mExpandedMenuPresenter != null &&
+                mExpandedMenuPresenter.mCurrentExpandedItem != null;
+    }
+
+    /**
+     * Collapse a currently expanded action view. If this Toolbar does not have an
+     * expanded action view this method has no effect.
+     *
+     * <p>An action view may be expanded either directly from the
+     * {@link android.view.MenuItem MenuItem} it belongs to or by user action.</p>
+     *
+     * @see #hasExpandedActionView()
+     */
+    public void collapseActionView() {
+        final MenuItemImpl item = mExpandedMenuPresenter == null ? null :
+                mExpandedMenuPresenter.mCurrentExpandedItem;
+        if (item != null) {
+            item.collapseActionView();
+        }
+    }
+
+    /**
+     * Returns the title of this toolbar.
+     *
+     * @return The current title.
      */
     public CharSequence getTitle() {
         return mTitleText;
@@ -319,6 +492,8 @@
             if (mTitleTextView == null) {
                 final Context context = getContext();
                 mTitleTextView = new TextView(context);
+                mTitleTextView.setSingleLine();
+                mTitleTextView.setEllipsize(TextUtils.TruncateAt.END);
                 mTitleTextView.setTextAppearance(context, mTitleTextAppearance);
             }
             if (mTitleTextView.getParent() == null) {
@@ -365,6 +540,8 @@
             if (mSubtitleTextView == null) {
                 final Context context = getContext();
                 mSubtitleTextView = new TextView(context);
+                mSubtitleTextView.setSingleLine();
+                mSubtitleTextView.setEllipsize(TextUtils.TruncateAt.END);
                 mSubtitleTextView.setTextAppearance(context, mSubtitleTextAppearance);
             }
             if (mSubtitleTextView.getParent() == null) {
@@ -395,6 +572,30 @@
     }
 
     /**
+     * Set a content description for the navigation button if one is present. The content
+     * description will be read via screen readers or other accessibility systems to explain
+     * the action of the navigation button.
+     *
+     * @param description Content description to set
+     */
+    public void setNavigationContentDescription(CharSequence description) {
+        ensureNavButtonView();
+        mNavButtonView.setContentDescription(description);
+    }
+
+    /**
+     * Set a content description for the navigation button if one is present. The content
+     * description will be read via screen readers or other accessibility systems to explain
+     * the action of the navigation button.
+     *
+     * @param resId Resource ID of a content description string to set
+     */
+    public void setNavigationContentDescription(int resId) {
+        ensureNavButtonView();
+        mNavButtonView.setContentDescription(resId != 0 ? getContext().getText(resId) : null);
+    }
+
+    /**
      * Set the icon to use for the toolbar's navigation button.
      *
      * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
@@ -480,12 +681,19 @@
      * @return The toolbar's Menu
      */
     public Menu getMenu() {
+        ensureMenuView();
+        return mMenuView.getMenu();
+    }
+
+    private void ensureMenuView() {
         if (mMenuView == null) {
             mMenuView = new ActionMenuView(getContext());
             mMenuView.setOnMenuItemClickListener(mMenuViewItemClickListener);
+            final LayoutParams lp = generateDefaultLayoutParams();
+            lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
+            mMenuView.setLayoutParams(lp);
             addSystemView(mMenuView);
         }
-        return mMenuView.getMenu();
     }
 
     private MenuInflater getMenuInflater() {
@@ -634,7 +842,27 @@
 
     private void ensureNavButtonView() {
         if (mNavButtonView == null) {
-            mNavButtonView = new ImageButton(getContext(), null, R.attr.borderlessButtonStyle);
+            mNavButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
+            final LayoutParams lp = generateDefaultLayoutParams();
+            lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
+            mNavButtonView.setLayoutParams(lp);
+        }
+    }
+
+    private void ensureCollapseButtonView() {
+        if (mCollapseButtonView == null) {
+            mCollapseButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
+            mCollapseButtonView.setImageDrawable(mCollapseIcon);
+            final LayoutParams lp = generateDefaultLayoutParams();
+            lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
+            lp.mViewType = LayoutParams.EXPANDED;
+            mCollapseButtonView.setLayoutParams(lp);
+            mCollapseButtonView.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    collapseActionView();
+                }
+            });
         }
     }
 
@@ -657,6 +885,27 @@
         super.onRestoreInstanceState(ss.getSuperState());
     }
 
+    private void measureChildConstrained(View child, int parentWidthSpec, int widthUsed,
+            int parentHeightSpec, int heightUsed, int heightConstraint) {
+        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+
+        int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
+                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
+                        + widthUsed, lp.width);
+        int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
+                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
+                        + heightUsed, lp.height);
+
+        final int childHeightMode = MeasureSpec.getMode(childHeightSpec);
+        if (childHeightMode != MeasureSpec.EXACTLY && heightConstraint >= 0) {
+            final int size = childHeightMode != MeasureSpec.UNSPECIFIED ?
+                    Math.min(MeasureSpec.getSize(childHeightSpec), heightConstraint) :
+                    heightConstraint;
+            childHeightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+        }
+        child.measure(childWidthSpec, childHeightSpec);
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = 0;
@@ -667,18 +916,30 @@
 
         int navWidth = 0;
         if (shouldLayout(mNavButtonView)) {
-            measureChildWithMargins(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0);
+            measureChildConstrained(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0,
+                    mMaxButtonHeight);
             navWidth = mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
             height = Math.max(height, mNavButtonView.getMeasuredHeight() +
                     getVerticalMargins(mNavButtonView));
             childState = combineMeasuredStates(childState, mNavButtonView.getMeasuredState());
         }
 
+        if (shouldLayout(mCollapseButtonView)) {
+            measureChildConstrained(mCollapseButtonView, widthMeasureSpec, width,
+                    heightMeasureSpec, 0, mMaxButtonHeight);
+            navWidth = mCollapseButtonView.getMeasuredWidth() +
+                    getHorizontalMargins(mCollapseButtonView);
+            height = Math.max(height, mCollapseButtonView.getMeasuredHeight() +
+                    getVerticalMargins(mCollapseButtonView));
+            childState = combineMeasuredStates(childState, mCollapseButtonView.getMeasuredState());
+        }
+
         width += Math.max(getContentInsetStart(), navWidth);
 
         int menuWidth = 0;
         if (shouldLayout(mMenuView)) {
-            measureChildWithMargins(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0);
+            measureChildConstrained(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0,
+                    mMaxButtonHeight);
             menuWidth = mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
             height = Math.max(height, mMenuView.getMeasuredHeight() +
                     getVerticalMargins(mMenuView));
@@ -687,6 +948,16 @@
 
         width += Math.max(getContentInsetEnd(), menuWidth);
 
+        if (shouldLayout(mExpandedActionView)) {
+            measureChildWithMargins(mExpandedActionView, widthMeasureSpec, width,
+                    heightMeasureSpec, 0);
+            width += mExpandedActionView.getMeasuredWidth() +
+                    getHorizontalMargins(mExpandedActionView);
+            height = Math.max(height, mExpandedActionView.getMeasuredHeight() +
+                    getVerticalMargins(mExpandedActionView));
+            childState = combineMeasuredStates(childState, mExpandedActionView.getMeasuredState());
+        }
+
         if (shouldLayout(mLogoView)) {
             measureChildWithMargins(mLogoView, widthMeasureSpec, width, heightMeasureSpec, 0);
             width += mLogoView.getMeasuredWidth() + getHorizontalMargins(mLogoView);
@@ -723,7 +994,7 @@
         for (int i = 0; i < childCount; i++) {
             final View child = getChildAt(i);
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            if (lp.mViewType == LayoutParams.SYSTEM || !shouldLayout(child)) {
+            if (lp.mViewType != LayoutParams.CUSTOM || !shouldLayout(child)) {
                 // We already got all system views above. Skip them and GONE views.
                 continue;
             }
@@ -768,6 +1039,14 @@
             }
         }
 
+        if (shouldLayout(mCollapseButtonView)) {
+            if (isRtl) {
+                right = layoutChildRight(mCollapseButtonView, right);
+            } else {
+                left = layoutChildLeft(mCollapseButtonView, left);
+            }
+        }
+
         if (shouldLayout(mMenuView)) {
             if (isRtl) {
                 left = layoutChildLeft(mMenuView, left);
@@ -779,6 +1058,14 @@
         left = Math.max(left, getContentInsetLeft());
         right = Math.min(right, width - paddingRight - getContentInsetRight());
 
+        if (shouldLayout(mExpandedActionView)) {
+            if (isRtl) {
+                right = layoutChildRight(mExpandedActionView, right);
+            } else {
+                left = layoutChildLeft(mExpandedActionView, left);
+            }
+        }
+
         if (shouldLayout(mLogoView)) {
             if (isRtl) {
                 right = layoutChildRight(mLogoView, right);
@@ -801,40 +1088,42 @@
 
         if (layoutTitle || layoutSubtitle) {
             int titleTop;
+            final View topChild = layoutTitle ? mTitleTextView : mSubtitleTextView;
+            final View bottomChild = layoutSubtitle ? mSubtitleTextView : mTitleTextView;
+            final LayoutParams toplp = (LayoutParams) topChild.getLayoutParams();
+            final LayoutParams bottomlp = (LayoutParams) bottomChild.getLayoutParams();
+
             switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
                 case Gravity.TOP:
-                    titleTop = getPaddingTop();
+                    titleTop = getPaddingTop() + toplp.topMargin + mTitleMarginTop;
                     break;
                 default:
                 case Gravity.CENTER_VERTICAL:
-                    final View child = layoutTitle ? mTitleTextView : mSubtitleTextView;
-                    final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                     final int space = height - paddingTop - paddingBottom;
                     int spaceAbove = (space - titleHeight) / 2;
-                    if (spaceAbove < lp.topMargin + mTitleMarginTop) {
-                        spaceAbove = lp.topMargin + mTitleMarginTop;
+                    if (spaceAbove < toplp.topMargin + mTitleMarginTop) {
+                        spaceAbove = toplp.topMargin + mTitleMarginTop;
                     } else {
                         final int spaceBelow = height - paddingBottom - titleHeight -
                                 spaceAbove - paddingTop;
-                        if (spaceBelow < lp.bottomMargin + mTitleMarginBottom) {
+                        if (spaceBelow < toplp.bottomMargin + mTitleMarginBottom) {
                             spaceAbove = Math.max(0, spaceAbove -
-                                    (lp.bottomMargin + mTitleMarginBottom - spaceBelow));
+                                    (bottomlp.bottomMargin + mTitleMarginBottom - spaceBelow));
                         }
                     }
                     titleTop = paddingTop + spaceAbove;
                     break;
                 case Gravity.BOTTOM:
-                    titleTop = height - paddingBottom - titleHeight;
+                    titleTop = height - paddingBottom - bottomlp.bottomMargin - mTitleMarginBottom -
+                            titleHeight;
                     break;
             }
             if (isRtl) {
                 int titleRight = right;
                 int subtitleRight = right;
-                titleTop += mTitleMarginTop;
                 if (layoutTitle) {
                     final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
                     titleRight -= lp.rightMargin + mTitleMarginStart;
-                    titleTop += lp.topMargin;
                     final int titleLeft = titleRight - mTitleTextView.getMeasuredWidth();
                     final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight();
                     mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom);
@@ -855,11 +1144,9 @@
             } else {
                 int titleLeft = left;
                 int subtitleLeft = left;
-                titleTop += mTitleMarginTop;
                 if (layoutTitle) {
                     final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
                     titleLeft += lp.leftMargin + mTitleMarginStart;
-                    titleTop += lp.topMargin;
                     final int titleRight = titleLeft + mTitleTextView.getMeasuredWidth();
                     final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight();
                     mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom);
@@ -897,7 +1184,7 @@
 
         // Centered views try to center with respect to the whole bar, but views pinned
         // to the left or right can push the mass of centered views to one side or the other.
-        addCustomViewsWithGravity(mTempViews, Gravity.CENTER);
+        addCustomViewsWithGravity(mTempViews, Gravity.CENTER_HORIZONTAL);
         final int centerViewsWidth = getViewListMeasuredWidth(mTempViews);
         final int parentCenter = paddingLeft + (width - paddingLeft - paddingRight) / 2;
         final int halfCenterViewsWidth = centerViewsWidth / 2;
@@ -1007,17 +1294,16 @@
             for (int i = childCount - 1; i >= 0; i--) {
                 final View child = getChildAt(i);
                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                if (lp.mViewType != LayoutParams.SYSTEM && shouldLayout(child) &&
+                if (lp.mViewType == LayoutParams.CUSTOM && shouldLayout(child) &&
                         getChildHorizontalGravity(lp.gravity) == absGrav) {
                     views.add(child);
                 }
-
             }
         } else {
             for (int i = 0; i < childCount; i++) {
                 final View child = getChildAt(i);
                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                if (lp.mViewType != LayoutParams.SYSTEM && shouldLayout(child) &&
+                if (lp.mViewType == LayoutParams.CUSTOM && shouldLayout(child) &&
                         getChildHorizontalGravity(lp.gravity) == absGrav) {
                     views.add(child);
                 }
@@ -1054,14 +1340,16 @@
     }
 
     @Override
-    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return super.generateLayoutParams(attrs);
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
     }
 
     @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
         if (p instanceof LayoutParams) {
             return new LayoutParams((LayoutParams) p);
+        } else if (p instanceof ActionBar.LayoutParams) {
+            return new LayoutParams((ActionBar.LayoutParams) p);
         } else if (p instanceof MarginLayoutParams) {
             return new LayoutParams((MarginLayoutParams) p);
         } else {
@@ -1070,7 +1358,7 @@
     }
 
     @Override
-    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+    protected LayoutParams generateDefaultLayoutParams() {
         return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
     }
 
@@ -1083,6 +1371,25 @@
         return ((LayoutParams) child.getLayoutParams()).mViewType == LayoutParams.CUSTOM;
     }
 
+    /** @hide */
+    public DecorToolbar getWrapper() {
+        if (mWrapper == null) {
+            mWrapper = new ToolbarWidgetWrapper(this);
+        }
+        return mWrapper;
+    }
+
+    private void setChildVisibilityForExpandedActionView(boolean expand) {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) {
+                child.setVisibility(expand ? GONE : VISIBLE);
+            }
+        }
+    }
+
     /**
      * Interface responsible for receiving menu item click events if the items themselves
      * do not have individual item click listeners.
@@ -1103,44 +1410,15 @@
      *
      * @attr ref android.R.styleable#Toolbar_LayoutParams_layout_gravity
      */
-    public static class LayoutParams extends MarginLayoutParams {
-        /**
-         * Gravity for the view associated with these LayoutParams.
-         *
-         * @see android.view.Gravity
-         */
-        @ViewDebug.ExportedProperty(category = "layout", mapping = {
-                @ViewDebug.IntToString(from =  -1,                       to = "NONE"),
-                @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),
-                @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),
-                @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
-                @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),
-                @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),
-                @ViewDebug.IntToString(from = Gravity.START,             to = "START"),
-                @ViewDebug.IntToString(from = Gravity.END,               to = "END"),
-                @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),
-                @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),
-                @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
-                @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL,   to = "FILL_HORIZONTAL"),
-                @ViewDebug.IntToString(from = Gravity.CENTER,            to = "CENTER"),
-                @ViewDebug.IntToString(from = Gravity.FILL,              to = "FILL")
-        })
-        public int gravity = Gravity.NO_GRAVITY;
-
+    public static class LayoutParams extends ActionBar.LayoutParams {
         static final int CUSTOM = 0;
         static final int SYSTEM = 1;
+        static final int EXPANDED = 2;
 
         int mViewType = CUSTOM;
 
         public LayoutParams(@NonNull Context c, AttributeSet attrs) {
             super(c, attrs);
-
-            TypedArray a = c.obtainStyledAttributes(attrs,
-                    com.android.internal.R.styleable.Toolbar_LayoutParams);
-            gravity = a.getInt(
-                    com.android.internal.R.styleable.Toolbar_LayoutParams_layout_gravity,
-                    Gravity.NO_GRAVITY);
-            a.recycle();
         }
 
         public LayoutParams(int width, int height) {
@@ -1160,7 +1438,11 @@
         public LayoutParams(LayoutParams source) {
             super(source);
 
-            this.gravity = source.gravity;
+            mViewType = source.mViewType;
+        }
+
+        public LayoutParams(ActionBar.LayoutParams source) {
+            super(source);
         }
 
         public LayoutParams(MarginLayoutParams source) {
@@ -1199,4 +1481,126 @@
             }
         };
     }
+
+    private class ExpandedActionViewMenuPresenter implements MenuPresenter {
+        MenuBuilder mMenu;
+        MenuItemImpl mCurrentExpandedItem;
+
+        @Override
+        public void initForMenu(Context context, MenuBuilder menu) {
+            // Clear the expanded action view when menus change.
+            if (mMenu != null && mCurrentExpandedItem != null) {
+                mMenu.collapseItemActionView(mCurrentExpandedItem);
+            }
+            mMenu = menu;
+        }
+
+        @Override
+        public MenuView getMenuView(ViewGroup root) {
+            return null;
+        }
+
+        @Override
+        public void updateMenuView(boolean cleared) {
+            // Make sure the expanded item we have is still there.
+            if (mCurrentExpandedItem != null) {
+                boolean found = false;
+
+                if (mMenu != null) {
+                    final int count = mMenu.size();
+                    for (int i = 0; i < count; i++) {
+                        final MenuItem item = mMenu.getItem(i);
+                        if (item == mCurrentExpandedItem) {
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+
+                if (!found) {
+                    // The item we had expanded disappeared. Collapse.
+                    collapseItemActionView(mMenu, mCurrentExpandedItem);
+                }
+            }
+        }
+
+        @Override
+        public void setCallback(Callback cb) {
+        }
+
+        @Override
+        public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+            return false;
+        }
+
+        @Override
+        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        }
+
+        @Override
+        public boolean flagActionItems() {
+            return false;
+        }
+
+        @Override
+        public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            ensureCollapseButtonView();
+            if (mCollapseButtonView.getParent() != Toolbar.this) {
+                addView(mCollapseButtonView);
+            }
+            mExpandedActionView = item.getActionView();
+            mCurrentExpandedItem = item;
+            if (mExpandedActionView.getParent() != Toolbar.this) {
+                final LayoutParams lp = generateDefaultLayoutParams();
+                lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
+                lp.mViewType = LayoutParams.EXPANDED;
+                mExpandedActionView.setLayoutParams(lp);
+                addView(mExpandedActionView);
+            }
+
+            setChildVisibilityForExpandedActionView(true);
+            requestLayout();
+            item.setActionViewExpanded(true);
+
+            if (mExpandedActionView instanceof CollapsibleActionView) {
+                ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded();
+            }
+
+            return true;
+        }
+
+        @Override
+        public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            // Do this before detaching the actionview from the hierarchy, in case
+            // it needs to dismiss the soft keyboard, etc.
+            if (mExpandedActionView instanceof CollapsibleActionView) {
+                ((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed();
+            }
+
+            removeView(mExpandedActionView);
+            removeView(mCollapseButtonView);
+            mExpandedActionView = null;
+
+            setChildVisibilityForExpandedActionView(false);
+            mCurrentExpandedItem = null;
+            requestLayout();
+            item.setActionViewExpanded(false);
+
+            return true;
+        }
+
+        @Override
+        public int getId() {
+            return 0;
+        }
+
+        @Override
+        public Parcelable onSaveInstanceState() {
+            return null;
+        }
+
+        @Override
+        public void onRestoreInstanceState(Parcelable state) {
+        }
+    }
 }
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 41f3337..7e11850 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1100,7 +1100,7 @@
 
     public boolean evaluateSystemProperties(boolean update) {
         boolean changed = false;
-        String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.1",
+        String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.2",
                 VMRuntime.getRuntime().vmLibrary());
         if (!Objects.equals(runtime, mRuntime)) {
             changed = true;
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index a238ae3..5c7a4e6 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -18,7 +18,10 @@
 
 import android.animation.ValueAnimator;
 import android.content.res.TypedArray;
+import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.widget.AdapterView;
+import android.widget.Toolbar;
 import com.android.internal.R;
 import com.android.internal.view.ActionBarPolicy;
 import com.android.internal.view.menu.MenuBuilder;
@@ -28,6 +31,7 @@
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.ActionBarOverlayLayout;
 import com.android.internal.widget.ActionBarView;
+import com.android.internal.widget.DecorToolbar;
 import com.android.internal.widget.ScrollingTabContainerView;
 
 import android.animation.Animator;
@@ -55,6 +59,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.widget.SpinnerAdapter;
+import com.android.internal.widget.ToolbarWidgetWrapper;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -77,7 +82,7 @@
 
     private ActionBarOverlayLayout mOverlayLayout;
     private ActionBarContainer mContainerView;
-    private ActionBarView mActionView;
+    private DecorToolbar mDecorToolbar;
     private ActionBarContextView mContextView;
     private ActionBarContainer mSplitView;
     private View mContentView;
@@ -187,7 +192,7 @@
         if (mOverlayLayout != null) {
             mOverlayLayout.setActionBarVisibilityCallback(this);
         }
-        mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
+        mDecorToolbar = getDecorToolbar(decor.findViewById(com.android.internal.R.id.action_bar));
         mContextView = (ActionBarContextView) decor.findViewById(
                 com.android.internal.R.id.action_context_bar);
         mContainerView = (ActionBarContainer) decor.findViewById(
@@ -195,18 +200,17 @@
         mSplitView = (ActionBarContainer) decor.findViewById(
                 com.android.internal.R.id.split_action_bar);
 
-        if (mActionView == null || mContextView == null || mContainerView == null) {
+        if (mDecorToolbar == null || mContextView == null || mContainerView == null) {
             throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
                     "with a compatible window decor layout");
         }
 
-        mContext = mActionView.getContext();
-        mActionView.setContextView(mContextView);
-        mContextDisplayMode = mActionView.isSplitActionBar() ?
+        mContext = mDecorToolbar.getContext();
+        mContextDisplayMode = mDecorToolbar.isSplit() ?
                 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
 
         // This was initially read from the action bar style
-        final int current = mActionView.getDisplayOptions();
+        final int current = mDecorToolbar.getDisplayOptions();
         final boolean homeAsUp = (current & DISPLAY_HOME_AS_UP) != 0;
         if (homeAsUp) {
             mDisplayHomeAsUpSet = true;
@@ -225,6 +229,17 @@
         a.recycle();
     }
 
+    private DecorToolbar getDecorToolbar(View view) {
+        if (view instanceof DecorToolbar) {
+            return (DecorToolbar) view;
+        } else if (view instanceof Toolbar) {
+            return ((Toolbar) view).getWrapper();
+        } else {
+            throw new IllegalStateException("Can't make a decor toolbar out of " +
+                    view.getClass().getSimpleName());
+        }
+    }
+
     public void onConfigurationChanged(Configuration newConfig) {
         setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs());
     }
@@ -233,11 +248,11 @@
         mHasEmbeddedTabs = hasEmbeddedTabs;
         // Switch tab layout configuration if needed
         if (!mHasEmbeddedTabs) {
-            mActionView.setEmbeddedTabView(null);
+            mDecorToolbar.setEmbeddedTabView(null);
             mContainerView.setTabContainer(mTabScrollView);
         } else {
             mContainerView.setTabContainer(null);
-            mActionView.setEmbeddedTabView(mTabScrollView);
+            mDecorToolbar.setEmbeddedTabView(mTabScrollView);
         }
         final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS;
         if (mTabScrollView != null) {
@@ -250,7 +265,7 @@
                 mTabScrollView.setVisibility(View.GONE);
             }
         }
-        mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode);
+        mDecorToolbar.setCollapsible(!mHasEmbeddedTabs && isInTabMode);
         mOverlayLayout.setHasNonEmbeddedTabs(!mHasEmbeddedTabs && isInTabMode);
     }
 
@@ -263,7 +278,7 @@
 
         if (mHasEmbeddedTabs) {
             tabScroller.setVisibility(View.VISIBLE);
-            mActionView.setEmbeddedTabView(tabScroller);
+            mDecorToolbar.setEmbeddedTabView(tabScroller);
         } else {
             if (getNavigationMode() == NAVIGATION_MODE_TABS) {
                 tabScroller.setVisibility(View.VISIBLE);
@@ -326,7 +341,8 @@
 
     @Override
     public void setCustomView(int resId) {
-        setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId, mActionView, false));
+        setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId,
+                mDecorToolbar.getViewGroup(), false));
     }
 
     @Override
@@ -356,7 +372,7 @@
 
     @Override
     public void setHomeButtonEnabled(boolean enable) {
-        mActionView.setHomeButtonEnabled(enable);
+        mDecorToolbar.setHomeButtonEnabled(enable);
     }
 
     @Override
@@ -370,12 +386,12 @@
     }
 
     public void setSelectedNavigationItem(int position) {
-        switch (mActionView.getNavigationMode()) {
+        switch (mDecorToolbar.getNavigationMode()) {
         case NAVIGATION_MODE_TABS:
             selectTab(mTabs.get(position));
             break;
         case NAVIGATION_MODE_LIST:
-            mActionView.setDropdownSelectedPosition(position);
+            mDecorToolbar.setDropdownSelectedPosition(position);
             break;
         default:
             throw new IllegalStateException(
@@ -399,26 +415,26 @@
     }
 
     public void setTitle(CharSequence title) {
-        mActionView.setTitle(title);
+        mDecorToolbar.setTitle(title);
     }
 
     public void setSubtitle(CharSequence subtitle) {
-        mActionView.setSubtitle(subtitle);
+        mDecorToolbar.setSubtitle(subtitle);
     }
 
     public void setDisplayOptions(int options) {
         if ((options & DISPLAY_HOME_AS_UP) != 0) {
             mDisplayHomeAsUpSet = true;
         }
-        mActionView.setDisplayOptions(options);
+        mDecorToolbar.setDisplayOptions(options);
     }
 
     public void setDisplayOptions(int options, int mask) {
-        final int current = mActionView.getDisplayOptions(); 
+        final int current = mDecorToolbar.getDisplayOptions();
         if ((mask & DISPLAY_HOME_AS_UP) != 0) {
             mDisplayHomeAsUpSet = true;
         }
-        mActionView.setDisplayOptions((options & mask) | (current & ~mask));
+        mDecorToolbar.setDisplayOptions((options & mask) | (current & ~mask));
     }
 
     public void setBackgroundDrawable(Drawable d) {
@@ -436,23 +452,23 @@
     }
 
     public View getCustomView() {
-        return mActionView.getCustomNavigationView();
+        return mDecorToolbar.getCustomView();
     }
 
     public CharSequence getTitle() {
-        return mActionView.getTitle();
+        return mDecorToolbar.getTitle();
     }
 
     public CharSequence getSubtitle() {
-        return mActionView.getSubtitle();
+        return mDecorToolbar.getSubtitle();
     }
 
     public int getNavigationMode() {
-        return mActionView.getNavigationMode();
+        return mDecorToolbar.getNavigationMode();
     }
 
     public int getDisplayOptions() {
-        return mActionView.getDisplayOptions();
+        return mDecorToolbar.getDisplayOptions();
     }
 
     public ActionMode startActionMode(ActionMode.Callback callback) {
@@ -572,7 +588,7 @@
             return;
         }
 
-        final FragmentTransaction trans = mActionView.isInEditMode() ? null :
+        final FragmentTransaction trans = ((View) mDecorToolbar).isInEditMode() ? null :
                 mActivity.getFragmentManager().beginTransaction().disallowAddToBackStack();
 
         if (mSelectedTab == tab) {
@@ -828,13 +844,18 @@
             hideForActionMode();
         }
 
-        mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
+        mDecorToolbar.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
         mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
-        if (mTabScrollView != null && !mActionView.hasEmbeddedTabs() && mActionView.isCollapsed()) {
+        if (mTabScrollView != null && !mDecorToolbar.hasEmbeddedTabs() &&
+                isCollapsed((View) mDecorToolbar)) {
             mTabScrollView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
         }
     }
 
+    private boolean isCollapsed(View view) {
+        return view == null || view.getVisibility() == View.GONE || view.getMeasuredHeight() == 0;
+    }
+
     public Context getThemedContext() {
         if (mThemedContext == null) {
             TypedValue outValue = new TypedValue();
@@ -854,27 +875,27 @@
     
     @Override
     public boolean isTitleTruncated() {
-        return mActionView != null && mActionView.isTitleTruncated();
+        return mDecorToolbar != null && mDecorToolbar.isTitleTruncated();
     }
 
     @Override
     public void setHomeAsUpIndicator(Drawable indicator) {
-        mActionView.setHomeAsUpIndicator(indicator);
+        mDecorToolbar.setNavigationIcon(indicator);
     }
 
     @Override
     public void setHomeAsUpIndicator(int resId) {
-        mActionView.setHomeAsUpIndicator(resId);
+        mDecorToolbar.setNavigationIcon(resId);
     }
 
     @Override
     public void setHomeActionContentDescription(CharSequence description) {
-        mActionView.setHomeActionContentDescription(description);
+        mDecorToolbar.setNavigationContentDescription(description);
     }
 
     @Override
     public void setHomeActionContentDescription(int resId) {
-        mActionView.setHomeActionContentDescription(resId);
+        mDecorToolbar.setNavigationContentDescription(resId);
     }
 
     @Override
@@ -938,7 +959,8 @@
 
             // Clear out the context mode views after the animation finishes
             mContextView.closeMode();
-            mActionView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+            ((View) mDecorToolbar).sendAccessibilityEvent(
+                    AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
             mOverlayLayout.setHideOnContentScrollEnabled(mHideOnContentScroll);
 
             mActionMode = null;
@@ -1178,28 +1200,27 @@
 
     @Override
     public void setCustomView(View view) {
-        mActionView.setCustomNavigationView(view);
+        mDecorToolbar.setCustomView(view);
     }
 
     @Override
     public void setCustomView(View view, LayoutParams layoutParams) {
         view.setLayoutParams(layoutParams);
-        mActionView.setCustomNavigationView(view);
+        mDecorToolbar.setCustomView(view);
     }
 
     @Override
     public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
-        mActionView.setDropdownAdapter(adapter);
-        mActionView.setCallback(callback);
+        mDecorToolbar.setDropdownParams(adapter, new NavItemSelectedListener(callback));
     }
 
     @Override
     public int getSelectedNavigationIndex() {
-        switch (mActionView.getNavigationMode()) {
+        switch (mDecorToolbar.getNavigationMode()) {
             case NAVIGATION_MODE_TABS:
                 return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
             case NAVIGATION_MODE_LIST:
-                return mActionView.getDropdownSelectedPosition();
+                return mDecorToolbar.getDropdownSelectedPosition();
             default:
                 return -1;
         }
@@ -1207,12 +1228,11 @@
 
     @Override
     public int getNavigationItemCount() {
-        switch (mActionView.getNavigationMode()) {
+        switch (mDecorToolbar.getNavigationMode()) {
             case NAVIGATION_MODE_TABS:
                 return mTabs.size();
             case NAVIGATION_MODE_LIST:
-                SpinnerAdapter adapter = mActionView.getDropdownAdapter();
-                return adapter != null ? adapter.getCount() : 0;
+                return mDecorToolbar.getDropdownItemCount();
             default:
                 return 0;
         }
@@ -1225,7 +1245,7 @@
 
     @Override
     public void setNavigationMode(int mode) {
-        final int oldMode = mActionView.getNavigationMode();
+        final int oldMode = mDecorToolbar.getNavigationMode();
         switch (oldMode) {
             case NAVIGATION_MODE_TABS:
                 mSavedTabPosition = getSelectedNavigationIndex();
@@ -1238,7 +1258,7 @@
                 mOverlayLayout.requestFitSystemWindows();
             }
         }
-        mActionView.setNavigationMode(mode);
+        mDecorToolbar.setNavigationMode(mode);
         switch (mode) {
             case NAVIGATION_MODE_TABS:
                 ensureTabsExist();
@@ -1249,7 +1269,7 @@
                 }
                 break;
         }
-        mActionView.setCollapsable(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
+        mDecorToolbar.setCollapsible(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
         mOverlayLayout.setHasNonEmbeddedTabs(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
     }
 
@@ -1261,30 +1281,30 @@
 
     @Override
     public void setIcon(int resId) {
-        mActionView.setIcon(resId);
+        mDecorToolbar.setIcon(resId);
     }
 
     @Override
     public void setIcon(Drawable icon) {
-        mActionView.setIcon(icon);
+        mDecorToolbar.setIcon(icon);
     }
 
     public boolean hasIcon() {
-        return mActionView.hasIcon();
+        return mDecorToolbar.hasIcon();
     }
 
     @Override
     public void setLogo(int resId) {
-        mActionView.setLogo(resId);
+        mDecorToolbar.setLogo(resId);
     }
 
     @Override
     public void setLogo(Drawable logo) {
-        mActionView.setLogo(logo);
+        mDecorToolbar.setLogo(logo);
     }
 
     public boolean hasLogo() {
-        return mActionView.hasLogo();
+        return mDecorToolbar.hasLogo();
     }
 
     public void setDefaultDisplayHomeAsUpEnabled(boolean enable) {
@@ -1292,4 +1312,24 @@
             setDisplayHomeAsUpEnabled(enable);
         }
     }
+
+    static class NavItemSelectedListener implements AdapterView.OnItemSelectedListener {
+        private final OnNavigationListener mListener;
+
+        public NavItemSelectedListener(OnNavigationListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+            if (mListener != null) {
+                mListener.onNavigationItemSelected(position, id);
+            }
+        }
+
+        @Override
+        public void onNothingSelected(AdapterView<?> parent) {
+            // Do nothing
+        }
+    }
 }
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index b78c70f..f22800c 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -56,4 +56,10 @@
     oneway void dispatch(in MotionEvent event);
     oneway void launchCamera();
     oneway void onBootCompleted();
+
+    /**
+     * Notifies that the activity behind has now been drawn and it's safe to remove the wallpaper
+     * and keyguard flag.
+     */
+    oneway void startKeyguardExitAnimation(long fadeoutDuration);
 }
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index 183478f..9e7ff93 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -34,7 +34,7 @@
 public abstract class AbsActionBarView extends ViewGroup {
     protected ActionMenuView mMenuView;
     protected ActionMenuPresenter mActionMenuPresenter;
-    protected ActionBarContainer mSplitView;
+    protected ViewGroup mSplitView;
     protected boolean mSplitActionBar;
     protected boolean mSplitWhenNarrow;
     protected int mContentHeight;
@@ -74,7 +74,7 @@
         setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0));
         a.recycle();
         if (mSplitWhenNarrow) {
-            setSplitActionBar(getContext().getResources().getBoolean(
+            setSplitToolbar(getContext().getResources().getBoolean(
                     com.android.internal.R.bool.split_action_bar_is_narrow));
         }
         if (mActionMenuPresenter != null) {
@@ -86,7 +86,7 @@
      * Sets whether the bar should be split right now, no questions asked.
      * @param split true if the bar should split
      */
-    public void setSplitActionBar(boolean split) {
+    public void setSplitToolbar(boolean split) {
         mSplitActionBar = split;
     }
 
@@ -107,7 +107,7 @@
         return mContentHeight;
     }
 
-    public void setSplitView(ActionBarContainer splitView) {
+    public void setSplitView(ViewGroup splitView) {
         mSplitView = splitView;
     }
 
@@ -214,6 +214,10 @@
         return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
     }
 
+    public boolean canShowOverflowMenu() {
+        return isOverflowReserved() && getVisibility() == VISIBLE;
+    }
+
     public void dismissPopupMenus() {
         if (mActionMenuPresenter != null) {
             mActionMenuPresenter.dismissPopupMenus();
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index ed07514..790b611 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -36,7 +36,7 @@
 public class ActionBarContainer extends FrameLayout {
     private boolean mIsTransitioning;
     private View mTabContainer;
-    private ActionBarView mActionBarView;
+    private View mActionBarView;
 
     private Drawable mBackground;
     private Drawable mStackedBackground;
@@ -76,7 +76,7 @@
     @Override
     public void onFinishInflate() {
         super.onFinishInflate();
-        mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
+        mActionBarView = findViewById(com.android.internal.R.id.action_bar);
     }
 
     public void setPrimaryBackground(Drawable bg) {
@@ -251,6 +251,10 @@
         return null;
     }
 
+    private boolean isCollapsed(View view) {
+        return view == null || view.getVisibility() == GONE || view.getMeasuredHeight() == 0;
+    }
+
     @Override
     public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         if (mActionBarView == null &&
@@ -263,7 +267,7 @@
         if (mActionBarView == null) return;
 
         final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams();
-        final int actionBarViewHeight = mActionBarView.isCollapsed() ? 0 :
+        final int actionBarViewHeight = isCollapsed(mActionBarView) ? 0 :
                 mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
 
         if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
@@ -298,9 +302,8 @@
             }
         } else {
             if (mBackground != null) {
-                final ActionBarView actionBarView = mActionBarView;
-                mBackground.setBounds(actionBarView.getLeft(), actionBarView.getTop(),
-                        actionBarView.getRight(), actionBarView.getBottom());
+                mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
+                        mActionBarView.getRight(), mActionBarView.getBottom());
                 needsInvalidate = true;
             }
             mIsStacked = hasTabs;
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index e10070f..6ff77a0 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -83,7 +83,7 @@
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.ActionMode, defStyleAttr, defStyleRes);
-        setBackgroundDrawable(a.getDrawable(
+        setBackground(a.getDrawable(
                 com.android.internal.R.styleable.ActionMode_background));
         mTitleStyleRes = a.getResourceId(
                 com.android.internal.R.styleable.ActionMode_titleTextStyle, 0);
@@ -109,7 +109,7 @@
     }
 
     @Override
-    public void setSplitActionBar(boolean split) {
+    public void setSplitToolbar(boolean split) {
         if (mSplitActionBar != split) {
             if (mActionMenuPresenter != null) {
                 // Mode is already active; move everything over and adjust the menu itself.
@@ -137,7 +137,7 @@
                     mSplitView.addView(mMenuView, layoutParams);
                 }
             }
-            super.setSplitActionBar(split);
+            super.setSplitToolbar(split);
         }
     }
 
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 7ab4bed..8a9cb22 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -39,6 +39,7 @@
 import android.view.Window;
 import android.view.WindowInsets;
 import android.widget.OverScroller;
+import android.widget.Toolbar;
 import com.android.internal.view.menu.MenuPresenter;
 
 /**
@@ -59,7 +60,7 @@
     private ActionBarContainer mActionBarTop;
 
     // Some interior UI elements.
-    private ActionBarView mActionBarView;
+    private DecorToolbar mDecorToolbar;
 
     // Content overlay drawable - generally the action bar's shadow
     private Drawable mWindowContentOverlay;
@@ -401,7 +402,7 @@
             topInset = mActionBarTop.getMeasuredHeight();
         }
 
-        if (mActionBarView.isSplitActionBar()) {
+        if (mDecorToolbar.isSplit()) {
             // If action bar is split, adjust bottom insets for it.
             if (mActionBarBottom != null) {
                 if (stable) {
@@ -563,12 +564,23 @@
             mContent = findViewById(com.android.internal.R.id.content);
             mActionBarTop = (ActionBarContainer) findViewById(
                     com.android.internal.R.id.action_bar_container);
-            mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
+            mDecorToolbar = getDecorToolbar(findViewById(com.android.internal.R.id.action_bar));
             mActionBarBottom = (ActionBarContainer) findViewById(
                     com.android.internal.R.id.split_action_bar);
         }
     }
 
+    private DecorToolbar getDecorToolbar(View view) {
+        if (view instanceof DecorToolbar) {
+            return (DecorToolbar) view;
+        } else if (view instanceof Toolbar) {
+            return ((Toolbar) view).getWrapper();
+        } else {
+            throw new IllegalStateException("Can't make a decor toolbar out of " +
+                    view.getClass().getSimpleName());
+        }
+    }
+
     public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
         if (hideOnContentScroll != mHideOnContentScroll) {
             mHideOnContentScroll = hideOnContentScroll;
@@ -648,9 +660,9 @@
             final int action = event.getAction();
 
             // Collapse any expanded action views.
-            if (mActionBarView != null && mActionBarView.hasExpandedActionView()) {
+            if (mDecorToolbar != null && mDecorToolbar.hasExpandedActionView()) {
                 if (action == KeyEvent.ACTION_UP) {
-                    mActionBarView.collapseActionView();
+                    mDecorToolbar.collapseActionView();
                 }
                 return true;
             }
@@ -662,19 +674,19 @@
     @Override
     public void setWindowCallback(Window.Callback cb) {
         pullChildren();
-        mActionBarView.setWindowCallback(cb);
+        mDecorToolbar.setWindowCallback(cb);
     }
 
     @Override
     public void setWindowTitle(CharSequence title) {
         pullChildren();
-        mActionBarView.setWindowTitle(title);
+        mDecorToolbar.setWindowTitle(title);
     }
 
     @Override
     public CharSequence getTitle() {
         pullChildren();
-        return mActionBarView.getTitle();
+        return mDecorToolbar.getTitle();
     }
 
     @Override
@@ -682,10 +694,10 @@
         pullChildren();
         switch (windowFeature) {
             case Window.FEATURE_PROGRESS:
-                mActionBarView.initProgress();
+                mDecorToolbar.initProgress();
                 break;
             case Window.FEATURE_INDETERMINATE_PROGRESS:
-                mActionBarView.initIndeterminateProgress();
+                mDecorToolbar.initIndeterminateProgress();
                 break;
             case Window.FEATURE_ACTION_BAR_OVERLAY:
                 setOverlayMode(true);
@@ -704,15 +716,15 @@
         }
         if (splitActionBar) {
             pullChildren();
-            if (mActionBarBottom != null) {
-                mActionBarView.setSplitView(mActionBarBottom);
-                mActionBarView.setSplitActionBar(splitActionBar);
-                mActionBarView.setSplitWhenNarrow(splitWhenNarrow);
+            if (mActionBarBottom != null && mDecorToolbar.canSplit()) {
+                mDecorToolbar.setSplitView(mActionBarBottom);
+                mDecorToolbar.setSplitToolbar(splitActionBar);
+                mDecorToolbar.setSplitWhenNarrow(splitWhenNarrow);
 
                 final ActionBarContextView cab = (ActionBarContextView) findViewById(
                         com.android.internal.R.id.action_context_bar);
                 cab.setSplitView(mActionBarBottom);
-                cab.setSplitActionBar(splitActionBar);
+                cab.setSplitToolbar(splitActionBar);
                 cab.setSplitWhenNarrow(splitWhenNarrow);
             } else if (splitActionBar) {
                 Log.e(TAG, "Requested split action bar with " +
@@ -724,91 +736,91 @@
     @Override
     public boolean hasIcon() {
         pullChildren();
-        return mActionBarView.hasIcon();
+        return mDecorToolbar.hasIcon();
     }
 
     @Override
     public boolean hasLogo() {
         pullChildren();
-        return mActionBarView.hasLogo();
+        return mDecorToolbar.hasLogo();
     }
 
     @Override
     public void setIcon(int resId) {
         pullChildren();
-        mActionBarView.setIcon(resId);
+        mDecorToolbar.setIcon(resId);
     }
 
     @Override
     public void setIcon(Drawable d) {
         pullChildren();
-        mActionBarView.setIcon(d);
+        mDecorToolbar.setIcon(d);
     }
 
     @Override
     public void setLogo(int resId) {
         pullChildren();
-        mActionBarView.setLogo(resId);
+        mDecorToolbar.setLogo(resId);
     }
 
     @Override
     public boolean canShowOverflowMenu() {
         pullChildren();
-        return mActionBarView.isOverflowReserved() && mActionBarView.getVisibility() == VISIBLE;
+        return mDecorToolbar.canShowOverflowMenu();
     }
 
     @Override
     public boolean isOverflowMenuShowing() {
         pullChildren();
-        return mActionBarView.isOverflowMenuShowing();
+        return mDecorToolbar.isOverflowMenuShowing();
     }
 
     @Override
     public boolean isOverflowMenuShowPending() {
         pullChildren();
-        return mActionBarView.isOverflowMenuShowPending();
+        return mDecorToolbar.isOverflowMenuShowPending();
     }
 
     @Override
     public boolean showOverflowMenu() {
         pullChildren();
-        return mActionBarView.showOverflowMenu();
+        return mDecorToolbar.showOverflowMenu();
     }
 
     @Override
     public boolean hideOverflowMenu() {
         pullChildren();
-        return mActionBarView.hideOverflowMenu();
+        return mDecorToolbar.hideOverflowMenu();
     }
 
     @Override
     public void setMenuPrepared() {
         pullChildren();
-        mActionBarView.setMenuPrepared();
+        mDecorToolbar.setMenuPrepared();
     }
 
     @Override
     public void setMenu(Menu menu, MenuPresenter.Callback cb) {
         pullChildren();
-        mActionBarView.setMenu(menu, cb);
+        mDecorToolbar.setMenu(menu, cb);
     }
 
     @Override
     public void saveToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
         pullChildren();
-        mActionBarView.saveHierarchyState(toolbarStates);
+        mDecorToolbar.saveHierarchyState(toolbarStates);
     }
 
     @Override
     public void restoreToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
         pullChildren();
-        mActionBarView.restoreHierarchyState(toolbarStates);
+        mDecorToolbar.restoreHierarchyState(toolbarStates);
     }
 
     @Override
     public void dismissPopups() {
         pullChildren();
-        mActionBarView.dismissPopupMenus();
+        mDecorToolbar.dismissPopupMenus();
     }
 
     public static class LayoutParams extends MarginLayoutParams {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 60631b9..af82778 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -18,7 +18,6 @@
 
 import android.animation.LayoutTransition;
 import android.app.ActionBar;
-import android.app.ActionBar.OnNavigationListener;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -63,7 +62,7 @@
 /**
  * @hide
  */
-public class ActionBarView extends AbsActionBarView {
+public class ActionBarView extends AbsActionBarView implements DecorToolbar {
     private static final String TAG = "ActionBarView";
 
     /**
@@ -117,8 +116,7 @@
 
     private boolean mUserTitle;
     private boolean mIncludeTabs;
-    private boolean mIsCollapsable;
-    private boolean mIsCollapsed;
+    private boolean mIsCollapsible;
     private boolean mWasHomeEnabled; // Was it enabled before action view expansion?
 
     private MenuBuilder mOptionsMenu;
@@ -129,7 +127,7 @@
     private ActionMenuItem mLogoNavItem;
 
     private SpinnerAdapter mSpinnerAdapter;
-    private OnNavigationListener mCallback;
+    private AdapterView.OnItemSelectedListener mNavItemSelectedListener;
 
     private Runnable mTabSelector;
 
@@ -138,18 +136,6 @@
 
     Window.Callback mWindowCallback;
 
-    private final AdapterView.OnItemSelectedListener mNavItemSelectedListener =
-            new AdapterView.OnItemSelectedListener() {
-        public void onItemSelected(AdapterView parent, View view, int position, long id) {
-            if (mCallback != null) {
-                mCallback.onNavigationItemSelected(position, id);
-            }
-        }
-        public void onNothingSelected(AdapterView parent) {
-            // Do nothing
-        }
-    };
-
     private final OnClickListener mExpandedActionViewUpListener = new OnClickListener() {
         @Override
         public void onClick(View v) {
@@ -178,8 +164,6 @@
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar,
                 com.android.internal.R.attr.actionBarStyle, 0);
 
-        ApplicationInfo appInfo = context.getApplicationInfo();
-        PackageManager pm = context.getPackageManager();
         mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode,
                 ActionBar.NAVIGATION_MODE_STANDARD);
         mTitle = a.getText(R.styleable.ActionBar_title);
@@ -260,7 +244,7 @@
         }
 
         if (mHomeDescriptionRes != 0) {
-            setHomeActionContentDescription(mHomeDescriptionRes);
+            setNavigationContentDescription(mHomeDescriptionRes);
         }
 
         if (mTabScrollView != null && mIncludeTabs) {
@@ -313,7 +297,7 @@
     }
 
     @Override
-    public void setSplitActionBar(boolean splitActionBar) {
+    public void setSplitToolbar(boolean splitActionBar) {
         if (mSplitActionBar != splitActionBar) {
             if (mMenuView != null) {
                 final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
@@ -349,18 +333,26 @@
                     mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
                 }
             }
-            super.setSplitActionBar(splitActionBar);
+            super.setSplitToolbar(splitActionBar);
         }
     }
 
-    public boolean isSplitActionBar() {
+    public boolean isSplit() {
         return mSplitActionBar;
     }
 
+    public boolean canSplit() {
+        return true;
+    }
+
     public boolean hasEmbeddedTabs() {
         return mIncludeTabs;
     }
 
+    public void setEmbeddedTabView(View view) {
+        setEmbeddedTabView((ScrollingTabContainerView) view);
+    }
+
     public void setEmbeddedTabView(ScrollingTabContainerView tabs) {
         if (mTabScrollView != null) {
             removeView(mTabScrollView);
@@ -376,10 +368,6 @@
         }
     }
 
-    public void setCallback(OnNavigationListener callback) {
-        mCallback = callback;
-    }
-
     public void setMenuPrepared() {
         mMenuPrepared = true;
     }
@@ -473,7 +461,7 @@
         }
     }
 
-    public void setCustomNavigationView(View view) {
+    public void setCustomView(View view) {
         final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
         if (showCustom) {
             ActionBarTransition.beginDelayedTransition(this);
@@ -765,15 +753,16 @@
         }
     }
 
-    public void setDropdownAdapter(SpinnerAdapter adapter) {
+    public void setDropdownParams(SpinnerAdapter adapter, AdapterView.OnItemSelectedListener l) {
         mSpinnerAdapter = adapter;
+        mNavItemSelectedListener = l;
         if (mSpinner != null) {
             mSpinner.setAdapter(adapter);
         }
     }
 
-    public SpinnerAdapter getDropdownAdapter() {
-        return mSpinnerAdapter;
+    public int getDropdownItemCount() {
+        return mSpinnerAdapter != null ? mSpinnerAdapter.getCount() : 0;
     }
 
     public void setDropdownSelectedPosition(int position) {
@@ -784,7 +773,7 @@
         return mSpinner.getSelectedItemPosition();
     }
 
-    public View getCustomNavigationView() {
+    public View getCustomView() {
         return mCustomNavView;
     }
 
@@ -797,6 +786,11 @@
     }
 
     @Override
+    public ViewGroup getViewGroup() {
+        return this;
+    }
+
+    @Override
     protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
         // Used by custom nav views if they don't supply layout params. Everything else
         // added to an ActionBarView should have them already.
@@ -860,12 +854,8 @@
         mContextView = view;
     }
 
-    public void setCollapsable(boolean collapsable) {
-        mIsCollapsable = collapsable;
-    }
-
-    public boolean isCollapsed() {
-        return mIsCollapsed;
+    public void setCollapsible(boolean collapsible) {
+        mIsCollapsible = collapsible;
     }
 
     /**
@@ -893,7 +883,7 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final int childCount = getChildCount();
-        if (mIsCollapsable) {
+        if (mIsCollapsible) {
             int visibleChildren = 0;
             for (int i = 0; i < childCount; i++) {
                 final View child = getChildAt(i);
@@ -915,11 +905,9 @@
             if (visibleChildren == 0) {
                 // No size for an empty action bar when collapsable.
                 setMeasuredDimension(0, 0);
-                mIsCollapsed = true;
                 return;
             }
         }
-        mIsCollapsed = false;
 
         int widthMode = MeasureSpec.getMode(widthMeasureSpec);
         if (widthMode != MeasureSpec.EXACTLY) {
@@ -1323,20 +1311,20 @@
         }
     }
 
-    public void setHomeAsUpIndicator(Drawable indicator) {
+    public void setNavigationIcon(Drawable indicator) {
         mHomeLayout.setUpIndicator(indicator);
     }
 
-    public void setHomeAsUpIndicator(int resId) {
+    public void setNavigationIcon(int resId) {
         mHomeLayout.setUpIndicator(resId);
     }
 
-    public void setHomeActionContentDescription(CharSequence description) {
+    public void setNavigationContentDescription(CharSequence description) {
         mHomeDescription = description;
         updateHomeAccessibility(mUpGoerFive.isEnabled());
     }
 
-    public void setHomeActionContentDescription(int resId) {
+    public void setNavigationContentDescription(int resId) {
         mHomeDescriptionRes = resId;
         mHomeDescription = resId != 0 ? getResources().getText(resId) : null;
         updateHomeAccessibility(mUpGoerFive.isEnabled());
diff --git a/core/java/com/android/internal/widget/DecorToolbar.java b/core/java/com/android/internal/widget/DecorToolbar.java
new file mode 100644
index 0000000..ee6988e
--- /dev/null
+++ b/core/java/com/android/internal/widget/DecorToolbar.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Parcelable;
+import android.util.SparseArray;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.SpinnerAdapter;
+import com.android.internal.view.menu.MenuPresenter;
+
+/**
+ * Common interface for a toolbar that sits as part of the window decor.
+ * Layouts that control window decor use this as a point of interaction with different
+ * bar implementations.
+ *
+ * @hide
+ */
+public interface DecorToolbar {
+    ViewGroup getViewGroup();
+    Context getContext();
+    boolean isSplit();
+    boolean hasExpandedActionView();
+    void collapseActionView();
+    void setWindowCallback(Window.Callback cb);
+    void setWindowTitle(CharSequence title);
+    CharSequence getTitle();
+    void setTitle(CharSequence title);
+    CharSequence getSubtitle();
+    void setSubtitle(CharSequence subtitle);
+    void initProgress();
+    void initIndeterminateProgress();
+    boolean canSplit();
+    void setSplitView(ViewGroup splitView);
+    void setSplitToolbar(boolean split);
+    void setSplitWhenNarrow(boolean splitWhenNarrow);
+    boolean hasIcon();
+    boolean hasLogo();
+    void setIcon(int resId);
+    void setIcon(Drawable d);
+    void setLogo(int resId);
+    void setLogo(Drawable d);
+    boolean canShowOverflowMenu();
+    boolean isOverflowMenuShowing();
+    boolean isOverflowMenuShowPending();
+    boolean showOverflowMenu();
+    boolean hideOverflowMenu();
+    void setMenuPrepared();
+    void setMenu(Menu menu, MenuPresenter.Callback cb);
+    void dismissPopupMenus();
+
+    int getDisplayOptions();
+    void setDisplayOptions(int opts);
+    void setEmbeddedTabView(View tabView);
+    boolean hasEmbeddedTabs();
+    boolean isTitleTruncated();
+    void setCollapsible(boolean collapsible);
+    void setHomeButtonEnabled(boolean enable);
+    int getNavigationMode();
+    void setNavigationMode(int mode);
+    void setDropdownParams(SpinnerAdapter adapter, AdapterView.OnItemSelectedListener listener);
+    void setDropdownSelectedPosition(int position);
+    int getDropdownSelectedPosition();
+    int getDropdownItemCount();
+    void setCustomView(View view);
+    View getCustomView();
+    void animateToVisibility(int visibility);
+    void setNavigationIcon(Drawable icon);
+    void setNavigationIcon(int resId);
+    void setNavigationContentDescription(CharSequence description);
+    void setNavigationContentDescription(int resId);
+    void saveHierarchyState(SparseArray<Parcelable> toolbarStates);
+    void restoreHierarchyState(SparseArray<Parcelable> toolbarStates);
+}
diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
new file mode 100644
index 0000000..f90aaea
--- /dev/null
+++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.internal.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.ActionBar;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.ActionMenuPresenter;
+import android.widget.AdapterView;
+import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
+import android.widget.Toolbar;
+import com.android.internal.R;
+import com.android.internal.view.menu.ActionMenuItem;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuPresenter;
+
+/**
+ * Internal class used to interact with the Toolbar widget without
+ * exposing interface methods to the public API.
+ *
+ * <p>ToolbarWidgetWrapper manages the differences between Toolbar and ActionBarView
+ * so that either variant acting as a
+ * {@link com.android.internal.app.WindowDecorActionBar WindowDecorActionBar} can behave
+ * in the same way.</p>
+ *
+ * @hide
+ */
+public class ToolbarWidgetWrapper implements DecorToolbar {
+    private static final String TAG = "ToolbarWidgetWrapper";
+
+    private static final int AFFECTS_LOGO_MASK =
+            ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_USE_LOGO;
+
+    private Toolbar mToolbar;
+
+    private int mDisplayOpts;
+    private View mTabView;
+    private Spinner mSpinner;
+    private View mCustomView;
+
+    private Drawable mIcon;
+    private Drawable mLogo;
+    private Drawable mNavIcon;
+
+    private boolean mTitleSet;
+    private CharSequence mTitle;
+    private CharSequence mSubtitle;
+
+    private Window.Callback mWindowCallback;
+    private boolean mMenuPrepared;
+    private ActionMenuPresenter mActionMenuPresenter;
+
+    public ToolbarWidgetWrapper(Toolbar toolbar) {
+        mToolbar = toolbar;
+
+        final TypedArray a = toolbar.getContext().obtainStyledAttributes(null,
+                R.styleable.ActionBar, R.attr.actionBarStyle, 0);
+
+        final CharSequence title = a.getText(R.styleable.ActionBar_title);
+        if (title != null) {
+            setTitle(title);
+        }
+
+        final CharSequence subtitle = a.getText(R.styleable.ActionBar_subtitle);
+        if (subtitle != null) {
+            setSubtitle(subtitle);
+        }
+
+        final Drawable logo = a.getDrawable(R.styleable.ActionBar_logo);
+        if (logo != null) {
+            setLogo(logo);
+        }
+
+        final Drawable icon = a.getDrawable(R.styleable.ActionBar_icon);
+        if (icon != null) {
+            setIcon(icon);
+        }
+
+        final Drawable navIcon = a.getDrawable(R.styleable.ActionBar_homeAsUpIndicator);
+        if (navIcon != null) {
+            setNavigationIcon(navIcon);
+        }
+
+        setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, 0));
+
+        final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0);
+        if (customNavId != 0) {
+            setCustomView(LayoutInflater.from(mToolbar.getContext()).inflate(customNavId,
+                    mToolbar, false));
+            setDisplayOptions(mDisplayOpts | ActionBar.DISPLAY_SHOW_CUSTOM);
+        }
+
+        final int height = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
+        if (height > 0) {
+            final ViewGroup.LayoutParams lp = mToolbar.getLayoutParams();
+            lp.height = height;
+            mToolbar.setLayoutParams(lp);
+        }
+
+        final int contentInsetStart = a.getDimensionPixelOffset(
+                R.styleable.ActionBar_contentInsetStart, 0);
+        final int contentInsetEnd = a.getDimensionPixelOffset(
+                R.styleable.ActionBar_contentInsetEnd, 0);
+        if (contentInsetStart > 0 || contentInsetEnd > 0) {
+            mToolbar.setContentInsetsRelative(contentInsetStart, contentInsetEnd);
+        }
+
+        a.recycle();
+
+        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
+            final ActionMenuItem mNavItem = new ActionMenuItem(mToolbar.getContext(),
+                    0, android.R.id.home, 0, 0, mTitle);
+            @Override
+            public void onClick(View v) {
+                if (mWindowCallback != null && mMenuPrepared) {
+                    mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mNavItem);
+                }
+            }
+        });
+    }
+
+    @Override
+    public ViewGroup getViewGroup() {
+        return mToolbar;
+    }
+
+    @Override
+    public Context getContext() {
+        return mToolbar.getContext();
+    }
+
+    @Override
+    public boolean isSplit() {
+        return false;
+    }
+
+    @Override
+    public boolean hasExpandedActionView() {
+        return mToolbar.hasExpandedActionView();
+    }
+
+    @Override
+    public void collapseActionView() {
+        mToolbar.collapseActionView();
+    }
+
+    @Override
+    public void setWindowCallback(Window.Callback cb) {
+        mWindowCallback = cb;
+    }
+
+    @Override
+    public void setWindowTitle(CharSequence title) {
+        // "Real" title always trumps window title.
+        if (!mTitleSet) {
+            setTitleInt(title);
+        }
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        return mToolbar.getTitle();
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        mTitleSet = true;
+        setTitleInt(title);
+    }
+
+    private void setTitleInt(CharSequence title) {
+        mTitle = title;
+        if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+            mToolbar.setTitle(title);
+        }
+    }
+
+    @Override
+    public CharSequence getSubtitle() {
+        return mToolbar.getSubtitle();
+    }
+
+    @Override
+    public void setSubtitle(CharSequence subtitle) {
+        mSubtitle = subtitle;
+        if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+            mToolbar.setSubtitle(subtitle);
+        }
+    }
+
+    @Override
+    public void initProgress() {
+        Log.i(TAG, "Progress display unsupported");
+    }
+
+    @Override
+    public void initIndeterminateProgress() {
+        Log.i(TAG, "Progress display unsupported");
+    }
+
+    @Override
+    public boolean canSplit() {
+        return false;
+    }
+
+    @Override
+    public void setSplitView(ViewGroup splitView) {
+    }
+
+    @Override
+    public void setSplitToolbar(boolean split) {
+        if (split) {
+            throw new UnsupportedOperationException("Cannot split an android.widget.Toolbar");
+        }
+    }
+
+    @Override
+    public void setSplitWhenNarrow(boolean splitWhenNarrow) {
+        // Ignore.
+    }
+
+    @Override
+    public boolean hasIcon() {
+        return mIcon != null;
+    }
+
+    @Override
+    public boolean hasLogo() {
+        return mLogo != null;
+    }
+
+    @Override
+    public void setIcon(int resId) {
+        setIcon(resId != 0 ? getContext().getDrawable(resId) : null);
+    }
+
+    @Override
+    public void setIcon(Drawable d) {
+        mIcon = d;
+        updateToolbarLogo();
+    }
+
+    @Override
+    public void setLogo(int resId) {
+        setLogo(resId != 0 ? getContext().getDrawable(resId) : null);
+    }
+
+    @Override
+    public void setLogo(Drawable d) {
+        mLogo = d;
+        updateToolbarLogo();
+    }
+
+    private void updateToolbarLogo() {
+        Drawable logo = null;
+        if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_HOME) != 0) {
+            if ((mDisplayOpts & ActionBar.DISPLAY_USE_LOGO) != 0) {
+                logo = mLogo != null ? mLogo : mIcon;
+            } else {
+                logo = mIcon;
+            }
+        }
+        mToolbar.setLogo(logo);
+    }
+
+    @Override
+    public boolean canShowOverflowMenu() {
+        return mToolbar.canShowOverflowMenu();
+    }
+
+    @Override
+    public boolean isOverflowMenuShowing() {
+        return mToolbar.isOverflowMenuShowing();
+    }
+
+    @Override
+    public boolean isOverflowMenuShowPending() {
+        return mToolbar.isOverflowMenuShowPending();
+    }
+
+    @Override
+    public boolean showOverflowMenu() {
+        return mToolbar.showOverflowMenu();
+    }
+
+    @Override
+    public boolean hideOverflowMenu() {
+        return mToolbar.hideOverflowMenu();
+    }
+
+    @Override
+    public void setMenuPrepared() {
+        mMenuPrepared = true;
+    }
+
+    @Override
+    public void setMenu(Menu menu, MenuPresenter.Callback cb) {
+        if (mActionMenuPresenter == null) {
+            mActionMenuPresenter = new ActionMenuPresenter(mToolbar.getContext());
+            mActionMenuPresenter.setId(com.android.internal.R.id.action_menu_presenter);
+        }
+        mActionMenuPresenter.setCallback(cb);
+        mToolbar.setMenu((MenuBuilder) menu, mActionMenuPresenter);
+    }
+
+    @Override
+    public void dismissPopupMenus() {
+        mToolbar.dismissPopupMenus();
+    }
+
+    @Override
+    public int getDisplayOptions() {
+        return mDisplayOpts;
+    }
+
+    @Override
+    public void setDisplayOptions(int newOpts) {
+        final int oldOpts = mDisplayOpts;
+        final int changed = oldOpts ^ newOpts;
+        mDisplayOpts = newOpts;
+        if (changed != 0) {
+            if ((changed & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+                if ((newOpts & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+                    mToolbar.setNavigationIcon(mNavIcon);
+                } else {
+                    mToolbar.setNavigationIcon(null);
+                }
+            }
+
+            if ((changed & AFFECTS_LOGO_MASK) != 0) {
+                updateToolbarLogo();
+            }
+
+            if ((changed & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+                if ((newOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+                    mToolbar.setTitle(mTitle);
+                    mToolbar.setSubtitle(mSubtitle);
+                } else {
+                    mToolbar.setTitle(null);
+                    mToolbar.setSubtitle(null);
+                }
+            }
+
+            if ((changed & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomView != null) {
+                if ((newOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+                    mToolbar.addView(mCustomView);
+                } else {
+                    mToolbar.removeView(mCustomView);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setEmbeddedTabView(View tabView) {
+        mTabView = tabView;
+    }
+
+    @Override
+    public boolean hasEmbeddedTabs() {
+        return mTabView != null;
+    }
+
+    @Override
+    public boolean isTitleTruncated() {
+        return mToolbar.isTitleTruncated();
+    }
+
+    @Override
+    public void setCollapsible(boolean collapsible) {
+        // Ignore
+    }
+
+    @Override
+    public void setHomeButtonEnabled(boolean enable) {
+        // Ignore
+    }
+
+    @Override
+    public int getNavigationMode() {
+        return 0;
+    }
+
+    @Override
+    public void setNavigationMode(int mode) {
+        if (mode != ActionBar.NAVIGATION_MODE_STANDARD) {
+            throw new IllegalArgumentException(
+                    "Navigation modes not supported in this configuration");
+        }
+    }
+
+    @Override
+    public void setDropdownParams(SpinnerAdapter adapter,
+            AdapterView.OnItemSelectedListener listener) {
+        if (mSpinner == null) {
+            mSpinner = new Spinner(getContext());
+        }
+        mSpinner.setAdapter(adapter);
+        mSpinner.setOnItemSelectedListener(listener);
+    }
+
+    @Override
+    public void setDropdownSelectedPosition(int position) {
+        if (mSpinner == null) {
+            throw new IllegalStateException(
+                    "Can't set dropdown selected position without an adapter");
+        }
+        mSpinner.setSelection(position);
+    }
+
+    @Override
+    public int getDropdownSelectedPosition() {
+        return mSpinner != null ? mSpinner.getSelectedItemPosition() : 0;
+    }
+
+    @Override
+    public int getDropdownItemCount() {
+        return mSpinner != null ? mSpinner.getCount() : 0;
+    }
+
+    @Override
+    public void setCustomView(View view) {
+        if (mCustomView != null && (mDisplayOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+            mToolbar.removeView(mCustomView);
+        }
+        mCustomView = view;
+        if (view != null && (mDisplayOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+            mToolbar.addView(mCustomView);
+        }
+    }
+
+    @Override
+    public View getCustomView() {
+        return mCustomView;
+    }
+
+    @Override
+    public void animateToVisibility(int visibility) {
+        if (visibility == View.GONE) {
+            mToolbar.animate().translationY(mToolbar.getHeight()).alpha(0)
+                    .setListener(new AnimatorListenerAdapter() {
+                        private boolean mCanceled = false;
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            if (!mCanceled) {
+                                mToolbar.setVisibility(View.GONE);
+                            }
+                        }
+
+                        @Override
+                        public void onAnimationCancel(Animator animation) {
+                            mCanceled = true;
+                        }
+                    });
+        } else if (visibility == View.VISIBLE) {
+            mToolbar.animate().translationY(0).alpha(1)
+                    .setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationStart(Animator animation) {
+                            mToolbar.setVisibility(View.VISIBLE);
+                        }
+                    });
+        }
+    }
+
+    @Override
+    public void setNavigationIcon(Drawable icon) {
+        mNavIcon = icon;
+        if ((mDisplayOpts & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+            mToolbar.setNavigationIcon(icon);
+        }
+    }
+
+    @Override
+    public void setNavigationIcon(int resId) {
+        setNavigationIcon(mToolbar.getContext().getDrawable(resId));
+    }
+
+    @Override
+    public void setNavigationContentDescription(CharSequence description) {
+        mToolbar.setNavigationContentDescription(description);
+    }
+
+    @Override
+    public void setNavigationContentDescription(int resId) {
+        mToolbar.setNavigationContentDescription(resId);
+    }
+
+    @Override
+    public void saveHierarchyState(SparseArray<Parcelable> toolbarStates) {
+        mToolbar.saveHierarchyState(toolbarStates);
+    }
+
+    @Override
+    public void restoreHierarchyState(SparseArray<Parcelable> toolbarStates) {
+        mToolbar.restoreHierarchyState(toolbarStates);
+    }
+
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index a159715..f446c3a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -173,8 +173,10 @@
 	$(call include-path-for, bluedroid) \
 	$(call include-path-for, libhardware)/hardware \
 	$(call include-path-for, libhardware_legacy)/hardware_legacy \
+	$(TOP)/bionic/libc/dns/include \
 	$(TOP)/frameworks/av/include \
 	$(TOP)/system/media/camera/include \
+	$(TOP)/system/netd/include \
 	external/pdfium/core/include/fpdfapi \
 	external/pdfium/core/include/fpdfdoc \
 	external/pdfium/fpdfsdk/include \
@@ -233,6 +235,7 @@
 	libaudioutils \
 	libpdfium \
 	libimg_utils \
+	libnetd_client \
 
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 0c7eefa..e069876 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -789,7 +789,7 @@
     }
 
     // libart tolerates libdvm flags, but not vice versa, so only pass some options if libart.
-    property_get("persist.sys.dalvik.vm.lib.1", dalvikVmLibBuf, "libdvm.so");
+    property_get("persist.sys.dalvik.vm.lib.2", dalvikVmLibBuf, "libart.so");
     bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0);
 
     if (libart) {
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 6d23c32..bc5e1b3 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -18,6 +18,8 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
+#include "NetdClient.h"
+#include "resolv_netid.h"
 #include <utils/misc.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
@@ -250,6 +252,36 @@
     }
 }
 
+static void android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId)
+{
+    setNetworkForProcess(netId);
+}
+
+static void android_net_utils_unbindProcessToNetwork(JNIEnv *env, jobject thiz)
+{
+    setNetworkForProcess(NETID_UNSET);
+}
+
+static jint android_net_utils_getNetworkBoundToProcess(JNIEnv *env, jobject thiz)
+{
+    return getNetworkForProcess();
+}
+
+static void android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz, jint netId)
+{
+    setNetworkForResolv(netId);
+}
+
+static void android_net_utils_unbindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz)
+{
+    setNetworkForResolv(NETID_UNSET);
+}
+
+static void android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket, jint netId)
+{
+    setNetworkForSocket(netId, socket);
+}
+
 // ----------------------------------------------------------------------------
 
 /*
@@ -267,6 +299,12 @@
     { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
     { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
     { "markSocket", "(II)V", (void*) android_net_utils_markSocket },
+    { "bindProcessToNetwork", "(I)V", (void*) android_net_utils_bindProcessToNetwork },
+    { "getNetworkBoundToProcess", "()I", (void*) android_net_utils_getNetworkBoundToProcess },
+    { "unbindProcessToNetwork", "()V", (void*) android_net_utils_unbindProcessToNetwork },
+    { "bindProcessToNetworkForHostResolution", "(I)V", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
+    { "unbindProcessToNetworkForHostResolution", "()V", (void*) android_net_utils_unbindProcessToNetworkForHostResolution },
+    { "bindSocketToNetwork", "(II)V", (void*) android_net_utils_bindSocketToNetwork },
 };
 
 int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/core/res/res/anim/input_method_exit.xml b/core/res/res/anim/input_method_exit.xml
index e87352f..4c4f6a4 100644
--- a/core/res/res/anim/input_method_exit.xml
+++ b/core/res/res/anim/input_method_exit.xml
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/fade_out.xml
-**
-** Copyright 2007, The Android Open Source Project
+/* Copyright 2007, 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. 
@@ -19,7 +17,7 @@
 -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
 	android:shareInterpolator="false">
-    <translate android:fromYDelta="0" android:toYDelta="10%"
+    <translate android:fromYDelta="0" android:toYDelta="-20%"
 			android:interpolator="@interpolator/accelerate_quint"
             android:duration="@android:integer/config_shortAnimTime"/>
     <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
diff --git a/core/res/res/anim/lock_screen_behind_enter.xml b/core/res/res/anim/lock_screen_behind_enter.xml
index cb47b3c..4a956d7 100644
--- a/core/res/res/anim/lock_screen_behind_enter.xml
+++ b/core/res/res/anim/lock_screen_behind_enter.xml
@@ -20,9 +20,8 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:background="#ff000000" android:shareInterpolator="false">
     <alpha
-        android:fromAlpha="0.0" android:toAlpha="1.0"
+        android:fromAlpha="1.0" android:toAlpha="1.0"
         android:fillEnabled="true" android:fillBefore="true"
         android:interpolator="@interpolator/decelerate_quint"
-        android:startOffset="@android:integer/config_shortAnimTime"
-        android:duration="@android:integer/config_shortAnimTime"/>
+        android:duration="0"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/lock_screen_wallpaper_behind_enter.xml b/core/res/res/anim/lock_screen_wallpaper_behind_enter.xml
index c29fd1a..f7a6a65 100644
--- a/core/res/res/anim/lock_screen_wallpaper_behind_enter.xml
+++ b/core/res/res/anim/lock_screen_wallpaper_behind_enter.xml
@@ -23,6 +23,6 @@
         android:fromAlpha="0.0" android:toAlpha="1.0"
         android:fillEnabled="true" android:fillBefore="true"
         android:interpolator="@interpolator/decelerate_quad"
-        android:startOffset="@android:integer/config_shortAnimTime"
+        android:startOffset="@android:integer/config_mediumAnimTime"
         android:duration="@android:integer/config_shortAnimTime"/>
 </set>
diff --git a/core/res/res/anim/voice_activity_close_enter.xml b/core/res/res/anim/voice_activity_close_enter.xml
new file mode 100644
index 0000000..4f3d3d5
--- /dev/null
+++ b/core/res/res/anim/voice_activity_close_enter.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+	android:shareInterpolator="false">
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+			android:interpolator="@interpolator/accelerate_cubic"
+            android:duration="@android:integer/config_shortAnimTime"/>
+</set>
diff --git a/core/res/res/anim/voice_activity_close_exit.xml b/core/res/res/anim/voice_activity_close_exit.xml
new file mode 100644
index 0000000..023b012
--- /dev/null
+++ b/core/res/res/anim/voice_activity_close_exit.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+	android:shareInterpolator="false">
+    <translate android:fromYDelta="0" android:toYDelta="-20%"
+			android:interpolator="@interpolator/accelerate_quint"
+            android:duration="@android:integer/config_shortAnimTime"/>
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+			android:interpolator="@interpolator/accelerate_cubic"
+            android:duration="@android:integer/config_shortAnimTime"/>
+</set>
diff --git a/core/res/res/anim/voice_activity_open_enter.xml b/core/res/res/anim/voice_activity_open_enter.xml
new file mode 100644
index 0000000..57fba2a
--- /dev/null
+++ b/core/res/res/anim/voice_activity_open_enter.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/fade_in.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+		android:shareInterpolator="false">
+    <translate android:fromYDelta="-20%" android:toYDelta="0"
+	        android:interpolator="@interpolator/decelerate_quint"
+            android:duration="@android:integer/config_shortAnimTime"/>
+    <alpha android:fromAlpha="0.5" android:toAlpha="1.0"
+			android:interpolator="@interpolator/decelerate_cubic"
+            android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/core/res/res/anim/voice_activity_open_exit.xml b/core/res/res/anim/voice_activity_open_exit.xml
new file mode 100644
index 0000000..4f3d3d5
--- /dev/null
+++ b/core/res/res/anim/voice_activity_open_exit.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+	android:shareInterpolator="false">
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+			android:interpolator="@interpolator/accelerate_cubic"
+            android:duration="@android:integer/config_shortAnimTime"/>
+</set>
diff --git a/core/res/res/anim/voice_layer_enter.xml b/core/res/res/anim/voice_layer_enter.xml
new file mode 100644
index 0000000..57fba2a
--- /dev/null
+++ b/core/res/res/anim/voice_layer_enter.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/fade_in.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+		android:shareInterpolator="false">
+    <translate android:fromYDelta="-20%" android:toYDelta="0"
+	        android:interpolator="@interpolator/decelerate_quint"
+            android:duration="@android:integer/config_shortAnimTime"/>
+    <alpha android:fromAlpha="0.5" android:toAlpha="1.0"
+			android:interpolator="@interpolator/decelerate_cubic"
+            android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/core/res/res/anim/voice_layer_exit.xml b/core/res/res/anim/voice_layer_exit.xml
new file mode 100644
index 0000000..023b012
--- /dev/null
+++ b/core/res/res/anim/voice_layer_exit.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+	android:shareInterpolator="false">
+    <translate android:fromYDelta="0" android:toYDelta="-20%"
+			android:interpolator="@interpolator/accelerate_quint"
+            android:duration="@android:integer/config_shortAnimTime"/>
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+			android:interpolator="@interpolator/accelerate_cubic"
+            android:duration="@android:integer/config_shortAnimTime"/>
+</set>
diff --git a/core/res/res/layout/screen_toolbar.xml b/core/res/res/layout/screen_toolbar.xml
new file mode 100644
index 0000000..290c7da
--- /dev/null
+++ b/core/res/res/layout/screen_toolbar.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+
+<!--
+This is an optimized layout for a screen with a toolbar enabled.
+-->
+
+<com.android.internal.widget.ActionBarOverlayLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/decor_content_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:splitMotionEvents="false"
+    android:theme="?attr/actionBarTheme">
+    <FrameLayout android:id="@android:id/content"
+                 android:layout_width="match_parent"
+                 android:layout_height="match_parent" />
+    <com.android.internal.widget.ActionBarContainer
+        android:id="@+id/action_bar_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        style="?attr/actionBarStyle"
+        android:viewName="android:action_bar"
+        android:gravity="top">
+        <Toolbar
+            android:id="@+id/action_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            style="?attr/toolbarStyle" />
+        <com.android.internal.widget.ActionBarContextView
+            android:id="@+id/action_context_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            style="?attr/actionModeStyle" />
+    </com.android.internal.widget.ActionBarContainer>
+</com.android.internal.widget.ActionBarOverlayLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c05dfca..5fec907 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -493,6 +493,9 @@
              {@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
         <attr name="windowAllowExitTransitionOverlap" format="boolean"/>
 
+        <!-- Internal layout used internally for window decor -->
+        <attr name="windowActionBarFullscreenDecorLayout" format="reference" />
+
         <!-- ============ -->
         <!-- Alert Dialog styles -->
         <!-- ============ -->
@@ -685,6 +688,7 @@
         <!-- Default ActivityChooserView style. -->
         <attr name="activityChooserViewStyle" format="reference" />
 
+        <!-- Default Toolbar style. -->
         <attr name="toolbarStyle" format="reference" />
 
         <!-- Fast scroller styles -->
@@ -1713,6 +1717,7 @@
         <attr name="windowSwipeToDismiss" />
         <attr name="windowContentTransitions" />
         <attr name="windowContentTransitionManager" />
+        <attr name="windowActionBarFullscreenDecorLayout" />
 
         <!-- The minimum width the window is allowed to be, along the major
              axis of the screen.  That is, when in landscape.  Can be either
@@ -6398,11 +6403,17 @@
         <attr name="indeterminateProgressStyle" format="reference" />
         <!-- Specifies the horizontal padding on either end for an embedded progress bar. -->
         <attr name="progressBarPadding" format="dimension" />
+        <!-- Up navigation glyph -->
+        <attr name="homeAsUpIndicator" />
         <!-- Specifies padding that should be applied to the left and right sides of
              system-provided items in the bar. -->
         <attr name="itemPadding" format="dimension" />
         <!-- Set true to hide the action bar on a vertical nested scroll of content. -->
         <attr name="hideOnContentScroll" format="boolean" />
+        <attr name="contentInsetStart" format="dimension" />
+        <attr name="contentInsetEnd" format="dimension" />
+        <attr name="contentInsetLeft" format="dimension" />
+        <attr name="contentInsetRight" format="dimension" />
     </declare-styleable>
 
     <declare-styleable name="ActionMode">
@@ -6653,10 +6664,19 @@
         <attr name="titleMarginEnd" format="dimension" />
         <attr name="titleMarginTop" format="dimension" />
         <attr name="titleMarginBottom" format="dimension" />
-        <attr name="contentInsetStart" format="dimension" />
-        <attr name="contentInsetEnd" format="dimension" />
-        <attr name="contentInsetLeft" format="dimension" />
-        <attr name="contentInsetRight" format="dimension" />
+        <attr name="contentInsetStart" />
+        <attr name="contentInsetEnd" />
+        <attr name="contentInsetLeft" />
+        <attr name="contentInsetRight" />
+        <attr name="maxButtonHeight" format="dimension" />
+        <attr name="navigationButtonStyle" format="reference" />
+        <attr name="buttonGravity">
+            <!-- Push object to the top of its container, not changing its size. -->
+            <flag name="top" value="0x30" />
+            <!-- Push object to the bottom of its container, not changing its size. -->
+            <flag name="bottom" value="0x50" />
+        </attr>
+        <attr name="collapseIcon" format="reference" />
     </declare-styleable>
 
     <declare-styleable name="Toolbar_LayoutParams">
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index f6cd9e8..933063f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -171,8 +171,8 @@
 
     <!-- Window animations that are applied to voice interaction overlay windows. -->
     <style name="Animation.VoiceInteractionSession">
-        <item name="windowEnterAnimation">@anim/input_method_enter</item>
-        <item name="windowExitAnimation">@anim/input_method_exit</item>
+        <item name="windowEnterAnimation">@anim/voice_layer_enter</item>
+        <item name="windowExitAnimation">@anim/voice_layer_exit</item>
     </style>
 
     <!-- Special optional fancy IM animations. @hide -->
@@ -1197,6 +1197,16 @@
         <item name="android:subtitleTextAppearance">@android:style/TextAppearance.Widget.Toolbar.Subtitle</item>
         <item name="android:minHeight">?android:attr/actionBarSize</item>
         <item name="android:titleMargins">4dp</item>
+        <item name="android:maxButtonHeight">56dp</item>
+        <item name="android:buttonGravity">top</item>
+        <item name="android:navigationButtonStyle">@android:style/Widget.Toolbar.Button.Navigation</item>
+        <item name="android:collapseIcon">?android:attr/homeAsUpIndicator</item>
+    </style>
+
+    <style name="Widget.Toolbar.Button.Navigation" parent="@android:style/Widget">
+        <item name="android:background">?android:attr/selectableItemBackground</item>
+        <item name="android:minWidth">56dp</item>
+        <item name="android:scaleType">center</item>
     </style>
 
     <style name="TextAppearance.Widget.ActionBar.Title"
@@ -2394,7 +2404,6 @@
         <item name="android:background">@android:drawable/ab_transparent_light_holo</item>
         <item name="android:backgroundStacked">@android:drawable/ab_stacked_transparent_light_holo</item>
         <item name="android:backgroundSplit">@android:drawable/ab_bottom_transparent_light_holo</item>
-        <item name="android:homeAsUpIndicator">@android:drawable/ic_ab_back_holo_light</item>
         <item name="android:progressBarStyle">@android:style/Widget.Holo.Light.ProgressBar.Horizontal</item>
         <item name="android:indeterminateProgressStyle">@android:style/Widget.Holo.Light.ProgressBar</item>
     </style>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 2e7a5b1..ea32681 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -773,7 +773,7 @@
         <item name="background">@null</item>
         <item name="backgroundStacked">@null</item>
         <item name="backgroundSplit">@null</item>
-        <item name="displayOptions">useLogo|showHome|showTitle</item>
+        <item name="displayOptions">showTitle</item>
         <item name="divider">?attr/dividerVertical</item>
         <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
         <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
@@ -783,6 +783,7 @@
         <item name="itemPadding">8dip</item>
         <item name="homeLayout">@layout/action_bar_home_quantum</item>
         <item name="gravity">center_vertical</item>
+        <item name="contentInsetStart">56dp</item>
     </style>
 
     <style name="Widget.Quantum.ActionBar.Solid">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 69f73e5..6e1629b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1286,6 +1286,10 @@
   <java-symbol type="anim" name="dock_left_exit" />
   <java-symbol type="anim" name="dock_right_enter" />
   <java-symbol type="anim" name="dock_right_exit" />
+  <java-symbol type="anim" name="voice_activity_close_exit" />
+  <java-symbol type="anim" name="voice_activity_close_enter" />
+  <java-symbol type="anim" name="voice_activity_open_exit" />
+  <java-symbol type="anim" name="voice_activity_open_enter" />
 
   <java-symbol type="array" name="config_hdmiCecLogicalDeviceType" />
   <java-symbol type="array" name="config_keyboardTapVibePattern" />
@@ -1862,6 +1866,7 @@
   <java-symbol type="attr" name="toolbarStyle" />
   <java-symbol type="attr" name="titleTextAppearance" />
   <java-symbol type="attr" name="subtitleTextAppearance" />
+  <java-symbol type="attr" name="windowActionBarFullscreenDecorLayout" />
   <java-symbol type="drawable" name="ic_lock_bugreport" />
   <java-symbol type="id" name="icon_frame" />
   <java-symbol type="style" name="Animation.VolumePanel" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index aaab949..41f4ff8 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -192,6 +192,7 @@
         <item name="windowDrawsSystemBarBackgrounds">false</item>
         <item name="statusBarColor">@android:color/black</item>
         <item name="navigationBarColor">@android:color/black</item>
+        <item name="windowActionBarFullscreenDecorLayout">@layout/screen_action_bar</item>
 
         <!-- Define these here; ContextThemeWrappers around themes that define them should
              always clear these values. -->
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index bb787bb..484c694 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -162,6 +162,7 @@
         <item name="windowActionBar">true</item>
         <item name="windowActionModeOverlay">false</item>
         <item name="windowDrawsSystemBarBackgrounds">true</item>
+        <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
         <item name="statusBarColor">?attr/colorPrimaryDark</item>
         <item name="navigationBarColor">?attr/colorPrimaryDark</item>
 
@@ -505,6 +506,7 @@
         <item name="windowActionBar">true</item>
         <item name="windowActionModeOverlay">false</item>
         <item name="windowDrawsSystemBarBackgrounds">true</item>
+        <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
         <item name="statusBarColor">?attr/colorPrimaryDark</item>
         <item name="navigationBarColor">?attr/colorPrimaryDark</item>
 
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
new file mode 100644
index 0000000..c088906
--- /dev/null
+++ b/media/java/android/media/AudioDevicePort.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+/**
+ * The AudioDevicePort is a specialized type of AudioPort
+ * describing an input (e.g microphone) or output device (e.g speaker)
+ * of the system.
+ * An AudioDevicePort is an AudioPort controlled by the audio HAL, almost always a physical
+ * device at the boundary of the audio system.
+ * In addition to base audio port attributes, the device descriptor contains:
+ * - the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
+ * - the device address (e.g MAC adddress for AD2P sink).
+ * @see AudioPort
+ * @hide
+ */
+
+public class AudioDevicePort extends AudioPort {
+
+    private final int mType;
+    private final String mAddress;
+
+    AudioDevicePort(AudioHandle handle, int[] samplingRates, int[] channelMasks,
+            int[] formats, AudioGain[] gains, int type, String address) {
+        super(handle,
+             (AudioManager.isInputDevice(type) == true)  ?
+                        AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK,
+             samplingRates, channelMasks, formats, gains);
+        mType = type;
+        mAddress = address;
+    }
+
+    /**
+     * Get the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
+     */
+    public int type() {
+        return mType;
+    }
+
+    /**
+     * Get the device address. Address format varies with the device type.
+     * - USB devices ({@link AudioManager#DEVICE_OUT_USB_DEVICE},
+     * {@link AudioManager#DEVICE_IN_USB_DEVICE}) use an address composed of the ALSA card number
+     * and device number: "card=2;device=1"
+     * - Bluetooth devices ({@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO},
+     * {@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO}, {@link AudioManager#DEVICE_OUT_BLUETOOTH_A2DP})
+     * use the MAC address of the bluetooth device in the form "00:11:22:AA:BB:CC" as reported by
+     * {@link BluetoothDevice#getAddress()}.
+     * - Deivces that do not have an address will indicate an empty string "".
+     */
+    public String address() {
+        return mAddress;
+    }
+
+    /**
+     * Build a specific configuration of this audio device port for use by methods
+     * like AudioManager.connectAudioPatch().
+     */
+    public AudioDevicePortConfig buildConfig(int samplingRate, int channelMask, int format,
+                                          AudioGainConfig gain) {
+        return new AudioDevicePortConfig(this, samplingRate, channelMask, format, gain);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioDevicePort)) {
+            return false;
+        }
+        return super.equals(o);
+    }
+}
diff --git a/media/java/android/media/AudioDevicePortConfig.java b/media/java/android/media/AudioDevicePortConfig.java
new file mode 100644
index 0000000..a381e10
--- /dev/null
+++ b/media/java/android/media/AudioDevicePortConfig.java
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+/**
+ * An AudioDevicePortConfig describes a possible configuration of an output or input device
+ * (speaker, headphone, microphone ...).
+ * It is used to specify a sink or source when creating a connection with
+ * AudioManager.connectAudioPatch().
+ * An AudioDevicePortConfig is obtained from AudioDevicePort.buildConfig().
+ * @hide
+ */
+
+public class AudioDevicePortConfig extends AudioPortConfig {
+    AudioDevicePortConfig(AudioDevicePort devicePort, int samplingRate, int channelMask,
+            int format, AudioGainConfig gain) {
+        super((AudioPort)devicePort, samplingRate, channelMask, format, gain);
+    }
+
+    /**
+     * Returns the audio device port this AudioDevicePortConfig is issued from.
+     */
+    public AudioDevicePort port() {
+        return (AudioDevicePort)mPort;
+    }
+}
+
diff --git a/media/java/android/media/AudioGain.java b/media/java/android/media/AudioGain.java
new file mode 100644
index 0000000..57709d5
--- /dev/null
+++ b/media/java/android/media/AudioGain.java
@@ -0,0 +1,159 @@
+/*
+ * 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;
+
+/**
+ * The AudioGain describes a gain controller. Gain controllers are exposed by
+ * audio ports when the gain is configurable at this port's input or output.
+ * Gain values are expressed in millibels.
+ * A gain controller has the following attributes:
+ * - mode: defines modes of operation or features
+ *    MODE_JOINT: all channel gains are controlled simultaneously
+ *    MODE_CHANNELS: each channel gain is controlled individually
+ *    MODE_RAMP: ramps can be applied when gain changes
+ * - channel mask: indicates for which channels the gain can be controlled
+ * - min value: minimum gain value in millibel
+ * - max value: maximum gain value in millibel
+ * - default value: gain value after reset in millibel
+ * - step value: granularity of gain control in millibel
+ * - min ramp duration: minimum ramp duration in milliseconds
+ * - max ramp duration: maximum ramp duration in milliseconds
+ *
+ * This object is always created by the framework and read only by applications.
+ * Applications get a list of AudioGainDescriptors from AudioPortDescriptor.gains() and can build a
+ * valid gain configuration from AudioGain.buildConfig()
+ * @hide
+ */
+public class AudioGain {
+
+    /**
+     * Bit of AudioGain.mode() field indicating that
+     * all channel gains are controlled simultaneously
+     */
+    public static final int MODE_JOINT = 1;
+    /**
+     * Bit of AudioGain.mode() field indicating that
+     * each channel gain is controlled individually
+     */
+    public static final int MODE_CHANNELS = 2;
+    /**
+     * Bit of AudioGain.mode() field indicating that
+     * ramps can be applied when gain changes. The type of ramp (linear, log etc...) is
+     * implementation specific.
+     */
+    public static final int MODE_RAMP = 4;
+
+    private final int mIndex;
+    private final int mMode;
+    private final int mChannelMask;
+    private final int mMinValue;
+    private final int mMaxValue;
+    private final int mDefaultValue;
+    private final int mStepValue;
+    private final int mRampDurationMinMs;
+    private final int mRampDurationMaxMs;
+
+    // The channel mask passed to the constructor is as specified in AudioFormat
+    // (e.g. AudioFormat.CHANNEL_OUT_STEREO)
+    AudioGain(int index, int mode, int channelMask,
+                        int minValue, int maxValue, int defaultValue, int stepValue,
+                        int rampDurationMinMs, int rampDurationMaxMs) {
+        mIndex = index;
+        mMode = mode;
+        mChannelMask = channelMask;
+        mMinValue = minValue;
+        mMaxValue = maxValue;
+        mDefaultValue = defaultValue;
+        mStepValue = stepValue;
+        mRampDurationMinMs = rampDurationMinMs;
+        mRampDurationMaxMs = rampDurationMaxMs;
+    }
+
+    /**
+     * Bit field indicating supported modes of operation
+     */
+    public int mode() {
+        return mMode;
+    }
+
+    /**
+     * Indicates for which channels the gain can be controlled
+     * (e.g. AudioFormat.CHANNEL_OUT_STEREO)
+     */
+    public int channelMask() {
+        return mChannelMask;
+    }
+
+    /**
+     * Minimum gain value in millibel
+     */
+    public int minValue() {
+        return mMinValue;
+    }
+
+    /**
+     * Maximum gain value in millibel
+     */
+    public int maxValue() {
+        return mMaxValue;
+    }
+
+    /**
+     * Default gain value in millibel
+     */
+    public int defaultValue() {
+        return mDefaultValue;
+    }
+
+    /**
+     * Granularity of gain control in millibel
+     */
+    public int stepValue() {
+        return mStepValue;
+    }
+
+    /**
+     * Minimum ramp duration in milliseconds
+     * 0 if MODE_RAMP not set
+     */
+    public int rampDurationMinMs() {
+        return mRampDurationMinMs;
+    }
+
+    /**
+     * Maximum ramp duration in milliseconds
+     * 0 if MODE_RAMP not set
+     */
+    public int rampDurationMaxMs() {
+        return mRampDurationMaxMs;
+    }
+
+    /**
+     * Build a valid gain configuration for this gain controller for use by
+     * AudioPortDescriptor.setGain()
+     * @param mode: desired mode of operation
+     * @param channelMask: channels of which the gain should be modified.
+     * @param values: gain values for each channels.
+     * @param rampDurationMs: ramp duration if mode MODE_RAMP is set.
+     * ignored if MODE_JOINT.
+     */
+    public AudioGainConfig buildConfig(int mode, int channelMask,
+                                       int[] values, int rampDurationMs) {
+        //TODO: check params here
+        return new AudioGainConfig(mIndex, this, mode, channelMask, values, rampDurationMs);
+    }
+}
diff --git a/media/java/android/media/AudioGainConfig.java b/media/java/android/media/AudioGainConfig.java
new file mode 100644
index 0000000..ea61679
--- /dev/null
+++ b/media/java/android/media/AudioGainConfig.java
@@ -0,0 +1,84 @@
+/*
+ * 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;
+
+/**
+ * The AudioGainConfig is used by APIs setting or getting values on a given gain
+ * controller. It contains a valid configuration (value, channels...) for a gain controller
+ * exposed by an audio port.
+ * @see AudioGain
+ * @see AudioPort
+ * @hide
+ */
+public class AudioGainConfig {
+    AudioGain mGain;
+    private final int mIndex;
+    private final int mMode;
+    private final int mChannelMask;
+    private final int mValues[];
+    private final int mRampDurationMs;
+
+    AudioGainConfig(int index, AudioGain gain, int mode, int channelMask,
+            int[] values, int rampDurationMs) {
+        mIndex = index;
+        mGain = gain;
+        mMode = mode;
+        mChannelMask = channelMask;
+        mValues = values;
+        mRampDurationMs = rampDurationMs;
+    }
+
+    /**
+     * get the index of the parent gain.
+     * frameworks use only.
+     */
+    int index() {
+        return mIndex;
+    }
+
+    /**
+     * Bit field indicating requested modes of operation. See {@link AudioGain#MODE_JOINT},
+     * {@link AudioGain#MODE_CHANNELS}, {@link AudioGain#MODE_RAMP}
+     */
+    public int mode() {
+        return mMode;
+    }
+
+    /**
+     * Indicates for which channels the gain is set.
+     * See {@link AudioFormat#CHANNEL_OUT_STEREO}, {@link AudioFormat#CHANNEL_OUT_MONO} ...
+     */
+    public int channelMask() {
+        return mChannelMask;
+    }
+
+    /**
+     * Gain values for each channel in the order of bits set in
+     * channelMask() from LSB to MSB
+     */
+    public int[] values() {
+        return mValues;
+    }
+
+    /**
+     * Ramp duration in milliseconds. N/A if mode() does not
+     * specify MODE_RAMP.
+     */
+    public int rampDurationMs() {
+        return mRampDurationMs;
+    }
+}
diff --git a/media/java/android/media/AudioHandle.java b/media/java/android/media/AudioHandle.java
new file mode 100644
index 0000000..b58e7a3
--- /dev/null
+++ b/media/java/android/media/AudioHandle.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+/**
+ * The AudioHandle is used by the audio framework implementation to
+ * uniquely identify a particular component of the routing topology
+ * (AudioPort or AudioPatch)
+ * It is not visible or used at the API.
+ */
+class AudioHandle {
+    private final int mId;
+
+    AudioHandle(int id) {
+        mId = id;
+    }
+
+    int id() {
+        return mId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioHandle)) {
+            return false;
+        }
+        AudioHandle ah = (AudioHandle)o;
+        return mId == ah.id();
+    }
+
+    @Override
+    public int hashCode() {
+        return mId;
+    }
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 9803161..f4affa0 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -39,6 +39,7 @@
 import android.view.KeyEvent;
 
 import java.util.HashMap;
+import java.util.ArrayList;
 
 /**
  * AudioManager provides access to volume and ringer mode control.
@@ -2966,4 +2967,151 @@
             Log.w(TAG, "Error disabling safe media volume", e);
         }
     }
+
+    /**
+     * Return codes for listAudioPorts(), createAudioPatch() ...
+     */
+
+    /** @hide
+     */
+    public static final int SUCCESS = AudioSystem.SUCCESS;
+    /** @hide
+     */
+    public static final int ERROR = AudioSystem.ERROR;
+    /** @hide
+     */
+    public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
+    /** @hide
+     */
+    public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
+    /** @hide
+     */
+    public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
+    /** @hide
+     */
+    public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
+    /** @hide
+     */
+    public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
+
+    /**
+     * Returns a list of descriptors for all audio ports managed by the audio framework.
+     * Audio ports are nodes in the audio framework or audio hardware that can be configured
+     * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
+     * See AudioPort for a list of attributes of each audio port.
+     * @param ports An AudioPort ArrayList where the list will be returned.
+     * @hide
+     */
+    public int listAudioPorts(ArrayList<AudioPort> ports) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
+     * @see listAudioPorts(ArrayList<AudioPort>)
+     * @hide
+     */
+    public int listAudioDevicePorts(ArrayList<AudioPort> devices) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Create a connection between two or more devices. The framework will reject the request if
+     * device types are not compatible or the implementation does not support the requested
+     * configuration.
+     * NOTE: current implementation is limited to one source and one sink per patch.
+     * @param patch AudioPatch array where the newly created patch will be returned.
+     *              As input, if patch[0] is not null, the specified patch will be replaced by the
+     *              new patch created. This avoids calling releaseAudioPatch() when modifying a
+     *              patch and allows the implementation to optimize transitions.
+     * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
+     * @param sinks   List of sink audio ports. All must be AudioPort.ROLE_SINK.
+     *
+     * @return - {@link #SUCCESS} if connection is successful.
+     *         - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
+     *         - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
+     *         - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
+     *         a patch.
+     *         - {@link #ERROR_DEAD_OBJECT} if the server process is dead
+     *         - {@link #ERROR} if patch cannot be connected for any other reason.
+     *
+     *         patch[0] contains the newly created patch
+     * @hide
+     */
+    public int createAudioPatch(AudioPatch[] patch,
+                                 AudioPortConfig[] sources,
+                                 AudioPortConfig[] sinks) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Releases an existing audio patch connection.
+     * @param patch The audio patch to disconnect.
+     * @return - {@link #SUCCESS} if disconnection is successful.
+     *         - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
+     *         - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
+     *         a patch.
+     *         - {@link #ERROR_DEAD_OBJECT} if the server process is dead
+     *         - {@link #ERROR} if patch cannot be released for any other reason.
+     * @hide
+     */
+    public int releaseAudioPatch(AudioPatch patch) {
+        return  ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * List all existing connections between audio ports.
+     * @param patches An AudioPatch array where the list will be returned.
+     * @hide
+     */
+    public int listAudioPatches(ArrayList<AudioPatch> patches) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
+     * AudioGain.buildConfig()
+     * @hide
+     */
+    public int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Listener registered by client to be notified upon new audio port connections,
+     * disconnections or attributes update.
+     * @hide
+     */
+    public interface OnAudioPortUpdateListener {
+        /**
+         * Callback method called upon audio port list update.
+         * @param portList the updated list of audio ports
+         */
+        public void OnAudioPortListUpdate(AudioPort[] portList);
+
+        /**
+         * Callback method called upon audio patch list update.
+         * @param patchList the updated list of audio patches
+         */
+        public void OnAudioPatchListUpdate(AudioPatch[] patchList);
+
+        /**
+         * Callback method called when the mediaserver dies
+         */
+        public void OnServiceDied();
+    }
+
+    /**
+     * Register an audio port update listener.
+     * @hide
+     */
+    public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
+    }
+
+    /**
+     * Unregister an audio port update listener.
+     * @hide
+     */
+    public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
+    }
 }
diff --git a/media/java/android/media/AudioMixPort.java b/media/java/android/media/AudioMixPort.java
new file mode 100644
index 0000000..1500a43
--- /dev/null
+++ b/media/java/android/media/AudioMixPort.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+/**
+ * The AudioMixPort is a specialized type of AudioPort
+ * describing an audio mix or stream at an input or output stream of the audio
+ * framework.
+ * @see AudioPort
+ * @hide
+ */
+
+public class AudioMixPort extends AudioPort {
+
+    AudioMixPort(AudioHandle handle, int role, int[] samplingRates, int[] channelMasks,
+            int[] formats, AudioGain[] gains) {
+        super(handle, role, samplingRates, channelMasks, formats, gains);
+    }
+
+    /**
+     * Build a specific configuration of this audio mix port for use by methods
+     * like AudioManager.connectAudioPatch().
+     */
+    public AudioMixPortConfig buildConfig(int samplingRate, int channelMask, int format,
+                                       AudioGainConfig gain) {
+        return new AudioMixPortConfig(this, samplingRate, channelMask, format, gain);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioMixPort)) {
+            return false;
+        }
+        return super.equals(o);
+    }
+
+}
diff --git a/media/java/android/media/AudioMixPortConfig.java b/media/java/android/media/AudioMixPortConfig.java
new file mode 100644
index 0000000..8eb9ef46
--- /dev/null
+++ b/media/java/android/media/AudioMixPortConfig.java
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+/**
+ * An AudioMixPortConfig describes a possible configuration of an output or input mixer.
+ * It is used to specify a sink or source when creating a connection with
+ * AudioManager.connectAudioPatch().
+ * An AudioMixPortConfig is obtained from AudioMixPort.buildConfig().
+ * @hide
+ */
+
+public class AudioMixPortConfig extends AudioPortConfig {
+
+    AudioMixPortConfig(AudioMixPort mixPort, int samplingRate, int channelMask, int format,
+                AudioGainConfig gain) {
+        super((AudioPort)mixPort, samplingRate, channelMask, format, gain);
+    }
+
+    /**
+     * Returns the audio mix port this AudioMixPortConfig is issued from.
+     */
+    public AudioMixPort port() {
+        return (AudioMixPort)mPort;
+    }
+}
+
diff --git a/media/java/android/media/AudioPatch.java b/media/java/android/media/AudioPatch.java
new file mode 100644
index 0000000..72291f6
--- /dev/null
+++ b/media/java/android/media/AudioPatch.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+
+/**
+ * An AudioPatch describes a connection between audio sources and audio sinks.
+ * An audio source can be an output mix (playback AudioBus) or an input device (microphone).
+ * An audio sink can be an output device (speaker) or an input mix (capture AudioBus).
+ * An AudioPatch is created by AudioManager.connectAudioPatch() and released by
+ * AudioManager.disconnectAudioPatch()
+ * It contains the list of source and sink AudioPortConfig showing audio port configurations
+ * being connected.
+ * @hide
+ */
+public class AudioPatch {
+
+    private final AudioHandle mHandle;
+    private final AudioPortConfig[] mSources;
+    private final AudioPortConfig[] mSinks;
+
+    AudioPatch(AudioHandle patchHandle, AudioPortConfig[] sources, AudioPortConfig[] sinks) {
+        mHandle = patchHandle;
+        mSources = sources;
+        mSinks = sinks;
+    }
+
+    /**
+     * Retrieve the list of sources of this audio patch.
+     */
+    public AudioPortConfig[] sources() {
+        return mSources;
+    }
+
+    /**
+     * Retreive the list of sinks of this audio patch.
+     */
+    public AudioPortConfig[] sinks() {
+        return mSinks;
+    }
+}
diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java
new file mode 100644
index 0000000..9aeddef
--- /dev/null
+++ b/media/java/android/media/AudioPort.java
@@ -0,0 +1,174 @@
+/*
+ * 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;
+
+
+/**
+ * An audio port is a node of the audio framework or hardware that can be connected to or
+ * disconnect from another audio node to create a specific audio routing configuration.
+ * Examples of audio ports are an output device (speaker) or an output mix (see AudioMixPort).
+ * All attributes that are relevant for applications to make routing selection are decribed
+ * in an AudioPort,  in particular:
+ * - possible channel mask configurations.
+ * - audio format (PCM 16bit, PCM 24bit...)
+ * - gain: a port can be associated with one or more gain controllers (see AudioGain).
+ *
+ * This object is always created by the framework and read only by applications.
+ * A list of all audio port descriptors currently available for applications to control
+ * is obtained by AudioManager.listAudioPorts().
+ * An application can obtain an AudioPortConfig for a valid configuration of this port
+ * by calling AudioPort.buildConfig() and use this configuration
+ * to create a connection between audio sinks and sources with AudioManager.connectAudioPatch()
+ *
+ * @hide
+ */
+public class AudioPort {
+
+    /**
+     * For use by the audio framework.
+     */
+    public static final int ROLE_NONE = 0;
+    /**
+     * The audio port is a source (produces audio)
+     */
+    public static final int ROLE_SOURCE = 1;
+    /**
+     * The audio port is a sink (consumes audio)
+     */
+    public static final int ROLE_SINK = 2;
+
+    /**
+     * audio port type for use by audio framework implementation
+     */
+    public static final int TYPE_NONE = 0;
+    /**
+     */
+    public static final int TYPE_DEVICE = 1;
+    /**
+     */
+    public static final int TYPE_SUBMIX = 2;
+    /**
+     */
+    public static final int TYPE_SESSION = 3;
+
+
+    AudioHandle mHandle;
+    private final int mRole;
+    private final int[] mSamplingRates;
+    private final int[] mChannelMasks;
+    private final int[] mFormats;
+    private final AudioGain[] mGains;
+    private AudioPortConfig mActiveConfig;
+
+    AudioPort(AudioHandle handle, int role, int[] samplingRates, int[] channelMasks,
+            int[] formats, AudioGain[] gains) {
+        mHandle = handle;
+        mRole = role;
+        mSamplingRates = samplingRates;
+        mChannelMasks = channelMasks;
+        mFormats = formats;
+        mGains = gains;
+    }
+
+    AudioHandle handle() {
+        return mHandle;
+    }
+
+    /**
+     * Get the audio port role
+     */
+    public int role() {
+        return mRole;
+    }
+
+    /**
+     * Get the list of supported sampling rates
+     * Empty array if sampling rate is not relevant for this audio port
+     */
+    public int[] samplingRates() {
+        return mSamplingRates;
+    }
+
+    /**
+     * Get the list of supported channel mask configurations
+     * (e.g AudioFormat.CHANNEL_OUT_STEREO)
+     * Empty array if channel mask is not relevant for this audio port
+     */
+    public int[] channelMasks() {
+        return mChannelMasks;
+    }
+
+    /**
+     * Get the list of supported audio format configurations
+     * (e.g AudioFormat.ENCODING_PCM_16BIT)
+     * Empty array if format is not relevant for this audio port
+     */
+    public int[] formats() {
+        return mFormats;
+    }
+
+    /**
+     * Get the list of gain descriptors
+     * Empty array if this port does not have gain control
+     */
+    public AudioGain[] gains() {
+        return mGains;
+    }
+
+    /**
+     * Get the gain descriptor at a given index
+     */
+    AudioGain gain(int index) {
+        return mGains[index];
+    }
+
+    /**
+     * Build a specific configuration of this audio port for use by methods
+     * like AudioManager.connectAudioPatch().
+     * @param channelMask The desired channel mask. AudioFormat.CHANNEL_OUT_DEFAULT if no change
+     * from active configuration requested.
+     * @param format The desired audio format. AudioFormat.ENCODING_DEFAULT if no change
+     * from active configuration requested.
+     * @param gain The desired gain. null if no gain changed requested.
+     */
+    public AudioPortConfig buildConfig(int samplingRate, int channelMask, int format,
+                                        AudioGainConfig gain) {
+        return new AudioPortConfig(this, samplingRate, channelMask, format, gain);
+    }
+
+    /**
+     * Get currently active configuration of this audio port.
+     */
+    public AudioPortConfig activeConfig() {
+        return mActiveConfig;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioPort)) {
+            return false;
+        }
+        AudioPort ap = (AudioPort)o;
+        return mHandle.equals(ap.handle());
+    }
+
+    @Override
+    public int hashCode() {
+        return mHandle.hashCode();
+    }
+}
+
diff --git a/media/java/android/media/AudioPortConfig.java b/media/java/android/media/AudioPortConfig.java
new file mode 100644
index 0000000..5dc768d
--- /dev/null
+++ b/media/java/android/media/AudioPortConfig.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+/**
+ * An AudioPortConfig contains a possible configuration of an audio port chosen
+ * among all possible attributes described by an AudioPort.
+ * An AudioPortConfig is created by AudioPort.buildConfiguration().
+ * AudioPorts are used to specify the sources and sinks of a patch created
+ * with AudioManager.connectAudioPatch().
+ * Several specialized versions of AudioPortConfig exist to handle different categories of
+ * audio ports and their specific attributes:
+ * - AudioDevicePortConfig for input (e.g micropohone) and output devices (e.g speaker)
+ * - AudioMixPortConfig for input or output streams of the audio framework.
+ * @hide
+ */
+
+public class AudioPortConfig {
+    final AudioPort mPort;
+    private final int mSamplingRate;
+    private final int mChannelMask;
+    private final int mFormat;
+    private final AudioGainConfig mGain;
+
+    // mConfigMask indicates which fields in this configuration should be
+    // taken into account. Used with AudioSystem.setAudioPortConfig()
+    // framework use only.
+    static final int SAMPLE_RATE  = 0x1;
+    static final int CHANNEL_MASK = 0x2;
+    static final int FORMAT       = 0x4;
+    static final int GAIN         = 0x8;
+    int mConfigMask;
+
+    AudioPortConfig(AudioPort port, int samplingRate, int channelMask, int format,
+            AudioGainConfig gain) {
+        mPort = port;
+        mSamplingRate = samplingRate;
+        mChannelMask = channelMask;
+        mFormat = format;
+        mGain = gain;
+        mConfigMask = 0;
+    }
+
+    /**
+     * Returns the audio port this AudioPortConfig is issued from.
+     */
+    public AudioPort port() {
+        return mPort;
+    }
+
+    /**
+     * Sampling rate configured for this AudioPortConfig.
+     */
+    public int samplingRate() {
+        return mSamplingRate;
+    }
+
+    /**
+     * Channel mask configuration (e.g AudioFormat.CHANNEL_CONFIGURATION_STEREO).
+     */
+    public int channelMask() {
+        return mChannelMask;
+    }
+
+    /**
+     * Audio format configuration (e.g AudioFormat.ENCODING_PCM_16BIT).
+     */
+    public int format() {
+        return mFormat;
+    }
+
+    /**
+     * The gain configuration if this port supports gain control, null otherwise
+     * @see AudioGainConfig.
+     */
+    public AudioGainConfig gain() {
+        return mGain;
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index a3caba2..afc2931 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -41,6 +41,7 @@
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
+import android.hardware.camera2.params.TonemapCurve;
 import android.hardware.camera2.utils.TypeReference;
 
 import static android.hardware.camera2.impl.CameraMetadataNative.*;
@@ -49,6 +50,7 @@
 import java.lang.reflect.Array;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -1015,6 +1017,29 @@
             assertNull(resultSimpleFaces[i].getMouthPosition());
         }
 
+        /**
+         * Read/Write TonemapCurve
+         */
+        float[] red = new float[] {0.0f, 0.0f, 1.0f, 1.0f};
+        float[] green = new float[] {0.0f, 1.0f, 1.0f, 0.0f};
+        float[] blue = new float[] {
+                0.0000f, 0.0000f, 0.0667f, 0.2920f, 0.1333f, 0.4002f, 0.2000f, 0.4812f,
+                0.2667f, 0.5484f, 0.3333f, 0.6069f, 0.4000f, 0.6594f, 0.4667f, 0.7072f,
+                0.5333f, 0.7515f, 0.6000f, 0.7928f, 0.6667f, 0.8317f, 0.7333f, 0.8685f,
+                0.8000f, 0.9035f, 0.8667f, 0.9370f, 0.9333f, 0.9691f, 1.0000f, 1.0000f};
+        TonemapCurve tcIn = new TonemapCurve(red, green, blue);
+        mMetadata.set(CaptureResult.TONEMAP_CURVE, tcIn);
+        float[] redOut = mMetadata.get(CaptureResult.TONEMAP_CURVE_RED);
+        float[] greenOut = mMetadata.get(CaptureResult.TONEMAP_CURVE_GREEN);
+        float[] blueOut = mMetadata.get(CaptureResult.TONEMAP_CURVE_BLUE);
+        assertArrayEquals(red, redOut);
+        assertArrayEquals(green, greenOut);
+        assertArrayEquals(blue, blueOut);
+        TonemapCurve tcOut = mMetadata.get(CaptureResult.TONEMAP_CURVE);
+        assertEquals(tcIn, tcOut);
+        mMetadata.set(CaptureResult.TONEMAP_CURVE_GREEN, null);
+        // If any of channel has null curve, return a null TonemapCurve
+        assertNull(mMetadata.get(CaptureResult.TONEMAP_CURVE));
     }
 
     /**
@@ -1166,6 +1191,48 @@
         }
     }
 
+    private <T> void assertKeyValueEquals(T expected, CameraCharacteristics.Key<T> key) {
+        assertKeyValueEquals(expected, key.getNativeKey());
+    }
+
+    private <T> void assertKeyValueEquals(T expected, Key<T> key) {
+        T actual = mMetadata.get(key);
+
+        assertEquals("Expected value for key " + key + " to match", expected, actual);
+    }
+
+    @SmallTest
+    public void testOverrideMaxRegions() {
+        // All keys are null before doing any writes.
+        assertKeyValueEquals(null, CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
+        assertKeyValueEquals(null, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
+        assertKeyValueEquals(null, CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
+
+        mMetadata.set(CameraCharacteristics.CONTROL_MAX_REGIONS,
+                new int[] { /*AE*/1, /*AWB*/2, /*AF*/3 });
+
+        // All keys are the expected value after doing a write
+        assertKeyValueEquals(1, CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
+        assertKeyValueEquals(2, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
+        assertKeyValueEquals(3, CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
+    }
+
+    @SmallTest
+    public void testOverrideMaxNumOutputStreams() {
+        // All keys are null before doing any writes.
+        assertKeyValueEquals(null, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW);
+        assertKeyValueEquals(null, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC);
+        assertKeyValueEquals(null, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING);
+
+        mMetadata.set(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS,
+                new int[] { /*AE*/1, /*AWB*/2, /*AF*/3 });
+
+        // All keys are the expected value after doing a write
+        assertKeyValueEquals(1, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW);
+        assertKeyValueEquals(2, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC);
+        assertKeyValueEquals(3, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING);
+    }
+
     @SmallTest
     public void testCaptureResult() {
         mMetadata.set(CaptureRequest.CONTROL_AE_MODE,
diff --git a/packages/SystemUI/res/layout/volume_panel.xml b/packages/SystemUI/res/layout/volume_panel.xml
index bc7288d..046862f 100644
--- a/packages/SystemUI/res/layout/volume_panel.xml
+++ b/packages/SystemUI/res/layout/volume_panel.xml
@@ -24,6 +24,7 @@
         android:id="@+id/slider_panel"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:minHeight="64dip"
         android:layout_toLeftOf="@+id/expand_button_divider" />
 
     <ImageView
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index ae04bf5..0936cc2 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -21,7 +21,9 @@
     android:layout_height="wrap_content"
     android:background="@color/system_primary_color"
     android:orientation="vertical"
-    android:padding="@dimen/qs_panel_padding" >
+    android:paddingTop="@dimen/qs_panel_padding"
+    android:paddingLeft="@dimen/qs_panel_padding"
+    android:paddingRight="@dimen/qs_panel_padding" >
 
     <TextView
         android:id="@android:id/title"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 41c0e78..4c7f3df 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -202,6 +202,12 @@
             checkPermission();
             mKeyguardViewMediator.onBootCompleted();
         }
+
+        @Override
+        public void startKeyguardExitAnimation(long fadeoutDuration) {
+            checkPermission();
+            mKeyguardViewMediator.startKeyguardExitAnimation(fadeoutDuration);
+        }
     };
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b2872fa..7110d8d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -46,7 +46,8 @@
 import android.util.Log;
 import android.util.Slog;
 import android.view.ViewGroup;
-import android.view.WindowManager;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy;
 
 import com.android.internal.policy.IKeyguardExitCallback;
@@ -137,6 +138,7 @@
     private static final int SET_OCCLUDED = 12;
     private static final int KEYGUARD_TIMEOUT = 13;
     private static final int DISMISS = 17;
+    private static final int START_KEYGUARD_EXIT_ANIM = 18;
 
     /**
      * The default amount of time we stay awake (used for all key input)
@@ -180,6 +182,9 @@
     /** High level access to the power manager for WakeLocks */
     private PowerManager mPM;
 
+    /** High level access to the window manager for dismissing keyguard animation */
+    private IWindowManager mWM;
+
     /** UserManager for querying number of users */
     private UserManager mUserManager;
 
@@ -440,6 +445,7 @@
 
     private void setup() {
         mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mWM = WindowManagerGlobal.getWindowManagerService();
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
         mShowKeyguardWakeLock.setReferenceCounted(false);
@@ -1076,6 +1082,9 @@
                 case DISMISS:
                     handleDismiss();
                     break;
+                case START_KEYGUARD_EXIT_ANIM:
+                    handleStartKeyguardExitAnimation((Long) msg.obj);
+                    break;
             }
         }
     };
@@ -1207,6 +1216,19 @@
     private void handleHide() {
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleHide");
+            try {
+
+                // Don't actually hide the Keyguard at the moment, wait for window manager until
+                // it tells us it's safe to do so with startKeyguardExitAnimation.
+                mWM.keyguardGoingAway();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error while calling WindowManager", e);
+            }
+        }
+    }
+
+    private void handleStartKeyguardExitAnimation(long fadeoutDuration) {
+        synchronized (KeyguardViewMediator.this) {
 
             // only play "unlock" noises if not on a call (since the incall UI
             // disables the keyguard)
@@ -1324,6 +1346,11 @@
         return mStatusBarKeyguardViewManager;
     }
 
+    public void startKeyguardExitAnimation(long fadeoutDuration) {
+        Message msg = mHandler.obtainMessage(START_KEYGUARD_EXIT_ANIM, fadeoutDuration);
+        mHandler.sendMessage(msg);
+    }
+
     public ViewMediatorCallback getViewMediatorCallback() {
         return mViewMediatorCallback;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index bdac7a0..626fc0d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -191,15 +191,23 @@
             final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight;
             record.tileView.measure(exactly(cw), exactly(ch));
         }
-        final int actualHeight = rows == 0 ? 0 : getRowTop(rows);
-        mDetail.measure(exactly(width), exactly(actualHeight));
-        setMeasuredDimension(width, actualHeight);
+        int h = rows == 0 ? 0 : getRowTop(rows);
+        mDetail.measure(exactly(width), unspecified());
+        if (mDetail.getVisibility() == VISIBLE && mDetail.getChildCount() > 0) {
+            final int dmh = mDetail.getMeasuredHeight();
+            if (dmh > 0) h = dmh;
+        }
+        setMeasuredDimension(width, h);
     }
 
     private static int exactly(int size) {
         return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
     }
 
+    private static int unspecified() {
+        return MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+    }
+
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         final int w = getWidth();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
index 130f9ce..20bbf8b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
@@ -85,7 +85,7 @@
                 // noop
             }
         });
-        vp.postVolumeChanged(AudioManager.STREAM_NOTIFICATION, AudioManager.FLAG_SHOW_UI);
+        vp.postVolumeChanged(AudioManager.STREAM_RING, AudioManager.FLAG_SHOW_UI);
         return v;
     }
 
@@ -108,11 +108,7 @@
 
     @Override
     protected void handleClick() {
-        if (mState.zen) {
-            mZenController.setZen(false);
-        } else {
-            showDetail(true);
-        }
+        showDetail(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 6246e05..fbe76f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -93,7 +93,7 @@
     public static final String TAG = "StatusBar";
     public static final boolean DEBUG = false;
     public static final boolean MULTIUSER_DEBUG = false;
-    private static final boolean USE_NOTIFICATION_LISTENER = false;
+    private static final boolean USE_NOTIFICATION_LISTENER = true;
 
     protected static final int MSG_SHOW_RECENT_APPS = 1019;
     protected static final int MSG_HIDE_RECENT_APPS = 1020;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
index 993bb92..24da5c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
@@ -31,7 +31,6 @@
 public class InterceptedNotifications {
     private static final String TAG = "InterceptedNotifications";
     private static final String EXTRA_INTERCEPT = "android.intercept";
-    private static final String SYNTHETIC_KEY = "InterceptedNotifications.SYNTHETIC_KEY";
 
     private final Context mContext;
     private final PhoneStatusBar mBar;
@@ -71,7 +70,7 @@
     }
 
     public boolean isSyntheticEntry(Entry ent) {
-        return ent.key.equals(SYNTHETIC_KEY);
+        return ent.key.equals(mSynKey);
     }
 
     public void update(StatusBarNotification notification) {
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 838e5e3..802e5e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -164,7 +164,9 @@
         // Calculate quick setting heights.
         mQsMinExpansionHeight = mHeader.getCollapsedHeight() + mQsPeekHeight;
         mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
-        if (!mQsExpanded) {
+        if (mQsExpanded) {
+            setQsStackScrollerPadding(mQsMaxExpansionHeight);
+        } else {
             setQsExpansion(mQsMinExpansionHeight);
             positionClockAndNotifications();
             mNotificationStackScroller.setStackHeight(getExpandedHeight());
@@ -260,6 +262,7 @@
         mQsExpansionEnabled = qsExpansionEnabled;
     }
 
+    @Override
     public void resetViews() {
         mBlockTouches = false;
         mPageSwiper.reset();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 1015d5b..b94f6f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -191,6 +191,7 @@
                 pv.setExpandedFraction(0); // just in case
                 pv.setVisibility(View.GONE);
                 pv.cancelPeek();
+                pv.resetViews();
             }
         }
         if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index f6db8a8..c5a9b85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -540,4 +540,6 @@
                 mHeightAnimator, ((mHeightAnimator !=null && mHeightAnimator.isStarted())?" (started)":"")
         ));
     }
+
+    public abstract void resetViews();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 06f4c2e..67f3a3d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -1035,8 +1035,8 @@
                 if (isShowing()) {
                     if (mDialog != null) {
                         mDialog.dismiss();
+                        mActiveStreamType = -1;
                     }
-                    mActiveStreamType = -1;
                 }
                 synchronized (sConfirmSafeVolumeLock) {
                     if (sConfirmSafeVolumeDialog != null) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 2fea785..6b0095a 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -3179,7 +3179,9 @@
                         com.android.internal.R.attr.dialogTitleDecorLayout, res, true);
                 layoutResource = res.resourceId;
             } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
-                layoutResource = com.android.internal.R.layout.screen_action_bar;
+                layoutResource = a.getResourceId(
+                        com.android.internal.R.styleable.Window_windowActionBarFullscreenDecorLayout,
+                        com.android.internal.R.layout.screen_action_bar);
             } else {
                 layoutResource = com.android.internal.R.layout.screen_title;
             }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index e178773..8e68dfc 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -66,6 +66,7 @@
 import android.provider.Settings;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
+import android.telephony.TelephonyManager;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -354,6 +355,10 @@
     // the same as mCur*, but may be larger if the screen decor has supplied
     // content insets.
     int mContentLeft, mContentTop, mContentRight, mContentBottom;
+    // During layout, the frame in which voice content should be displayed
+    // to the user, accounting for all screen decoration except for any
+    // space they deem as available for other content.
+    int mVoiceContentLeft, mVoiceContentTop, mVoiceContentRight, mVoiceContentBottom;
     // During layout, the current screen borders along which input method
     // windows are placed.
     int mDockLeft, mDockTop, mDockRight, mDockBottom;
@@ -478,7 +483,6 @@
     private static final int MSG_DISABLE_POINTER_LOCATION = 2;
     private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
     private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
-    private static final int MSG_DISPATCH_SHOW_RECENTS = 5;
 
     private class PolicyHandler extends Handler {
         @Override
@@ -496,9 +500,6 @@
                 case MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK:
                     dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj);
                     break;
-                case MSG_DISPATCH_SHOW_RECENTS:
-                    showRecentApps(false);
-                    break;
             }
         }
     }
@@ -1265,6 +1266,7 @@
             case TYPE_INPUT_METHOD:
             case TYPE_WALLPAPER:
             case TYPE_PRIVATE_PRESENTATION:
+            case TYPE_VOICE_INTERACTION:
                 // The window manager will check these.
                 break;
             case TYPE_PHONE:
@@ -1431,74 +1433,77 @@
             return 3;
         case TYPE_SEARCH_BAR:
             return 4;
+        case TYPE_VOICE_INTERACTION:
+            // voice interaction layer is almost immediately above apps.
+            return 5;
         case TYPE_RECENTS_OVERLAY:
         case TYPE_SYSTEM_DIALOG:
-            return 5;
+            return 6;
         case TYPE_TOAST:
             // toasts and the plugged-in battery thing
-            return 6;
+            return 7;
         case TYPE_PRIORITY_PHONE:
             // SIM errors and unlock.  Not sure if this really should be in a high layer.
-            return 7;
+            return 8;
         case TYPE_DREAM:
             // used for Dreams (screensavers with TYPE_DREAM windows)
-            return 8;
+            return 9;
         case TYPE_SYSTEM_ALERT:
             // like the ANR / app crashed dialogs
-            return 9;
+            return 10;
         case TYPE_INPUT_METHOD:
             // on-screen keyboards and other such input method user interfaces go here.
-            return 10;
+            return 11;
         case TYPE_INPUT_METHOD_DIALOG:
             // on-screen keyboards and other such input method user interfaces go here.
-            return 11;
+            return 12;
         case TYPE_KEYGUARD_SCRIM:
             // the safety window that shows behind keyguard while keyguard is starting
-            return 12;
-        case TYPE_STATUS_BAR_SUB_PANEL:
             return 13;
-        case TYPE_STATUS_BAR:
+        case TYPE_STATUS_BAR_SUB_PANEL:
             return 14;
-        case TYPE_STATUS_BAR_PANEL:
+        case TYPE_STATUS_BAR:
             return 15;
-        case TYPE_KEYGUARD_DIALOG:
+        case TYPE_STATUS_BAR_PANEL:
             return 16;
+        case TYPE_KEYGUARD_DIALOG:
+            return 17;
         case TYPE_VOLUME_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 17;
+            return 18;
         case TYPE_SYSTEM_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 18;
+            return 19;
         case TYPE_NAVIGATION_BAR:
             // the navigation bar, if available, shows atop most things
-            return 19;
+            return 20;
         case TYPE_NAVIGATION_BAR_PANEL:
             // some panels (e.g. search) need to show on top of the navigation bar
-            return 20;
+            return 21;
         case TYPE_SYSTEM_ERROR:
             // system-level error dialogs
-            return 21;
+            return 22;
         case TYPE_MAGNIFICATION_OVERLAY:
             // used to highlight the magnified portion of a display
-            return 22;
+            return 23;
         case TYPE_DISPLAY_OVERLAY:
             // used to simulate secondary display devices
-            return 23;
+            return 24;
         case TYPE_DRAG:
             // the drag layer: input for drag-and-drop is associated with this window,
             // which sits above all other focusable windows
-            return 24;
-        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 25;
-        case TYPE_BOOT_PROGRESS:
+        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 26;
+        case TYPE_BOOT_PROGRESS:
+            return 27;
         case TYPE_POINTER:
             // the (mouse) pointer layer
-            return 27;
-        case TYPE_HIDDEN_NAV_CONSUMER:
             return 28;
+        case TYPE_HIDDEN_NAV_CONSUMER:
+            return 29;
         }
         Log.e(TAG, "Unknown window type: " + type);
         return 2;
@@ -1567,11 +1572,16 @@
     }
 
     @Override
-    public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
+    public boolean doesForceHide(WindowManager.LayoutParams attrs) {
         return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
     }
 
     @Override
+    public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
+        return attrs.type == TYPE_STATUS_BAR;
+    }
+
+    @Override
     public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
         switch (attrs.type) {
             case TYPE_STATUS_BAR:
@@ -1925,9 +1935,8 @@
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
     }
 
-    static ITelephony getTelephonyService() {
-        return ITelephony.Stub.asInterface(
-                ServiceManager.checkService(Context.TELEPHONY_SERVICE));
+    TelephonyManager getTelephonyService() {
+        return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
     }
 
     static IAudioService getAudioService() {
@@ -2010,14 +2019,10 @@
                 // If an incoming call is ringing, HOME is totally disabled.
                 // (The user is already on the InCallScreen at this point,
                 // and his ONLY options are to answer or reject the call.)
-                try {
-                    ITelephony telephonyService = getTelephonyService();
-                    if (telephonyService != null && telephonyService.isRinging()) {
-                        Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
-                        return -1;
-                    }
-                } catch (RemoteException ex) {
-                    Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
+                TelephonyManager telephonyManager = getTelephonyService();
+                if (telephonyManager != null && telephonyManager.isRinging()) {
+                    Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
+                    return -1;
                 }
 
                 // Delay handling home if a double-tap is possible.
@@ -2463,12 +2468,6 @@
         }
     }
 
-    @Override
-    public void showRecentApps() {
-        mHandler.removeMessages(MSG_DISPATCH_SHOW_RECENTS);
-        mHandler.sendEmptyMessage(MSG_DISPATCH_SHOW_RECENTS);
-    }
-
     private void showRecentApps(boolean triggeredFromAltTab) {
         mPreloadedRecentApps = false; // preloading no longer needs to be canceled
         try {
@@ -2715,13 +2714,13 @@
         mRestrictedScreenTop = mUnrestrictedScreenTop;
         mRestrictedScreenWidth = mSystemGestures.screenWidth = mUnrestrictedScreenWidth;
         mRestrictedScreenHeight = mSystemGestures.screenHeight = mUnrestrictedScreenHeight;
-        mDockLeft = mContentLeft = mStableLeft = mStableFullscreenLeft
+        mDockLeft = mContentLeft = mVoiceContentLeft = mStableLeft = mStableFullscreenLeft
                 = mCurLeft = mUnrestrictedScreenLeft;
-        mDockTop = mContentTop = mStableTop = mStableFullscreenTop
+        mDockTop = mContentTop = mVoiceContentTop = mStableTop = mStableFullscreenTop
                 = mCurTop = mUnrestrictedScreenTop;
-        mDockRight = mContentRight = mStableRight = mStableFullscreenRight
+        mDockRight = mContentRight = mVoiceContentRight = mStableRight = mStableFullscreenRight
                 = mCurRight = displayWidth - overscanRight;
-        mDockBottom = mContentBottom = mStableBottom = mStableFullscreenBottom
+        mDockBottom = mContentBottom = mVoiceContentBottom = mStableBottom = mStableFullscreenBottom
                 = mCurBottom = displayHeight - overscanBottom;
         mDockLayer = 0x10000000;
         mStatusBarLayer = -1;
@@ -2832,10 +2831,10 @@
                 }
                 // Make sure the content and current rectangles are updated to
                 // account for the restrictions from the navigation bar.
-                mContentTop = mCurTop = mDockTop;
-                mContentBottom = mCurBottom = mDockBottom;
-                mContentLeft = mCurLeft = mDockLeft;
-                mContentRight = mCurRight = mDockRight;
+                mContentTop = mVoiceContentTop = mCurTop = mDockTop;
+                mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
+                mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
+                mContentRight = mVoiceContentRight = mCurRight = mDockRight;
                 mStatusBarLayer = mNavigationBar.getSurfaceLayer();
                 // And compute the final frame.
                 mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
@@ -2882,10 +2881,10 @@
                     // status bar is visible.
                     mDockTop = mUnrestrictedScreenTop + mStatusBarHeight;
 
-                    mContentTop = mCurTop = mDockTop;
-                    mContentBottom = mCurBottom = mDockBottom;
-                    mContentLeft = mCurLeft = mDockLeft;
-                    mContentRight = mCurRight = mDockRight;
+                    mContentTop = mVoiceContentTop = mCurTop = mDockTop;
+                    mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
+                    mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
+                    mContentRight = mVoiceContentRight = mCurRight = mDockRight;
 
                     if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " +
                         String.format(
@@ -2956,7 +2955,12 @@
                 // Ungh.  So to deal with that, make sure the content frame
                 // we end up using is not covering the IM dock.
                 cf.set(attached.getContentFrameLw());
-                if (attached.getSurfaceLayer() < mDockLayer) {
+                if (attached.isVoiceInteraction()) {
+                    if (cf.left < mVoiceContentLeft) cf.left = mVoiceContentLeft;
+                    if (cf.top < mVoiceContentTop) cf.top = mVoiceContentTop;
+                    if (cf.right > mVoiceContentRight) cf.right = mVoiceContentRight;
+                    if (cf.bottom > mVoiceContentBottom) cf.bottom = mVoiceContentBottom;
+                } else if (attached.getSurfaceLayer() < mDockLayer) {
                     if (cf.left < mContentLeft) cf.left = mContentLeft;
                     if (cf.top < mContentTop) cf.top = mContentTop;
                     if (cf.right > mContentRight) cf.right = mContentRight;
@@ -3164,16 +3168,23 @@
                     }
 
                     if ((fl & FLAG_FULLSCREEN) == 0) {
-                        if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
-                            cf.left = mDockLeft;
-                            cf.top = mDockTop;
-                            cf.right = mDockRight;
-                            cf.bottom = mDockBottom;
+                        if (win.isVoiceInteraction()) {
+                            cf.left = mVoiceContentLeft;
+                            cf.top = mVoiceContentTop;
+                            cf.right = mVoiceContentRight;
+                            cf.bottom = mVoiceContentBottom;
                         } else {
-                            cf.left = mContentLeft;
-                            cf.top = mContentTop;
-                            cf.right = mContentRight;
-                            cf.bottom = mContentBottom;
+                            if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+                                cf.left = mDockLeft;
+                                cf.top = mDockTop;
+                                cf.right = mDockRight;
+                                cf.bottom = mDockBottom;
+                            } else {
+                                cf.left = mContentLeft;
+                                cf.top = mContentTop;
+                                cf.right = mContentRight;
+                                cf.bottom = mContentBottom;
+                            }
                         }
                     } else {
                         // Full screen windows are always given a layout that is as if the
@@ -3385,6 +3396,10 @@
             setLastInputMethodWindowLw(null, null);
             offsetInputMethodWindowLw(win);
         }
+        if (attrs.type == TYPE_VOICE_INTERACTION && win.isVisibleOrBehindKeyguardLw()
+                && !win.getGivenInsetsPendingLw()) {
+            offsetVoiceInputWindowLw(win);
+        }
     }
 
     private void offsetInputMethodWindowLw(WindowState win) {
@@ -3393,6 +3408,9 @@
         if (mContentBottom > top) {
             mContentBottom = top;
         }
+        if (mVoiceContentBottom > top) {
+            mVoiceContentBottom = top;
+        }
         top = win.getVisibleFrameLw().top;
         top += win.getGivenVisibleInsetsLw().top;
         if (mCurBottom > top) {
@@ -3403,6 +3421,40 @@
                 + mContentBottom + " mCurBottom=" + mCurBottom);
     }
 
+    private void offsetVoiceInputWindowLw(WindowState win) {
+        final int gravity = win.getAttrs().gravity;
+        switch (gravity&((Gravity.AXIS_PULL_BEFORE|Gravity.AXIS_PULL_AFTER)
+                << Gravity.AXIS_X_SHIFT)) {
+            case Gravity.AXIS_PULL_BEFORE<<Gravity.AXIS_X_SHIFT: {
+                int right = win.getContentFrameLw().right - win.getGivenContentInsetsLw().right;
+                if (mVoiceContentLeft < right) {
+                    mVoiceContentLeft = right;
+                }
+            } break;
+            case Gravity.AXIS_PULL_AFTER<<Gravity.AXIS_X_SHIFT: {
+                int left = win.getContentFrameLw().left - win.getGivenContentInsetsLw().left;
+                if (mVoiceContentRight < left) {
+                    mVoiceContentRight = left;
+                }
+            } break;
+        }
+        switch (gravity&((Gravity.AXIS_PULL_BEFORE|Gravity.AXIS_PULL_AFTER)
+                << Gravity.AXIS_Y_SHIFT)) {
+            case Gravity.AXIS_PULL_BEFORE<<Gravity.AXIS_Y_SHIFT: {
+                int bottom = win.getContentFrameLw().bottom - win.getGivenContentInsetsLw().bottom;
+                if (mVoiceContentTop < bottom) {
+                    mVoiceContentTop = bottom;
+                }
+            } break;
+            case Gravity.AXIS_PULL_AFTER<<Gravity.AXIS_Y_SHIFT: {
+                int top = win.getContentFrameLw().top - win.getGivenContentInsetsLw().top;
+                if (mVoiceContentBottom < top) {
+                    mVoiceContentBottom = top;
+                }
+            } break;
+        }
+    }
+
     /** {@inheritDoc} */
     @Override
     public void finishLayoutLw() {
@@ -3967,37 +4019,33 @@
                     }
                 }
                 if (down) {
-                    ITelephony telephonyService = getTelephonyService();
-                    if (telephonyService != null) {
-                        try {
-                            if (telephonyService.isRinging()) {
-                                // If an incoming call is ringing, either VOLUME key means
-                                // "silence ringer".  We handle these keys here, rather than
-                                // in the InCallScreen, to make sure we'll respond to them
-                                // even if the InCallScreen hasn't come to the foreground yet.
-                                // Look for the DOWN event here, to agree with the "fallback"
-                                // behavior in the InCallScreen.
-                                Log.i(TAG, "interceptKeyBeforeQueueing:"
-                                      + " VOLUME key-down while ringing: Silence ringer!");
+                    TelephonyManager telephonyManager = getTelephonyService();
+                    if (telephonyManager != null) {
+                        if (telephonyManager.isRinging()) {
+                            // If an incoming call is ringing, either VOLUME key means
+                            // "silence ringer".  We handle these keys here, rather than
+                            // in the InCallScreen, to make sure we'll respond to them
+                            // even if the InCallScreen hasn't come to the foreground yet.
+                            // Look for the DOWN event here, to agree with the "fallback"
+                            // behavior in the InCallScreen.
+                            Log.i(TAG, "interceptKeyBeforeQueueing:"
+                                  + " VOLUME key-down while ringing: Silence ringer!");
 
-                                // Silence the ringer.  (It's safe to call this
-                                // even if the ringer has already been silenced.)
-                                telephonyService.silenceRinger();
+                            // Silence the ringer.  (It's safe to call this
+                            // even if the ringer has already been silenced.)
+                            telephonyManager.silenceRinger();
 
-                                // And *don't* pass this key thru to the current activity
-                                // (which is probably the InCallScreen.)
-                                result &= ~ACTION_PASS_TO_USER;
-                                break;
-                            }
-                            if (telephonyService.isOffhook()
-                                    && (result & ACTION_PASS_TO_USER) == 0) {
-                                // If we are in call but we decided not to pass the key to
-                                // the application, handle the volume change here.
-                                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
-                                break;
-                            }
-                        } catch (RemoteException ex) {
-                            Log.w(TAG, "ITelephony threw RemoteException", ex);
+                            // And *don't* pass this key thru to the current activity
+                            // (which is probably the InCallScreen.)
+                            result &= ~ACTION_PASS_TO_USER;
+                            break;
+                        }
+                        if (telephonyManager.isOffhook()
+                                && (result & ACTION_PASS_TO_USER) == 0) {
+                            // If we are in call but we decided not to pass the key to
+                            // the application, handle the volume change here.
+                            handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
+                            break;
                         }
                     }
 
@@ -4014,14 +4062,10 @@
             case KeyEvent.KEYCODE_ENDCALL: {
                 result &= ~ACTION_PASS_TO_USER;
                 if (down) {
-                    ITelephony telephonyService = getTelephonyService();
+                    TelephonyManager telephonyManager = getTelephonyService();
                     boolean hungUp = false;
-                    if (telephonyService != null) {
-                        try {
-                            hungUp = telephonyService.endCall();
-                        } catch (RemoteException ex) {
-                            Log.w(TAG, "ITelephony threw RemoteException", ex);
-                        }
+                    if (telephonyManager != null) {
+                        hungUp = telephonyManager.endCall();
                     }
                     interceptPowerKeyDown(!interactive || hungUp);
                 } else {
@@ -4057,23 +4101,19 @@
                         interceptScreenshotChord();
                     }
 
-                    ITelephony telephonyService = getTelephonyService();
+                    TelephonyManager telephonyManager = getTelephonyService();
                     boolean hungUp = false;
-                    if (telephonyService != null) {
-                        try {
-                            if (telephonyService.isRinging()) {
-                                // Pressing Power while there's a ringing incoming
-                                // call should silence the ringer.
-                                telephonyService.silenceRinger();
-                            } else if ((mIncallPowerBehavior
-                                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
-                                    && telephonyService.isOffhook() && interactive) {
-                                // Otherwise, if "Power button ends call" is enabled,
-                                // the Power button will hang up any current active call.
-                                hungUp = telephonyService.endCall();
-                            }
-                        } catch (RemoteException ex) {
-                            Log.w(TAG, "ITelephony threw RemoteException", ex);
+                    if (telephonyManager != null) {
+                        if (telephonyManager.isRinging()) {
+                            // Pressing Power while there's a ringing incoming
+                            // call should silence the ringer.
+                            telephonyManager.silenceRinger();
+                        } else if ((mIncallPowerBehavior
+                                & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
+                                && telephonyManager.isOffhook() && interactive) {
+                            // Otherwise, if "Power button ends call" is enabled,
+                            // the Power button will hang up any current active call.
+                            hungUp = telephonyManager.endCall();
                         }
                     }
                     interceptPowerKeyDown(!interactive || hungUp
@@ -4106,16 +4146,12 @@
             case KeyEvent.KEYCODE_MEDIA_PAUSE:
             case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
                 if (down) {
-                    ITelephony telephonyService = getTelephonyService();
-                    if (telephonyService != null) {
-                        try {
-                            if (!telephonyService.isIdle()) {
-                                // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
-                                // to avoid music playback.
-                                break;
-                            }
-                        } catch (RemoteException ex) {
-                            Log.w(TAG, "ITelephony threw RemoteException", ex);
+                    TelephonyManager telephonyManager = getTelephonyService();
+                    if (telephonyManager != null) {
+                        if (!telephonyManager.isIdle()) {
+                            // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
+                            // to avoid music playback.
+                            break;
                         }
                     }
                 }
@@ -4145,20 +4181,16 @@
 
             case KeyEvent.KEYCODE_CALL: {
                 if (down) {
-                    ITelephony telephonyService = getTelephonyService();
-                    if (telephonyService != null) {
-                        try {
-                            if (telephonyService.isRinging()) {
-                                Log.i(TAG, "interceptKeyBeforeQueueing:"
-                                      + " CALL key-down while ringing: Answer the call!");
-                                telephonyService.answerRingingCall();
+                    TelephonyManager telephonyManager = getTelephonyService();
+                    if (telephonyManager != null) {
+                        if (telephonyManager.isRinging()) {
+                            Log.i(TAG, "interceptKeyBeforeQueueing:"
+                                  + " CALL key-down while ringing: Answer the call!");
+                            telephonyManager.answerRingingCall();
 
-                                // And *don't* pass this key thru to the current activity
-                                // (which is presumably the InCallScreen.)
-                                result &= ~ACTION_PASS_TO_USER;
-                            }
-                        } catch (RemoteException ex) {
-                            Log.w(TAG, "ITelephony threw RemoteException", ex);
+                            // And *don't* pass this key thru to the current activity
+                            // (which is presumably the InCallScreen.)
+                            result &= ~ACTION_PASS_TO_USER;
                         }
                     }
                 }
@@ -4533,6 +4565,18 @@
         }
     }
 
+    @Override
+    public void startKeyguardExitAnimation(final long fadeoutDuration) {
+        if (mKeyguardDelegate != null) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mKeyguardDelegate.startKeyguardExitAnimation(fadeoutDuration);
+                }
+            });
+        }
+    }
+
     void sendCloseSystemWindows() {
         sendCloseSystemWindows(mContext, null);
     }
@@ -5506,6 +5550,10 @@
                 pw.print(","); pw.print(mContentTop);
                 pw.print(")-("); pw.print(mContentRight);
                 pw.print(","); pw.print(mContentBottom); pw.println(")");
+        pw.print(prefix); pw.print("mVoiceContent=("); pw.print(mVoiceContentLeft);
+                pw.print(","); pw.print(mVoiceContentTop);
+                pw.print(")-("); pw.print(mVoiceContentRight);
+                pw.print(","); pw.print(mVoiceContentBottom); pw.println(")");
         pw.print(prefix); pw.print("mDock=("); pw.print(mDockLeft);
                 pw.print(","); pw.print(mDockTop);
                 pw.print(")-("); pw.print(mDockRight);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
index 966924b..faf7020 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
@@ -274,6 +274,12 @@
         mKeyguardState.currentUser = newUserId;
     }
 
+    public void startKeyguardExitAnimation(long fadeoutDuration) {
+        if (mKeyguardService != null) {
+            mKeyguardService.startKeyguardExitAnimation(fadeoutDuration);
+        }
+    }
+
     private static final View createScrim(Context context) {
         View view = new View(context);
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
index 7cb48fa..f236ce7 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
@@ -190,6 +190,14 @@
         }
     }
 
+    public void startKeyguardExitAnimation(long fadeoutDuration) {
+        try {
+            mService.startKeyguardExitAnimation(fadeoutDuration);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
     public void showAssistant() {
         // Not used by PhoneWindowManager
     }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1e21e1c..5527528 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5606,16 +5606,23 @@
         boolean isNewDefault = false;
         if (DBG) log("handleConnectionValidated for "+newNetwork.name());
         // check if any NetworkRequest wants this NetworkAgent
-        // first check if it satisfies the NetworkCapabilities
         ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
         if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities);
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+            NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
+            if (newNetwork == currentNetwork) {
+                if (VDBG) log("Network " + newNetwork.name() + " was already satisfying" +
+                              " request " + nri.request.requestId + ". No change.");
+                keep = true;
+                continue;
+            }
+
+            // check if it satisfies the NetworkCapabilities
             if (VDBG) log("  checking if request is satisfied: " + nri.request);
             if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities(
                     newNetwork.networkCapabilities)) {
                 // next check if it's better than any current network we're using for
                 // this request
-                NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
                 if (VDBG) {
                     log("currentScore = " +
                             (currentNetwork != null ? currentNetwork.currentScore : 0) +
@@ -5744,12 +5751,19 @@
         }
 
         if (state == NetworkInfo.State.CONNECTED) {
-            // TODO - check if we want it (optimization)
             try {
+                // This is likely caused by the fact that this network already
+                // exists. An example is when a network goes from CONNECTED to
+                // CONNECTING and back (like wifi on DHCP renew).
+                // TODO: keep track of which networks we've created, or ask netd
+                // to tell us whether we've already created this network or not.
                 mNetd.createNetwork(networkAgent.network.netId);
             } catch (Exception e) {
-                loge("Error creating Network " + networkAgent.network.netId);
+                loge("Error creating network " + networkAgent.network.netId + ": "
+                        + e.getMessage());
+                return;
             }
+
             updateLinkProperties(networkAgent, null);
             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
             networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index a0440cb..1804d03 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -30,10 +30,6 @@
 import static com.android.server.am.ActivityManagerService.DEBUG_VISBILITY;
 import static com.android.server.am.ActivityManagerService.VALIDATE_TOKENS;
 
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
-
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE;
@@ -1067,6 +1063,40 @@
         }
     }
 
+    /**
+     * Determine if home should be visible below the passed record.
+     * @param record activity we are querying for.
+     * @return true if home is visible below the passed activity, false otherwise.
+     */
+    boolean isActivityOverHome(ActivityRecord record) {
+        // Start at record and go down, look for either home or a visible fullscreen activity.
+        final TaskRecord recordTask = record.task;
+        for (int taskNdx = mTaskHistory.indexOf(recordTask); taskNdx >= 0; --taskNdx) {
+            TaskRecord task = mTaskHistory.get(taskNdx);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            final int startNdx =
+                    task == recordTask ? activities.indexOf(record) : activities.size() - 1;
+            for (int activityNdx = startNdx; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.isHomeActivity()) {
+                    return true;
+                }
+                if (!r.finishing && r.fullscreen) {
+                    // Passed activity is over a fullscreen activity.
+                    return false;
+                }
+            }
+            if (task.mOnTopOfHome) {
+                // Got to the bottom of a task on top of home without finding a visible fullscreen
+                // activity. Home is visible.
+                return true;
+            }
+        }
+        // Got to the bottom of this stack and still don't know. If this is over the home stack
+        // then record is over home. May not work if we ever get more than two layers.
+        return mStackSupervisor.isFrontStack(this);
+    }
+
     private void setVisibile(ActivityRecord r, boolean visible) {
         r.visible = visible;
         mWindowManager.setAppVisibility(r.appToken, visible);
@@ -1096,8 +1126,7 @@
         for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) {
             final ArrayList<TaskRecord> tasks = mStacks.get(i).getAllTasks();
             for (int taskNdx = 0; taskNdx < tasks.size(); taskNdx++) {
-                final TaskRecord task = tasks.get(taskNdx);
-                final ArrayList<ActivityRecord> activities = task.mActivities;
+                final ArrayList<ActivityRecord> activities = tasks.get(taskNdx).mActivities;
                 for (int activityNdx = 0; activityNdx < activities.size(); activityNdx++) {
                     final ActivityRecord r = activities.get(activityNdx);
 
@@ -1108,7 +1137,7 @@
                     // - Full Screen Activity OR
                     // - On top of Home and our stack is NOT home
                     if (!r.finishing && r.visible && (r.fullscreen ||
-                            (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()))) {
+                            (!isHomeStack() && r.frontOfTask && tasks.get(taskNdx).mOnTopOfHome))) {
                         return false;
                     }
                 }
@@ -1236,7 +1265,7 @@
                         // At this point, nothing else needs to be shown
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
                         behindFullscreen = true;
-                    } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
+                    } else if (!isHomeStack() && r.frontOfTask && task.mOnTopOfHome) {
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
                         behindFullscreen = true;
                     }
@@ -1390,7 +1419,6 @@
         final boolean userLeaving = mStackSupervisor.mUserLeaving;
         mStackSupervisor.mUserLeaving = false;
 
-        final TaskRecord prevTask = prev != null ? prev.task : null;
         if (next == null) {
             // There are no more activities!  Let's just start up the
             // Launcher...
@@ -1398,10 +1426,7 @@
             if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             // Only resume home if on home display
-            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
-                    HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
-            return isOnHomeDisplay() &&
-                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev);
+            return isOnHomeDisplay() && mStackSupervisor.resumeHomeActivity(prev);
         }
 
         next.delayedResume = false;
@@ -1420,24 +1445,22 @@
         }
 
         final TaskRecord nextTask = next.task;
+        final TaskRecord prevTask = prev != null ? prev.task : null;
         if (prevTask != null && prevTask.stack == this &&
-                prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
+                prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
             if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
             if (prevTask == nextTask) {
                 prevTask.setFrontOfTask();
             } else if (prevTask != topTask()) {
-                // This task is going away but it was supposed to return to the home stack.
+                // This task is going away but it was supposed to return to the home task.
                 // Now the task above it has to return to the home task instead.
                 final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
-                mTaskHistory.get(taskNdx).setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+                mTaskHistory.get(taskNdx).mOnTopOfHome = true;
             } else {
                 if (DEBUG_STATES && isOnHomeDisplay()) Slog.d(TAG,
                         "resumeTopActivityLocked: Launching home next");
                 // Only resume home if on home display
-                final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
-                        HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
-                return isOnHomeDisplay() &&
-                        mStackSupervisor.resumeHomeStackTask(returnTaskType, prev);
+                return isOnHomeDisplay() && mStackSupervisor.resumeHomeActivity(prev);
             }
         }
 
@@ -1808,11 +1831,10 @@
             ActivityStack lastStack = mStackSupervisor.getLastStack();
             final boolean fromHome = lastStack.isHomeStack();
             if (!isHomeStack() && (fromHome || topTask() != task)) {
-                task.setTaskToReturnTo(fromHome ?
-                        lastStack.topTask().taskType : APPLICATION_ACTIVITY_TYPE);
+                task.mOnTopOfHome = fromHome;
             }
         } else {
-            task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
+            task.mOnTopOfHome = false;
         }
 
         mTaskHistory.remove(task);
@@ -1860,7 +1882,7 @@
                         mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                                 r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                                 (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
-                                r.userId, r.info.configChanges);
+                                r.userId, r.info.configChanges, task.voiceSession != null);
                         if (VALIDATE_TOKENS) {
                             validateAppTokensLocked();
                         }
@@ -1921,7 +1943,7 @@
             mWindowManager.addAppToken(task.mActivities.indexOf(r),
                     r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                     (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
-                    r.info.configChanges);
+                    r.info.configChanges, task.voiceSession != null);
             boolean doShow = true;
             if (newTask) {
                 // Even though this activity is starting fresh, we still need
@@ -1966,7 +1988,7 @@
             mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                     r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                     (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
-                    r.info.configChanges);
+                    r.info.configChanges, task.voiceSession != null);
             ActivityOptions.abort(options);
             options = null;
         }
@@ -2357,8 +2379,8 @@
             ActivityRecord next = topRunningActivityLocked(null);
             if (next != r) {
                 final TaskRecord task = r.task;
-                if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
-                    mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo());
+                if (r.frontOfTask && task == topTask() && task.mOnTopOfHome) {
+                    mStackSupervisor.moveHomeToTop();
                 }
             }
             ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
@@ -2842,9 +2864,8 @@
         if (task != null && task.removeActivity(r)) {
             if (DEBUG_STACK) Slog.i(TAG,
                     "removeActivityFromHistoryLocked: last activity removed from " + this);
-            if (mStackSupervisor.isFrontStack(this) && task == topTask() &&
-                    task.isOverHomeStack()) {
-                mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo());
+            if (mStackSupervisor.isFrontStack(this) && task == topTask() && task.mOnTopOfHome) {
+                mStackSupervisor.moveHomeToTop();
             }
             removeTask(task);
         }
@@ -3159,13 +3180,12 @@
         }
     }
 
-    void moveHomeStackTaskToTop(int homeStackTaskType) {
+    void moveHomeTaskToTop() {
         final int top = mTaskHistory.size() - 1;
         for (int taskNdx = top; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
-            if (task.taskType == homeStackTaskType) {
-                if (DEBUG_TASKS || DEBUG_STACK)
-                    Slog.d(TAG, "moveHomeStackTaskToTop: moving " + task);
+            if (task.isHomeTask()) {
+                if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG, "moveHomeTaskToTop: moving " + task);
                 mTaskHistory.remove(taskNdx);
                 mTaskHistory.add(top, task);
                 updateTaskMovement(task, true);
@@ -3277,12 +3297,12 @@
         int numTasks = mTaskHistory.size();
         for (int taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
-            if (task.isOverHomeStack()) {
+            if (task.mOnTopOfHome) {
                 break;
             }
             if (taskNdx == 1) {
                 // Set the last task before tr to go to home.
-                task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+                task.mOnTopOfHome = true;
             }
         }
 
@@ -3303,10 +3323,9 @@
         }
 
         final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
-        if (task == tr && tr.isOverHomeStack() || numTasks <= 1 && isOnHomeDisplay()) {
-            final int taskToReturnTo = tr.getTaskToReturnTo();
-            tr.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
-            return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null);
+        if (task == tr && tr.mOnTopOfHome || numTasks <= 1 && isOnHomeDisplay()) {
+            tr.mOnTopOfHome = false;
+            return mStackSupervisor.resumeHomeActivity(null);
         }
 
         mStackSupervisor.resumeTopActivitiesLocked();
@@ -3747,11 +3766,8 @@
 
         final int taskNdx = mTaskHistory.indexOf(task);
         final int topTaskNdx = mTaskHistory.size() - 1;
-        if (task.isOverHomeStack() && taskNdx < topTaskNdx) {
-            final TaskRecord nextTask = mTaskHistory.get(taskNdx + 1);
-            if (!nextTask.isOverHomeStack()) {
-                nextTask.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
-            }
+        if (task.mOnTopOfHome && taskNdx < topTaskNdx) {
+            mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
         }
         mTaskHistory.remove(task);
         updateTaskMovement(task, true);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index ae7fab3..0b1c2b8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -31,9 +31,6 @@
 import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
 import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
 import static com.android.server.am.ActivityManagerService.TAG;
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -322,27 +319,18 @@
         }
     }
 
-    void moveHomeStackTaskToTop(int homeStackTaskType) {
-        if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) {
-            mWindowManager.showRecentApps();
-            return;
-        }
+    void moveHomeToTop() {
         moveHomeStack(true);
-        mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
+        mHomeStack.moveHomeTaskToTop();
     }
 
-    boolean resumeHomeStackTask(int homeStackTaskType, ActivityRecord prev) {
-        if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) {
-            mWindowManager.showRecentApps();
-            return false;
-        }
-        moveHomeStackTaskToTop(homeStackTaskType);
+    boolean resumeHomeActivity(ActivityRecord prev) {
+        moveHomeToTop();
         if (prev != null) {
-            prev.task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
+            prev.task.mOnTopOfHome = false;
         }
-
         ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
-        if (r != null && (r.isHomeActivity() || r.isRecentsActivity())) {
+        if (r != null && r.isHomeActivity()) {
             mService.setFocusedActivityLocked(r);
             return resumeTopActivitiesLocked(mHomeStack, prev, null);
         }
@@ -696,7 +684,7 @@
     }
 
     void startHomeActivity(Intent intent, ActivityInfo aInfo) {
-        moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE);
+        moveHomeToTop();
         startActivityLocked(null, intent, null, aInfo, null, null, null, null, 0, 0, 0, null, 0,
                 null, false, null, null);
     }
@@ -1631,7 +1619,7 @@
                                     (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                                     == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                                 // Caller wants to appear on home activity.
-                                intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+                                intentActivity.task.mOnTopOfHome = true;
                             }
                             options = null;
                         }
@@ -1816,11 +1804,6 @@
                         newTaskInfo != null ? newTaskInfo : r.info,
                         newTaskIntent != null ? newTaskIntent : intent,
                         voiceSession, voiceInteractor, true), null, true);
-                if (sourceRecord == null) {
-                    // Launched from a service or notification or task that is finishing.
-                    r.task.setTaskToReturnTo(isFrontStack(mHomeStack) ?
-                            mHomeStack.topTask().taskType : RECENTS_ACTIVITY_TYPE);
-                }
                 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
                         r.task);
             } else {
@@ -1832,7 +1815,7 @@
                         == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
                     // Caller wants to appear on home activity, so before starting
                     // their own activity we will bring home to the front.
-                    r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+                    r.task.mOnTopOfHome = r.task.stack.isOnHomeDisplay();
                 }
             }
         } else if (sourceRecord != null) {
@@ -2183,7 +2166,7 @@
         if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
             // Caller wants the home activity moved with it.  To accomplish this,
             // we'll just indicate that this task returns to the home task.
-            task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+            task.mOnTopOfHome = true;
         }
         task.stack.moveTaskToFrontLocked(task, null, options);
         if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack="
@@ -2290,11 +2273,11 @@
                 mWindowManager.addAppToken(0, r.appToken, taskId, stackId,
                         r.info.screenOrientation, r.fullscreen,
                         (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
-                        r.userId, r.info.configChanges);
+                        r.userId, r.info.configChanges, task.voiceSession != null);
             }
             mWindowManager.addTask(taskId, stackId, false);
         }
-        resumeHomeStackTask(HOME_ACTIVITY_TYPE, null);
+        resumeHomeActivity(null);
     }
 
     void moveTaskToStack(int taskId, int stackId, boolean toTop) {
@@ -2556,7 +2539,7 @@
             }
         } else {
             // Stack was moved to another display while user was swapped out.
-            resumeHomeStackTask(HOME_ACTIVITY_TYPE, null);
+            resumeHomeActivity(null);
         }
         return homeInFront;
     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index c07bc1e..ce83ae6 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -17,9 +17,6 @@
 package com.android.server.am;
 
 import static com.android.server.am.ActivityManagerService.TAG;
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
 
 import android.app.Activity;
@@ -57,6 +54,7 @@
     private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
     private static final String ATTR_USERID = "user_id";
     private static final String ATTR_TASKTYPE = "task_type";
+    private static final String ATTR_ONTOPOFHOME = "on_top_of_home";
     private static final String ATTR_LASTDESCRIPTION = "last_description";
     private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
 
@@ -106,11 +104,9 @@
 
     /** True if persistable, has changed, and has not yet been persisted */
     boolean needsPersisting = false;
-
-    /** Indication of what to run next when task exits. Use ActivityRecord types.
-     * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
-     * task stack. */
-    private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
+    /** Launch the home activity when leaving this task. Will be false for tasks that are not on
+     * Display.DEFAULT_DISPLAY. */
+    boolean mOnTopOfHome = false;
 
     final ActivityManagerService mService;
 
@@ -127,8 +123,9 @@
 
     TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent,
             String _affinity, ComponentName _realActivity, ComponentName _origActivity,
-            boolean _rootWasReset, boolean _askedCompatMode, int _taskType, int _userId,
-            String _lastDescription, ArrayList<ActivityRecord> activities, long lastTimeMoved) {
+            boolean _rootWasReset, boolean _askedCompatMode, int _taskType, boolean _onTopOfHome,
+            int _userId, String _lastDescription, ArrayList<ActivityRecord> activities,
+            long lastTimeMoved) {
         mService = service;
         taskId = _taskId;
         intent = _intent;
@@ -141,7 +138,7 @@
         rootWasReset = _rootWasReset;
         askedCompatMode = _askedCompatMode;
         taskType = _taskType;
-        mTaskToReturnTo = HOME_ACTIVITY_TYPE;
+        mOnTopOfHome = _onTopOfHome;
         userId = _userId;
         lastDescription = _lastDescription;
         mActivities = activities;
@@ -209,14 +206,6 @@
         }
     }
 
-    void setTaskToReturnTo(int taskToReturnTo) {
-        mTaskToReturnTo = taskToReturnTo;
-    }
-
-    int getTaskToReturnTo() {
-        return mTaskToReturnTo;
-    }
-
     void disposeThumbnail() {
         super.disposeThumbnail();
         for (int i=mActivities.size()-1; i>=0; i--) {
@@ -488,15 +477,11 @@
     }
 
     boolean isHomeTask() {
-        return taskType == HOME_ACTIVITY_TYPE;
+        return taskType == ActivityRecord.HOME_ACTIVITY_TYPE;
     }
 
     boolean isApplicationTask() {
-        return taskType == APPLICATION_ACTIVITY_TYPE;
-    }
-
-    boolean isOverHomeStack() {
-        return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
+        return taskType == ActivityRecord.APPLICATION_ACTIVITY_TYPE;
     }
 
     public TaskAccessInfo getTaskAccessInfoLocked() {
@@ -638,6 +623,7 @@
         out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
         out.attribute(null, ATTR_USERID, String.valueOf(userId));
         out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
+        out.attribute(null, ATTR_ONTOPOFHOME, String.valueOf(mOnTopOfHome));
         out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
         if (lastDescription != null) {
             out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
@@ -683,6 +669,7 @@
         boolean rootHasReset = false;
         boolean askedCompatMode = false;
         int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+        boolean onTopOfHome = true;
         int userId = 0;
         String lastDescription = null;
         long lastTimeOnTop = 0;
@@ -710,6 +697,8 @@
                 userId = Integer.valueOf(attrValue);
             } else if (ATTR_TASKTYPE.equals(attrName)) {
                 taskType = Integer.valueOf(attrValue);
+            } else if (ATTR_ONTOPOFHOME.equals(attrName)) {
+                onTopOfHome = Boolean.valueOf(attrValue);
             } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
                 lastDescription = attrValue;
             } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
@@ -747,7 +736,8 @@
 
         final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
                 affinityIntent, affinity, realActivity, origActivity, rootHasReset,
-                askedCompatMode, taskType, userId, lastDescription, activities, lastTimeOnTop);
+                askedCompatMode, taskType, onTopOfHome, userId, lastDescription, activities,
+                lastTimeOnTop);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
             final ActivityRecord r = activities.get(activityNdx);
@@ -766,7 +756,7 @@
                     pw.print(" userId="); pw.print(userId);
                     pw.print(" taskType="); pw.print(taskType);
                     pw.print(" numFullscreen="); pw.print(numFullscreen);
-                    pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
+                    pw.print(" mOnTopOfHome="); pw.println(mOnTopOfHome);
         }
         if (affinity != null) {
             pw.print(prefix); pw.print("affinity="); pw.println(affinity);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b06b090..d505e81 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11775,8 +11775,8 @@
                     }
                 }
                 if (removed.size() > 0) {
-                    for (int j=0; j<removed.size(); j++) {
-                        PreferredActivity pa = removed.get(i);
+                    for (int r=0; r<removed.size(); r++) {
+                        PreferredActivity pa = removed.get(r);
                         Slog.w(TAG, "Removing dangling preferred activity: "
                                 + pa.mPref.mComponent);
                         pir.removeFilter(pa);
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
index 6d208ff..80030b4 100644
--- a/services/core/java/com/android/server/task/TaskManagerService.java
+++ b/services/core/java/com/android/server/task/TaskManagerService.java
@@ -16,12 +16,22 @@
 
 package com.android.server.task;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.task.ITaskManager;
+import android.app.task.Task;
 import android.content.Context;
-import android.content.Task;
+import android.content.pm.PackageManager;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.util.Log;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.server.task.controllers.TaskStatus;
@@ -39,13 +49,6 @@
     /** Master list of tasks. */
     private final TaskStore mTasks;
 
-    /** Check the pending queue and start any tasks. */
-    static final int MSG_RUN_PENDING = 0;
-    /** Initiate the stop task flow. */
-    static final int MSG_STOP_TASK = 1;
-    /** */
-    static final int MSG_CHECK_TASKS = 2;
-
     /**
      * Track Services that have currently active or pending tasks. The index is provided by
      * {@link TaskStatus#getServiceToken()}
@@ -54,6 +57,14 @@
             new SparseArray<TaskServiceContext>();
 
     private final TaskHandler mHandler;
+    private final TaskManagerStub mTaskManagerStub;
+
+    /** Check the pending queue and start any tasks. */
+    static final int MSG_RUN_PENDING = 0;
+    /** Initiate the stop task flow. */
+    static final int MSG_STOP_TASK = 1;
+    /** */
+    static final int MSG_CHECK_TASKS = 2;
 
     private class TaskHandler extends Handler {
 
@@ -94,21 +105,6 @@
     }
 
     /**
-     * Entry point from client to schedule the provided task.
-     * This will add the task to the
-     * @param task Task object containing execution parameters
-     * @param userId The id of the user this task is for.
-     * @param uId The package identifier of the application this task is for.
-     * @param canPersistTask Whether or not the client has the appropriate permissions for persisting
-     *                    of this task.
-     * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
-     */
-    public int schedule(Task task, int userId, int uId, boolean canPersistTask) {
-        TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask);
-        return 0;
-    }
-
-    /**
      * Initializes the system service.
      * <p>
      * Subclasses must define a single argument constructor that accepts the context
@@ -121,11 +117,42 @@
         super(context);
         mTasks = new TaskStore(context);
         mHandler = new TaskHandler(context.getMainLooper());
+        mTaskManagerStub = new TaskManagerStub();
     }
 
     @Override
     public void onStart() {
+        publishBinderService(Context.TASK_SERVICE, mTaskManagerStub);
+    }
 
+    /**
+     * Entry point from client to schedule the provided task.
+     * This will add the task to the
+     * @param task Task object containing execution parameters
+     * @param userId The id of the user this task is for.
+     * @param uId The package identifier of the application this task is for.
+     * @param canPersistTask Whether or not the client has the appropriate permissions for
+     *     persisting of this task.
+     * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
+     */
+    public int schedule(Task task, int userId, int uId, boolean canPersistTask) {
+        TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask);
+        return 0;
+    }
+
+    public List<Task> getPendingTasks(int uid) {
+        ArrayList<Task> outList = new ArrayList<Task>(3);
+        synchronized (mTasks) {
+            final SparseArray<TaskStatus> tasks = mTasks.getTasks();
+            final int N = tasks.size();
+            for (int i = 0; i < N; i++) {
+                TaskStatus ts = tasks.get(i);
+                if (ts.getUid() == uid) {
+                    outList.add(ts.getTask());
+                }
+            }
+        }
+        return outList;
     }
 
     // StateChangedListener implementations.
@@ -162,7 +189,7 @@
     public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule) {
         final TaskServiceContext serviceContext = mActiveServices.get(serviceToken);
         if (serviceContext == null) {
-            Log.e(TAG, "Task completed for invalid service context; " + serviceToken);
+            Slog.e(TAG, "Task completed for invalid service context; " + serviceToken);
             return;
         }
 
@@ -203,4 +230,98 @@
     private void postCheckTasksMessage() {
         mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
     }
+
+    /**
+     * Binder stub trampoline implementation
+     */
+    final class TaskManagerStub extends ITaskManager.Stub {
+        /** Cache determination of whether a given app can persist tasks
+         * key is uid of the calling app; value is undetermined/true/false
+         */
+        private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>();
+
+        // Determine whether the caller is allowed to persist tasks, with a small cache
+        // because the lookup is expensive enough that we'd like to avoid repeating it.
+        // This must be called from within the calling app's binder identity!
+        private boolean canCallerPersistTasks() {
+            final boolean canPersist;
+            final int callingUid = Binder.getCallingUid();
+            synchronized (mPersistCache) {
+                Boolean cached = mPersistCache.get(callingUid);
+                if (cached) {
+                    canPersist = cached.booleanValue();
+                } else {
+                    // Persisting tasks is tantamount to running at boot, so we permit
+                    // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED
+                    // permission
+                    int result = getContext().checkCallingPermission(
+                            android.Manifest.permission.RECEIVE_BOOT_COMPLETED);
+                    canPersist = (result == PackageManager.PERMISSION_GRANTED);
+                    mPersistCache.put(callingUid, canPersist);
+                }
+            }
+            return canPersist;
+        }
+
+        // ITaskManager implementation
+        @Override
+        public int schedule(Task task) throws RemoteException {
+            final boolean canPersist = canCallerPersistTasks();
+            final int uid = Binder.getCallingUid();
+            final int userId = UserHandle.getCallingUserId();
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                return TaskManagerService.this.schedule(task, userId, uid, canPersist);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public List<Task> getAllPendingTasks() throws RemoteException {
+            return null;
+        }
+
+        @Override
+        public void cancelAll() throws RemoteException {
+        }
+
+        @Override
+        public void cancel(int taskId) throws RemoteException {
+        }
+
+        /**
+         * "dumpsys" infrastructure
+         */
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+            long identityToken = Binder.clearCallingIdentity();
+            try {
+                TaskManagerService.this.dumpInternal(pw);
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+        }
+    };
+
+    void dumpInternal(PrintWriter pw) {
+        synchronized (mTasks) {
+            pw.print("Registered tasks:");
+            if (mTasks.size() > 0) {
+                SparseArray<TaskStatus> tasks = mTasks.getTasks();
+                for (int i = 0; i < tasks.size(); i++) {
+                    TaskStatus ts = tasks.get(i);
+                    pw.println();
+                    ts.dump(pw, "  ");
+                }
+            } else {
+                pw.println();
+                pw.println("No tasks scheduled.");
+            }
+        }
+        pw.println();
+    }
 }
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/task/TaskServiceContext.java
index b51cbb3..165445a 100644
--- a/services/core/java/com/android/server/task/TaskServiceContext.java
+++ b/services/core/java/com/android/server/task/TaskServiceContext.java
@@ -45,7 +45,7 @@
  * is reused to start concurrent tasks on the TaskService. Information here is unique
  * to the service.
  * Functionality provided by this class:
- *     - Managages wakelock for the service.
+ *     - Manages wakelock for the service.
  *     - Sends onStartTask() and onStopTask() messages to client app, and handles callbacks.
  *     -
  */
diff --git a/services/core/java/com/android/server/task/TaskStore.java b/services/core/java/com/android/server/task/TaskStore.java
index 3bfc8a5..81187c8 100644
--- a/services/core/java/com/android/server/task/TaskStore.java
+++ b/services/core/java/com/android/server/task/TaskStore.java
@@ -16,8 +16,8 @@
 
 package com.android.server.task;
 
+import android.app.task.Task;
 import android.content.Context;
-import android.content.Task;
 import android.util.SparseArray;
 
 import com.android.server.task.controllers.TaskStatus;
@@ -95,6 +95,13 @@
     }
 
     /**
+     * @return the number of tasks in the store
+     */
+    public int size() {
+        return mTasks.size();
+    }
+
+    /**
      * @return The live array of TaskStatus objects.
      */
     public SparseArray<TaskStatus> getTasks() {
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
index 6a4e1f3..a0038c5d 100644
--- a/services/core/java/com/android/server/task/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
@@ -70,13 +70,10 @@
     }
 
     /**
-     * @param userId Id of the user for whom we are updating the connectivity state.
+     *
      */
-    private void updateTrackedTasks(int userId) {
+    private void updateTrackedTasks() {
         for (TaskStatus ts : mTrackedTasks) {
-            if (ts.userId != userId) {
-                continue;
-            }
             boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(mConnectivity);
             boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(mMetered);
             if (prevIsConnected != mConnectivity || prevIsMetered != mMetered) {
@@ -107,14 +104,13 @@
                 final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
                 // This broadcast gets sent a lot, only update if the active network has changed.
                 if (activeNetwork.getType() == networkType) {
-                    final int userid = context.getUserId();
                     mMetered = false;
                     mConnectivity =
                             !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
                     if (mConnectivity) {  // No point making the call if we know there's no conn.
                         mMetered = connManager.isActiveNetworkMetered();
                     }
-                    updateTrackedTasks(userid);
+                    updateTrackedTasks();
                 }
             } else {
                 Log.w(TAG, "Unrecognised action in intent: " + action);
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java
index d96fedc..d270016 100644
--- a/services/core/java/com/android/server/task/controllers/TaskStatus.java
+++ b/services/core/java/com/android/server/task/controllers/TaskStatus.java
@@ -16,17 +16,19 @@
 
 package com.android.server.task.controllers;
 
+import android.app.task.Task;
 import android.content.ComponentName;
-import android.content.Task;
 import android.content.pm.PackageParser;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.os.UserHandle;
 
+import java.io.PrintWriter;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Uniquely identifies a task internally.
- * Created from the public {@link android.content.Task} object when it lands on the scheduler.
+ * Created from the public {@link android.app.task.Task} object when it lands on the scheduler.
  * Contains current state of the requirements of the task, as well as a function to evaluate
  * whether it's ready to run.
  * This object is shared among the various controllers - hence why the different fields are atomic.
@@ -36,10 +38,9 @@
  * @hide
  */
 public class TaskStatus {
+    final Task task;
     final int taskId;
-    final int userId;
     final int uId;
-    final ComponentName component;
     final Bundle extras;
 
     final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
@@ -57,9 +58,9 @@
     private long earliestRunTimeElapsedMillis;
     private long latestRunTimeElapsedMillis;
 
-    /** Provide a unique handle to the service that this task will be run on. */
+    /** Provide a handle to the service that this task will be run on. */
     public int getServiceToken() {
-        return component.hashCode() + userId;
+        return uId;
     }
 
     /** Generate a TaskStatus object for a given task and uid. */
@@ -70,9 +71,8 @@
 
     /** Set up the state of a newly scheduled task. */
     TaskStatus(Task task, int userId, int uId) {
+        this.task = task;
         this.taskId = task.getTaskId();
-        this.userId = userId;
-        this.component = task.getService();
         this.extras = task.getExtras();
         this.uId = uId;
 
@@ -100,16 +100,20 @@
         hasConnectivityConstraint = task.getNetworkCapabilities() == Task.NetworkType.ANY;
     }
 
+    public Task getTask() {
+        return task;
+    }
+
     public int getTaskId() {
         return taskId;
     }
 
     public ComponentName getServiceComponent() {
-        return component;
+        return task.getService();
     }
 
     public int getUserId() {
-        return userId;
+        return UserHandle.getUserId(uId);
     }
 
     public int getUid() {
@@ -161,9 +165,9 @@
 
     @Override
     public int hashCode() {
-        int result = component.hashCode();
+        int result = getServiceComponent().hashCode();
         result = 31 * result + taskId;
-        result = 31 * result + userId;
+        result = 31 * result + uId;
         return result;
     }
 
@@ -174,7 +178,14 @@
 
         TaskStatus that = (TaskStatus) o;
         return ((taskId == that.taskId)
-                && (userId == that.userId)
-                && (component.equals(that.component)));
+                && (uId == that.uId)
+                && (getServiceComponent().equals(that.getServiceComponent())));
+    }
+
+    // Dumpsys infrastructure
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("Task "); pw.println(taskId);
+        pw.print(prefix); pw.print("uid="); pw.println(uId);
+        pw.print(prefix); pw.print("component="); pw.println(task.getService());
     }
 }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index e2d2ac6..4f8b9d7 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -24,9 +24,7 @@
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IRemoteCallback;
-import android.os.SystemProperties;
 import android.util.Slog;
-import android.view.View;
 import android.view.WindowManager;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
@@ -299,7 +297,7 @@
         return null;
     }
 
-    Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
+    Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) {
         int anim = 0;
         Context context = mContext;
         if (animAttr >= 0) {
@@ -315,7 +313,19 @@
         return null;
     }
 
-    private Animation loadAnimation(String packageName, int resId) {
+    Animation loadAnimationRes(WindowManager.LayoutParams lp, int resId) {
+        Context context = mContext;
+        if (resId >= 0) {
+            AttributeCache.Entry ent = getCachedAnimations(lp);
+            if (ent != null) {
+                context = ent.context;
+            }
+            return AnimationUtils.loadAnimation(context, resId);
+        }
+        return null;
+    }
+
+    private Animation loadAnimationRes(String packageName, int resId) {
         int anim = 0;
         Context context = mContext;
         if (resId >= 0) {
@@ -695,11 +705,31 @@
 
 
     Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
-                            int appWidth, int appHeight, int orientation,
-                            Rect containingFrame, Rect contentInsets, boolean isFullScreen) {
+            int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets,
+            boolean isFullScreen, boolean isVoiceInteraction) {
         Animation a;
-        if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
-            a = loadAnimation(mNextAppTransitionPackage, enter ?
+        if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
+                || transit == TRANSIT_TASK_OPEN
+                || transit == TRANSIT_TASK_TO_FRONT)) {
+            a = loadAnimationRes(lp, enter
+                    ? com.android.internal.R.anim.voice_activity_open_enter
+                    : com.android.internal.R.anim.voice_activity_open_exit);
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+                    "applyAnimation voice:"
+                    + " anim=" + a + " transit=" + transit + " isEntrance=" + enter
+                    + " Callers=" + Debug.getCallers(3));
+        } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
+                || transit == TRANSIT_TASK_CLOSE
+                || transit == TRANSIT_TASK_TO_BACK)) {
+            a = loadAnimationRes(lp, enter
+                    ? com.android.internal.R.anim.voice_activity_close_enter
+                    : com.android.internal.R.anim.voice_activity_close_exit);
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+                    "applyAnimation voice:"
+                    + " anim=" + a + " transit=" + transit + " isEntrance=" + enter
+                    + " Callers=" + Debug.getCallers(3));
+        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
+            a = loadAnimationRes(mNextAppTransitionPackage, enter ?
                     mNextAppTransitionEnter : mNextAppTransitionExit);
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                     "applyAnimation:"
@@ -782,7 +812,7 @@
                             : WindowAnimation_wallpaperIntraCloseExitAnimation;
                     break;
             }
-            a = animAttr != 0 ? loadAnimation(lp, animAttr) : null;
+            a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                     "applyAnimation:"
                     + " anim=" + a
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ca4ad8a..12c15e2 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -50,6 +50,8 @@
 
     final WindowAnimator mAnimator;
 
+    final boolean voiceInteraction;
+
     int groupId = -1;
     boolean appFullscreen;
     int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -107,11 +109,13 @@
 
     boolean mDeferRemoval;
 
-    AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
+    AppWindowToken(WindowManagerService _service, IApplicationToken _token,
+            boolean _voiceInteraction) {
         super(_service, _token.asBinder(),
                 WindowManager.LayoutParams.TYPE_APPLICATION, true);
         appWindowToken = this;
         appToken = _token;
+        voiceInteraction = _voiceInteraction;
         mInputApplicationHandle = new InputApplicationHandle(this);
         mAnimator = service.mAnimator;
         mAppAnimator = new AppWindowAnimator(this);
@@ -249,7 +253,7 @@
     void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);
         if (appToken != null) {
-            pw.print(prefix); pw.println("app=true");
+            pw.print(prefix); pw.print("app=true voiceInteraction="); pw.println(voiceInteraction);
         }
         if (allAppWindows.size() > 0) {
             pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 266527d..6fdd535 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -36,6 +36,7 @@
 import android.view.Display;
 import android.view.SurfaceControl;
 import android.view.WindowManagerPolicy;
+import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 
 import com.android.server.wm.WindowManagerService.LayoutFields;
@@ -50,6 +51,9 @@
 public class WindowAnimator {
     private static final String TAG = "WindowAnimator";
 
+    /** How long to give statusbar to clear the private keyguard flag when animating out */
+    private static final long KEYGUARD_ANIM_TIMEOUT_MS = 1000;
+
     final WindowManagerService mService;
     final Context mContext;
     final WindowManagerPolicy mPolicy;
@@ -82,6 +86,8 @@
 
     boolean mInitialized = false;
 
+    boolean mKeyguardGoingAway;
+
     // forceHiding states.
     static final int KEYGUARD_NOT_SHOWN     = 0;
     static final int KEYGUARD_ANIMATING_IN  = 1;
@@ -213,6 +219,29 @@
         final WindowList windows = mService.getWindowListLocked(displayId);
         ArrayList<WindowStateAnimator> unForceHiding = null;
         boolean wallpaperInUnForceHiding = false;
+
+        if (mKeyguardGoingAway) {
+            for (int i = windows.size() - 1; i >= 0; i--) {
+                WindowState win = windows.get(i);
+                if (!mPolicy.isKeyguardHostWindow(win.mAttrs)) {
+                    continue;
+                }
+                final WindowStateAnimator winAnimator = win.mWinAnimator;
+                if (mPolicy.doesForceHide(win.mAttrs)) {
+                    if (!winAnimator.mAnimating) {
+                        // Create a new animation to delay until keyguard is gone on its own.
+                        winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
+                        winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS);
+                        winAnimator.mAnimationIsEntrance = false;
+                    }
+                } else {
+                    mKeyguardGoingAway = false;
+                    winAnimator.clearAnimation();
+                }
+                break;
+            }
+        }
+
         mForceHiding = KEYGUARD_NOT_SHOWN;
 
         for (int i = windows.size() - 1; i >= 0; i--) {
@@ -239,7 +268,7 @@
                     }
                 }
 
-                if (mPolicy.doesForceHide(win, win.mAttrs)) {
+                if (mPolicy.doesForceHide(win.mAttrs)) {
                     if (!wasAnimating && nowAnimating) {
                         if (WindowManagerService.DEBUG_ANIM ||
                                 WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
@@ -252,6 +281,11 @@
                                     getPendingLayoutChanges(displayId));
                         }
                         mService.mFocusMayChange = true;
+                    } else if (mKeyguardGoingAway && !nowAnimating) {
+                        // Timeout!!
+                        Slog.e(TAG, "Timeout waiting for animation to startup");
+                        mPolicy.startKeyguardExitAnimation(0);
+                        mKeyguardGoingAway = false;
                     }
                     if (win.isReadyForDisplay()) {
                         if (nowAnimating) {
@@ -265,7 +299,7 @@
                         }
                     }
                     if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
-                            "Force hide " + mForceHiding
+                            "Force hide " + forceHidingToString()
                             + " hasSurface=" + win.mHasSurface
                             + " policyVis=" + win.mPolicyVisibility
                             + " destroying=" + win.mDestroying
@@ -349,12 +383,18 @@
         // If we have windows that are being show due to them no longer
         // being force-hidden, apply the appropriate animation to them.
         if (unForceHiding != null) {
+            boolean startKeyguardExit = true;
             for (int i=unForceHiding.size()-1; i>=0; i--) {
                 Animation a = mPolicy.createForceHideEnterAnimation(wallpaperInUnForceHiding);
                 if (a != null) {
                     final WindowStateAnimator winAnimator = unForceHiding.get(i);
                     winAnimator.setAnimation(a);
                     winAnimator.mAnimationIsEntrance = true;
+                    if (startKeyguardExit) {
+                        // Do one time only.
+                        mPolicy.startKeyguardExitAnimation(a.getStartOffset());
+                        startKeyguardExit = false;
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c23d1ea..7382f4ca 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2215,6 +2215,11 @@
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
+                if (type == TYPE_VOICE_INTERACTION) {
+                    Slog.w(TAG, "Attempted to add voice interaction window with unknown token "
+                          + attrs.token + ".  Aborting.");
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                }
                 if (type == TYPE_WALLPAPER) {
                     Slog.w(TAG, "Attempted to add wallpaper window with unknown token "
                           + attrs.token + ".  Aborting.");
@@ -2250,6 +2255,12 @@
                             + attrs.token + ".  Aborting.");
                       return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
+            } else if (type == TYPE_VOICE_INTERACTION) {
+                if (token.windowType != TYPE_VOICE_INTERACTION) {
+                    Slog.w(TAG, "Attempted to add voice interaction window with bad token "
+                            + attrs.token + ".  Aborting.");
+                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                }
             } else if (type == TYPE_WALLPAPER) {
                 if (token.windowType != TYPE_WALLPAPER) {
                     Slog.w(TAG, "Attempted to add wallpaper window with bad token "
@@ -3173,7 +3184,7 @@
     }
 
     private boolean applyAnimationLocked(AppWindowToken atoken,
-            WindowManager.LayoutParams lp, int transit, boolean enter) {
+            WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction) {
         // Only apply an animation if the display isn't frozen.  If it is
         // frozen, there is no reason to animate and it can cause strange
         // artifacts when we unfreeze the display if some different animation
@@ -3203,7 +3214,8 @@
             }
 
             Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
-                    mCurConfiguration.orientation, containingFrame, contentInsets, isFullScreen);
+                    mCurConfiguration.orientation, containingFrame, contentInsets, isFullScreen,
+                    isVoiceInteraction);
             if (a != null) {
                 if (DEBUG_ANIM) {
                     RuntimeException e = null;
@@ -3423,7 +3435,7 @@
     @Override
     public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
-            int configChanges) {
+            int configChanges, boolean voiceInteraction) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3449,7 +3461,7 @@
                 Slog.w(TAG, "Attempted to add existing app token: " + token);
                 return;
             }
-            atoken = new AppWindowToken(this, token);
+            atoken = new AppWindowToken(this, token, voiceInteraction);
             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
             atoken.groupId = taskId;
             atoken.appFullscreen = fullscreen;
@@ -4201,7 +4213,7 @@
     }
 
     boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
-            boolean visible, int transit, boolean performLayout) {
+            boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
         boolean delayed = false;
 
         if (wtoken.clientHidden == visible) {
@@ -4222,7 +4234,7 @@
                 if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
                     wtoken.mAppAnimator.animation = null;
                 }
-                if (applyAnimationLocked(wtoken, lp, transit, visible)) {
+                if (applyAnimationLocked(wtoken, lp, transit, visible, isVoiceInteraction)) {
                     delayed = runningAppAnimation = true;
                 }
                 WindowState window = wtoken.findMainWindow();
@@ -4400,7 +4412,7 @@
 
             final long origId = Binder.clearCallingIdentity();
             setTokenVisibilityLocked(wtoken, null, visible, AppTransition.TRANSIT_UNSET,
-                    true);
+                    true, wtoken.voiceInteraction);
             wtoken.updateReportedVisibilityLocked();
             Binder.restoreCallingIdentity(origId);
         }
@@ -4547,7 +4559,7 @@
             if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
                 delayed = setTokenVisibilityLocked(wtoken, null, false,
-                        AppTransition.TRANSIT_UNSET, true);
+                        AppTransition.TRANSIT_UNSET, true, wtoken.voiceInteraction);
                 wtoken.inPendingTransaction = false;
                 mOpeningApps.remove(wtoken);
                 wtoken.waitingToShow = false;
@@ -5127,6 +5139,18 @@
     }
 
     @Override
+    public void keyguardGoingAway() {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
+        }
+        synchronized (mWindowMap) {
+            mAnimator.mKeyguardGoingAway = true;
+            requestTraversalLocked();
+        }
+    }
+
+    @Override
     public void closeSystemDialogs(String reason) {
         synchronized(mWindowMap) {
             final int numDisplays = mDisplayContents.size();
@@ -7149,9 +7173,7 @@
         public static final int TAP_OUTSIDE_STACK = 31;
         public static final int NOTIFY_ACTIVITY_DRAWN = 32;
 
-        public static final int REMOVE_STARTING_TIMEOUT = 33;
-
-        public static final int SHOW_DISPLAY_MASK = 34;
+        public static final int SHOW_DISPLAY_MASK = 33;
 
         @Override
         public void handleMessage(Message msg) {
@@ -8528,6 +8550,7 @@
             LayoutParams animLp = null;
             int bestAnimLayer = -1;
             boolean fullscreenAnim = false;
+            boolean voiceInteraction = false;
 
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                     "New wallpaper target=" + mWallpaperTarget
@@ -8572,6 +8595,8 @@
                     }
                 }
 
+                voiceInteraction |= wtoken.voiceInteraction;
+
                 if (wtoken.appFullscreen) {
                     WindowState ws = wtoken.findMainWindow();
                     if (ws != null) {
@@ -8644,7 +8669,7 @@
                 appAnimator.clearThumbnail();
                 wtoken.inPendingTransaction = false;
                 appAnimator.animation = null;
-                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
+                setTokenVisibilityLocked(wtoken, animLp, true, transit, false, voiceInteraction);
                 wtoken.updateReportedVisibilityLocked();
                 wtoken.waitingToShow = false;
 
@@ -8676,7 +8701,7 @@
                 wtoken.mAppAnimator.clearThumbnail();
                 wtoken.inPendingTransaction = false;
                 wtoken.mAppAnimator.animation = null;
-                setTokenVisibilityLocked(wtoken, animLp, false, transit, false);
+                setTokenVisibilityLocked(wtoken, animLp, false, transit, false, voiceInteraction);
                 wtoken.updateReportedVisibilityLocked();
                 wtoken.waitingToHide = false;
                 // Force the allDrawn flag, because we want to start
@@ -10266,10 +10291,6 @@
         mPolicy.lockNow(options);
     }
 
-    public void showRecentApps() {
-        mPolicy.showRecentApps();
-    }
-
     @Override
     public boolean isSafeModeEnabled() {
         return mSafeMode;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c88382c..4a80e3e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -714,6 +714,11 @@
         return mAppToken != null ? mAppToken.appToken : null;
     }
 
+    @Override
+    public boolean isVoiceInteraction() {
+        return mAppToken != null ? mAppToken.voiceInteraction : false;
+    }
+
     boolean setInsetsChanged() {
         mOverscanInsetsChanged |= !mLastOverscanInsets.equals(mOverscanInsets);
         mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 1e79dcb..e257ebc 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1658,7 +1658,7 @@
                         break;
                 }
                 if (attr >= 0) {
-                    a = mService.mAppTransition.loadAnimation(mWin.mAttrs, attr);
+                    a = mService.mAppTransition.loadAnimationAttr(mWin.mAttrs, attr);
                 }
             }
             if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index de46b16..0f24ff6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -83,6 +83,7 @@
 import com.android.server.search.SearchManagerService;
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.storage.DeviceStorageMonitorService;
+import com.android.server.task.TaskManagerService;
 import com.android.server.trust.TrustManagerService;
 import com.android.server.tv.TvInputManagerService;
 import com.android.server.twilight.TwilightService;
@@ -132,6 +133,8 @@
             "com.android.server.hdmi.HdmiCecService";
     private static final String ETHERNET_SERVICE_CLASS =
             "com.android.server.ethernet.EthernetService";
+    private static final String TASK_SERVICE_CLASS =
+            "com.android.server.task.TaskManagerService";
 
     private final int mFactoryTestMode;
     private Timer mProfilerSnapshotTimer;
@@ -183,7 +186,7 @@
         // had to fallback to a different runtime because it is
         // running as root and we need to be the system user to set
         // the property. http://b/11463182
-        SystemProperties.set("persist.sys.dalvik.vm.lib.1", VMRuntime.getRuntime().vmLibrary());
+        SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
 
         // Enable the sampling profiler.
         if (SamplingProfilerIntegration.isEnabled()) {
@@ -831,6 +834,8 @@
 
             mSystemServiceManager.startService(UiModeManagerService.class);
 
+            mSystemServiceManager.startService(TaskManagerService.class);
+
             if (!disableNonCoreServices) {
                 try {
                     if (pm.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 9b6daad..62ff121 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -113,7 +113,7 @@
             if (mBound) {
                 try {
                     mIWindowManager.addWindowToken(mToken,
-                            WindowManager.LayoutParams.TYPE_INPUT_METHOD);
+                            WindowManager.LayoutParams.TYPE_VOICE_INTERACTION);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Failed adding window token", e);
                 }
diff --git a/telecomm/java/android/telecomm/package.html b/telecomm/java/android/telecomm/package.html
new file mode 100644
index 0000000..1c9bf9d
--- /dev/null
+++ b/telecomm/java/android/telecomm/package.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+    {@hide}
+</body>
+</html>
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
new file mode 100644
index 0000000..c439211
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecomm;
+
+/**
+ * Interface used to interact with Telecomm. Mostly this is used by TelephonyManager for passing
+ * commands that were previously handled by ITelephony.
+ * {@hide}
+ */
+oneway interface ITelecommService {
+
+    /**
+     * Silence the ringer if an incoming call is currently ringing.
+     * (If vibrating, stop the vibrator also.)
+     *
+     * It's safe to call this if the ringer has already been silenced, or
+     * even if there's no incoming call.  (If so, this method will do nothing.)
+     */
+    void silenceRinger();
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a896861..4aed1fe 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -30,6 +30,7 @@
 import android.telephony.Rlog;
 import android.util.Log;
 
+import com.android.internal.telecomm.ITelecommService;
 import com.android.internal.telephony.IPhoneSubInfo;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.ITelephonyRegistry;
@@ -65,6 +66,8 @@
 public class TelephonyManager {
     private static final String TAG = "TelephonyManager";
 
+    private static final String TELECOMM_SERVICE_NAME = "telecomm";
+
     private static ITelephonyRegistry sRegistry;
 
     /**
@@ -1536,6 +1539,10 @@
         return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
     }
 
+    private ITelecommService getTelecommService() {
+        return ITelecommService.Stub.asInterface(ServiceManager.getService(TELECOMM_SERVICE_NAME));
+    }
+
     //
     //
     // PhoneStateListener
@@ -2016,9 +2023,9 @@
     @PrivateApi
     public void silenceRinger() {
         try {
-            getITelephony().silenceRinger();
+            getTelecommService().silenceRinger();
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#silenceRinger", e);
+            Log.e(TAG, "Error calling ITelecommService#silenceRinger", e);
         }
     }
 
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index db802c5..6b70631 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -902,5 +902,14 @@
                 <category android:name="com.android.test.hwui.TEST" />
             </intent-filter>
         </activity>
+
+        <activity
+                android:name=".ZOrderingActivity"
+                android:label="Reordering/Z Ordering">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.hwui.TEST" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/HwAccelerationTest/res/layout/z_ordering.xml b/tests/HwAccelerationTest/res/layout/z_ordering.xml
new file mode 100644
index 0000000..970c5fd
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/z_ordering.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:id="@+id/parent">
+    <RelativeLayout
+            android:layout_width="400dp"
+            android:layout_height="200dp"
+            android:layout_weight="1"
+            android:orientation="vertical">
+        <TextView style="@style/TopLeftReorderTextView"/>
+        <TextView style="@style/BottomLeftReorderTextView"/>
+        <TextView style="@style/TopRightReorderTextView"/>
+        <TextView style="@style/BottomRightReorderTextView"/>
+    </RelativeLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/res/values/styles.xml b/tests/HwAccelerationTest/res/values/styles.xml
index cde5d20..108709b 100644
--- a/tests/HwAccelerationTest/res/values/styles.xml
+++ b/tests/HwAccelerationTest/res/values/styles.xml
@@ -1,34 +1,37 @@
 <resources>
     <style name="ReorderTextView" parent="@android:style/TextAppearance.Medium">
-        <item name="android:layout_width">match_parent</item>
+        <item name="android:background">@drawable/appwidget_background</item>
+        <item name="android:layout_width">300dp</item>
         <item name="android:layout_height">100dp</item>
         <item name="android:gravity">center</item>
     </style>
     <style name="LeftReorderTextView" parent="@style/ReorderTextView">
-        <item name="android:translationX">20dp</item>
+        <item name="android:translationX">50dp</item>
+        <item name="android:layout_alignParentLeft">true</item>
     </style>
     <style name="RightReorderTextView" parent="@style/ReorderTextView">
-        <item name="android:translationX">-20dp</item>
+        <item name="android:translationX">-50dp</item>
+        <item name="android:layout_alignParentRight">true</item>
     </style>
 
     <style name="TopLeftReorderTextView" parent="@style/LeftReorderTextView">
-        <item name="android:background">#666</item>
-        <item name="android:text">100</item>
-        <item name="android:translationZ">100dp</item>
-    </style>
-    <style name="BottomLeftReorderTextView" parent="@style/LeftReorderTextView">
-        <item name="android:background">#bbb</item>
-        <item name="android:text">300</item>
-        <item name="android:translationZ">300dp</item>
-    </style>
-    <style name="TopRightReorderTextView" parent="@style/RightReorderTextView">
-        <item name="android:background">#888</item>
         <item name="android:text">200</item>
         <item name="android:translationZ">200dp</item>
+        <item name="android:layout_alignParentTop">true</item>
+    </style>
+    <style name="BottomLeftReorderTextView" parent="@style/LeftReorderTextView">
+        <item name="android:text">300</item>
+        <item name="android:translationZ">300dp</item>
+        <item name="android:layout_alignParentBottom">true</item>
+    </style>
+    <style name="TopRightReorderTextView" parent="@style/RightReorderTextView">
+        <item name="android:text">100</item>
+        <item name="android:translationZ">100dp</item>
+        <item name="android:layout_alignParentTop">true</item>
     </style>
     <style name="BottomRightReorderTextView" parent="@style/RightReorderTextView">
-        <item name="android:background">#ccc</item>
         <item name="android:text">400</item>
         <item name="android:translationZ">400dp</item>
+        <item name="android:layout_alignParentBottom">true</item>
     </style>
 </resources>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java
new file mode 100644
index 0000000..45e77ed
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java
@@ -0,0 +1,28 @@
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class ZOrderingActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.z_ordering);
+
+        ViewGroup grandParent = (ViewGroup) findViewById(R.id.parent);
+        if (grandParent == null) throw new IllegalStateException();
+        View.OnClickListener l = new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {}
+        };
+        for (int i = 0; i < grandParent.getChildCount(); i++) {
+            ViewGroup parent = (ViewGroup) grandParent.getChildAt(i);
+            for (int j = 0; j < parent.getChildCount(); j++) {
+                parent.getChildAt(j).setOnClickListener(l);
+            }
+        }
+    }
+}
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index ac0f701..2d08163 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -2,7 +2,8 @@
         package="com.android.test.voiceinteraction">
 
     <application>
-        <activity android:name="VoiceInteractionMain" android:label="Voice Interaction">
+        <activity android:name="VoiceInteractionMain" android:label="Voice Interaction"
+                android:theme="@android:style/Theme.Quantum">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
index 9fcbf3e..563fa44 100644
--- a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
+++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
@@ -19,6 +19,7 @@
     android:layout_height="match_parent"
     android:orientation="vertical"
     android:background="#ffffffff"
+    android:fitsSystemWindows="true"
     >
 
     <TextView android:id="@+id/text"
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 6f5788a..a6c09f3 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
         }
         
         try {
-            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0);
+            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index cc621c4..105803e 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -826,6 +826,11 @@
         return null;
     }
 
+    @Override
+    public int[] extractThemeAttrs() {
+        return null;
+    }
+
     /**
      * Retrieve the raw TypedValue for the attribute at <var>index</var>.
      *
@@ -912,4 +917,9 @@
     public String toString() {
         return Arrays.toString(mResourceData);
     }
- }
+
+    static TypedArray obtain(Resources res, int len) {
+        return res instanceof BridgeResources ?
+                new BridgeTypedArray(((BridgeResources) res), null, len, true) : null;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java
index 5d89f83..faa8852 100644
--- a/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java
@@ -30,7 +30,6 @@
 
     @LayoutlibDelegate
     /*package*/ static TypedArray obtain(Resources res, int len) {
-        // FIXME
-        return null;
+        return BridgeTypedArray.obtain(res, len);
     }
 }
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
index cdbbe46..610c867 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -79,13 +79,6 @@
         return sManager.addNewDelegate(newDelegate);
     }
 
-    @LayoutlibDelegate
-    /*package*/ static long nativePostCreate(long native_shader, long native_bitmap,
-            int shaderTileModeX, int shaderTileModeY) {
-        // pass, not needed.
-        return 0;
-    }
-
     // ---- Private delegate/helper methods ----
 
     private BitmapShader_Delegate(java.awt.image.BufferedImage image,
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
index fae8aef..59ddcc6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
@@ -78,19 +78,6 @@
         return sManager.addNewDelegate(newDelegate);
     }
 
-    @LayoutlibDelegate
-    /*package*/ static long nativePostCreate1(long native_shader, long native_skiaShaderA,
-            long native_skiaShaderB, long native_mode) {
-        // pass, not needed.
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativePostCreate2(long native_shader, long native_skiaShaderA,
-            long native_skiaShaderB, int porterDuffMode) {
-        // pass, not needed.
-        return 0;
-    }
 
     // ---- Private delegate/helper methods ----
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index 5e7543a0..9ea4538 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -146,6 +146,8 @@
 
     @LayoutlibDelegate
     /*package*/ static void nUnrefFamily(long nativePtr) {
+        // Removing the java reference for the object doesn't mean that it's freed for garbage
+        // collection. Typeface_Delegate may still hold a reference for it.
         sManager.removeJavaReferenceFor(nativePtr);
     }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
index ac77377..55c4b98 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -71,22 +71,6 @@
                 tileMode);
     }
 
-    @LayoutlibDelegate
-    /*package*/ static long nativePostCreate1(LinearGradient thisGradient,
-            long native_shader, float x0, float y0, float x1, float y1,
-            int colors[], float positions[], int tileMode) {
-        // nothing to be done here.
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativePostCreate2(LinearGradient thisGradient,
-            long native_shader, float x0, float y0, float x1, float y1,
-            int color0, int color1, int tileMode) {
-        // nothing to be done here.
-        return 0;
-    }
-
     // ---- Private delegate/helper methods ----
 
     /**
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index 4f16dcf..80179ee 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -68,20 +68,6 @@
                 tileMode);
     }
 
-    @LayoutlibDelegate
-    /*package*/ static long nativePostCreate1(long native_shader, float x, float y, float radius,
-            int colors[], float positions[], int tileMode) {
-        // nothing to be done here.
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativePostCreate2(long native_shader, float x, float y, float radius,
-            int color0, int color1, int tileMode) {
-        // nothing to be done here.
-        return 0;
-    }
-
     // ---- Private delegate/helper methods ----
 
     /**
diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
index 70a0a43..14e9960 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
@@ -76,13 +76,12 @@
     // ---- native methods ----
 
     @LayoutlibDelegate
-    /*package*/ static void nativeDestructor(long native_shader, long native_skiaShader) {
+    /*package*/ static void nativeDestructor(long native_shader) {
         sManager.removeJavaReferenceFor(native_shader);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeSetLocalMatrix(long native_shader, long native_skiaShader,
-            long matrix_instance) {
+    /*package*/ static void nativeSetLocalMatrix(long native_shader, long matrix_instance) {
         // get the delegate from the native int.
         Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
         if (shaderDelegate == null) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
index f2b3e8d..95a57a9 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -62,20 +62,6 @@
         return nativeCreate1(x, y, new int[] { color0, color1 }, null /*positions*/);
     }
 
-    @LayoutlibDelegate
-    /*package*/ static long nativePostCreate1(long native_shader, float cx, float cy,
-            int[] colors, float[] positions) {
-        // nothing to be done here.
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativePostCreate2(long native_shader, float cx, float cy,
-            int color0, int color1) {
-        // nothing to be done here.
-        return 0;
-    }
-
     // ---- Private delegate/helper methods ----
 
     /**
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index ed8f3b4..9746b48 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -54,7 +54,7 @@
 
     // ---- delegate data ----
 
-    private final long[] mFontFamilies;  // the reference to FontFamily_Delegate.
+    private final FontFamily_Delegate[] mFontFamilies;  // the reference to FontFamily_Delegate.
     private int mStyle;
 
     private static long sDefaultTypeface;
@@ -71,8 +71,7 @@
 
     public List<Font> getFonts(boolean compact) {
         List<Font> fonts = new ArrayList<Font>(mFontFamilies.length);
-        for (long fontFamily : mFontFamilies) {
-            FontFamily_Delegate ffd = FontFamily_Delegate.getDelegate(fontFamily);
+        for (FontFamily_Delegate ffd : mFontFamilies) {
             if (ffd != null) {
                 Font font = ffd.getFont(mStyle, compact);
                 if (font != null) {
@@ -122,7 +121,11 @@
 
     @LayoutlibDelegate
     /*package*/ static synchronized long nativeCreateFromArray(long[] familyArray) {
-        Typeface_Delegate delegate = new Typeface_Delegate(familyArray, Typeface.NORMAL);
+        FontFamily_Delegate[] fontFamilies = new FontFamily_Delegate[familyArray.length];
+        for (int i = 0; i < familyArray.length; i++) {
+            fontFamilies[i] = FontFamily_Delegate.getDelegate(familyArray[i]);
+        }
+        Typeface_Delegate delegate = new Typeface_Delegate(fontFamilies, Typeface.NORMAL);
         return sManager.addNewDelegate(delegate);
     }
 
@@ -153,9 +156,8 @@
 
     // ---- Private delegate/helper methods ----
 
-    private Typeface_Delegate(long[] fontFamilies, int style) {
+    private Typeface_Delegate(FontFamily_Delegate[] fontFamilies, int style) {
         mFontFamilies = fontFamilies;
         mStyle = style;
     }
-
 }
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 757cdd2..3bf2b20 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -72,7 +72,7 @@
 
     @Override
     public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
-            boolean arg5, boolean arg6, int arg7, int arg8)
+            boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9)
             throws RemoteException {
         // TODO Auto-generated method stub
 
@@ -439,6 +439,10 @@
     }
 
     @Override
+    public void keyguardGoingAway() throws RemoteException {
+    }
+
+    @Override
     public void lockNow(Bundle options) {
         // TODO Auto-generated method stub
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
index 936ab4f..e59ccd7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
@@ -171,7 +171,7 @@
             // Set action bar to be split, if needed.
             ActionBarContainer splitView = (ActionBarContainer) findViewById(R.id.split_action_bar);
             mActionBarView.setSplitView(splitView);
-            mActionBarView.setSplitActionBar(mSplit);
+            mActionBarView.setSplitToolbar(mSplit);
 
             inflateMenus();
 
diff --git a/tools/layoutlib/rename_font/build_font.py b/tools/layoutlib/rename_font/build_font.py
index ea3dccc..aea3241 100755
--- a/tools/layoutlib/rename_font/build_font.py
+++ b/tools/layoutlib/rename_font/build_font.py
@@ -15,10 +15,10 @@
 # limitations under the License.
 
 """
-Rename the PS name of all fonts in the input directory and copy them to the
+Rename the PS name of all fonts in the input directories and copy them to the
 output directory.
 
-Usage: build_font.py /path/to/input_fonts/ /path/to/output_fonts/
+Usage: build_font.py /path/to/input_fonts1/ /path/to/input_fonts2/ /path/to/output_fonts/
 
 """
 
@@ -30,50 +30,86 @@
 from lxml import etree
 import shutil
 import glob
+from multiprocessing import Pool
+
+# global variable
+dest_dir = '/tmp'
 
 def main(argv):
-  if len(argv) != 2:
-    print "Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/"
-    sys.exit(1)
-  if not os.path.isdir(argv[0]):
-    print argv[0] + "is not a valid directory"
-    sys.exit(1)
-  if not os.path.isdir(argv[1]):
-    print argv[1] + "is not a valid directory"
-    sys.exit(1)
+  if len(argv) < 2:
+    sys.exit('Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/')
+  for directory in argv:
+    if not os.path.isdir(directory):
+      sys.exit(directory + ' is not a valid directory')
+  global dest_dir
+  dest_dir = argv[-1]
+  src_dirs = argv[:-1]
   cwd = os.getcwd()
-  os.chdir(argv[1])
+  os.chdir(dest_dir)
   files = glob.glob('*')
   for filename in files:
     os.remove(filename)
   os.chdir(cwd)
-  for filename in os.listdir(argv[0]):
-    if not os.path.splitext(filename)[1].lower() == ".ttf":
-      shutil.copy(os.path.join(argv[0], filename), argv[1])
-      continue
-    print os.path.join(argv[0], filename)
-    old_ttf_path = os.path.join(argv[0], filename)
+  input_fonts = list()
+  for src_dir in src_dirs:
+    for dirname, dirnames, filenames in os.walk(src_dir):
+      for filename in filenames:
+          input_path = os.path.join(dirname, filename)
+          extension = os.path.splitext(filename)[1].lower()
+          if (extension == '.ttf'):
+            input_fonts.append(input_path)
+          elif (extension == '.xml'):
+            shutil.copy(input_path, dest_dir)
+      if '.git' in dirnames:
+          # don't go into any .git directories.
+          dirnames.remove('.git')
+  # Create as many threads as the number of CPUs
+  pool = Pool(processes=None)
+  pool.map(convert_font, input_fonts)
+
+
+class InvalidFontException(Exception):
+  pass
+
+def convert_font(input_path):
+  filename = os.path.basename(input_path)
+  print 'Converting font: ' + filename
+  # the path to the output file. The file name is the fontfilename.ttx
+  ttx_path = os.path.join(dest_dir, filename)
+  ttx_path = ttx_path[:-1] + 'x'
+  try:
     # run ttx to generate an xml file in the output folder which represents all
     # its info
-    ttx_args = ["-d", argv[1], old_ttf_path]
+    ttx_args = ['-q', '-d', dest_dir, input_path]
     ttx.main(ttx_args)
-    # the path to the output file. The file name is the fontfilename.ttx
-    ttx_path = os.path.join(argv[1], filename)
-    ttx_path = ttx_path[:-1] + "x"
     # now parse the xml file to change its PS name.
     tree = etree.parse(ttx_path)
     encoding = tree.docinfo.encoding
     root = tree.getroot()
     for name in root.iter('name'):
       [old_ps_name, version] = get_font_info(name)
-      new_ps_name = old_ps_name + version
-      update_name(name, new_ps_name)
+      if old_ps_name is not None and version is not None:
+        new_ps_name = old_ps_name + version
+        update_name(name, new_ps_name)
     tree.write(ttx_path, xml_declaration=True, encoding=encoding )
     # generate the udpated font now.
-    ttx_args = ["-d", argv[1], ttx_path]
+    ttx_args = ['-q', '-d', dest_dir, ttx_path]
     ttx.main(ttx_args)
-    # delete the temp ttx file.
+  except InvalidFontException:
+    # In case of invalid fonts, we exit.
+    print filename + ' is not a valid font'
+    raise
+  except Exception as e:
+    print 'Error converting font: ' + filename
+    print e
+    # Some fonts are too big to be handled by the ttx library.
+    # Just copy paste them.
+    shutil.copy(input_path, dest_dir)
+  try:
+    # delete the temp ttx file is it exists.
     os.remove(ttx_path)
+  except OSError:
+    pass
 
 def get_font_info(tag):
   ps_name = None
@@ -85,19 +121,17 @@
       if namerecord.attrib['nameID'] == '6':
         if ps_name is not None:
           if not sanitize(namerecord.text) == ps_name:
-            sys.exit('found multiple possibilities of the font name')
+            raise InvalidFontException('found multiple possibilities of the font name')
         else:
           ps_name = sanitize(namerecord.text)
       # nameID=5 means the font version
       if namerecord.attrib['nameID'] == '5':
         if ps_version is not None:
           if not ps_version == get_version(namerecord.text):
-            sys.exit('found multiple possibilities of the font version')
+            raise InvalidFontException('found multiple possibilities of the font version')
         else:
           ps_version = get_version(namerecord.text)
-  if ps_name is not None and ps_version is not None:
-    return [ps_name, ps_version]
-  sys.exit('didn\'t find the font name or version')
+  return [ps_name, ps_version]
 
 
 def update_name(tag, name):
@@ -110,11 +144,11 @@
   return re.sub(r'[^\w-]+', '', string)
 
 def get_version(string):
-  # The string must begin with "Version n.nn "
+  # The string must begin with 'Version n.nn '
   # to extract n.nn, we return the second entry in the split strings.
   string = string.strip()
-  if not string.startswith("Version "):
-    sys.exit('mal-formed font version')
+  if not string.startswith('Version '):
+    raise InvalidFontException('mal-formed font version')
   return sanitize(string.split()[1])
 
 if __name__ == '__main__':